[SCSI] lpfc 8.3.11: Driver management improvements via BSG
- Add BSG support for PCI loopback testing. - Add BSG support for extended mailbox commands. Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
cb5172eafd
commit
7a47027743
@ -554,6 +554,7 @@ struct lpfc_hba {
|
|||||||
struct lpfc_dmabuf slim2p;
|
struct lpfc_dmabuf slim2p;
|
||||||
|
|
||||||
MAILBOX_t *mbox;
|
MAILBOX_t *mbox;
|
||||||
|
uint32_t *mbox_ext;
|
||||||
uint32_t *inb_ha_copy;
|
uint32_t *inb_ha_copy;
|
||||||
uint32_t *inb_counter;
|
uint32_t *inb_counter;
|
||||||
uint32_t inb_last_counter;
|
uint32_t inb_last_counter;
|
||||||
@ -622,6 +623,7 @@ struct lpfc_hba {
|
|||||||
uint32_t cfg_enable_hba_reset;
|
uint32_t cfg_enable_hba_reset;
|
||||||
uint32_t cfg_enable_hba_heartbeat;
|
uint32_t cfg_enable_hba_heartbeat;
|
||||||
uint32_t cfg_enable_bg;
|
uint32_t cfg_enable_bg;
|
||||||
|
uint32_t cfg_hostmem_hgp;
|
||||||
uint32_t cfg_log_verbose;
|
uint32_t cfg_log_verbose;
|
||||||
uint32_t cfg_aer_support;
|
uint32_t cfg_aer_support;
|
||||||
uint32_t cfg_suppress_link_up;
|
uint32_t cfg_suppress_link_up;
|
||||||
|
@ -79,6 +79,12 @@ struct lpfc_bsg_iocb {
|
|||||||
struct lpfc_bsg_mbox {
|
struct lpfc_bsg_mbox {
|
||||||
LPFC_MBOXQ_t *pmboxq;
|
LPFC_MBOXQ_t *pmboxq;
|
||||||
MAILBOX_t *mb;
|
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 outWxtWLen; /* from app */
|
||||||
|
|
||||||
/* job waiting for this mbox command to finish */
|
/* job waiting for this mbox command to finish */
|
||||||
struct fc_bsg_job *set_job;
|
struct fc_bsg_job *set_job;
|
||||||
@ -2377,35 +2383,68 @@ void
|
|||||||
lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
||||||
{
|
{
|
||||||
struct bsg_job_data *dd_data;
|
struct bsg_job_data *dd_data;
|
||||||
MAILBOX_t *pmb;
|
|
||||||
MAILBOX_t *mb;
|
|
||||||
struct fc_bsg_job *job;
|
struct fc_bsg_job *job;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
uint8_t *to;
|
||||||
|
uint8_t *from;
|
||||||
|
|
||||||
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
||||||
dd_data = pmboxq->context1;
|
dd_data = pmboxq->context1;
|
||||||
|
/* job already timed out? */
|
||||||
if (!dd_data) {
|
if (!dd_data) {
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmb = &dd_data->context_un.mbox.pmboxq->u.mb;
|
/* build the outgoing buffer to do an sg copy
|
||||||
mb = dd_data->context_un.mbox.mb;
|
* 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));
|
||||||
|
/* copy the extended data if any, count is in words */
|
||||||
|
if (dd_data->context_un.mbox.outWxtWLen) {
|
||||||
|
from = (uint8_t *)dd_data->context_un.mbox.ext;
|
||||||
|
to += sizeof(MAILBOX_t);
|
||||||
|
memcpy(to, from,
|
||||||
|
dd_data->context_un.mbox.outWxtWLen * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
from = (uint8_t *)dd_data->context_un.mbox.mb;
|
||||||
job = dd_data->context_un.mbox.set_job;
|
job = dd_data->context_un.mbox.set_job;
|
||||||
memcpy(mb, pmb, sizeof(*pmb));
|
size = job->reply_payload.payload_len;
|
||||||
size = job->request_payload.payload_len;
|
|
||||||
job->reply->reply_payload_rcv_len =
|
job->reply->reply_payload_rcv_len =
|
||||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
sg_copy_from_buffer(job->reply_payload.sg_list,
|
||||||
job->reply_payload.sg_cnt,
|
job->reply_payload.sg_cnt,
|
||||||
mb, size);
|
from, size);
|
||||||
job->reply->result = 0;
|
job->reply->result = 0;
|
||||||
|
|
||||||
dd_data->context_un.mbox.set_job = NULL;
|
dd_data->context_un.mbox.set_job = NULL;
|
||||||
job->dd_data = NULL;
|
job->dd_data = NULL;
|
||||||
job->job_done(job);
|
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);
|
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);
|
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);
|
kfree(dd_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2468,6 +2507,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
|
|||||||
case MBX_WRITE_EVENT_LOG:
|
case MBX_WRITE_EVENT_LOG:
|
||||||
case MBX_PORT_CAPABILITIES:
|
case MBX_PORT_CAPABILITIES:
|
||||||
case MBX_PORT_IOV_CONTROL:
|
case MBX_PORT_IOV_CONTROL:
|
||||||
|
case MBX_RUN_BIU_DIAG64:
|
||||||
break;
|
break;
|
||||||
case MBX_SET_VARIABLE:
|
case MBX_SET_VARIABLE:
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||||
@ -2482,7 +2522,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
|
|||||||
phba->fc_topology = TOPOLOGY_PT_PT;
|
phba->fc_topology = TOPOLOGY_PT_PT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MBX_RUN_BIU_DIAG64:
|
|
||||||
case MBX_READ_EVENT_LOG:
|
case MBX_READ_EVENT_LOG:
|
||||||
case MBX_READ_SPARM64:
|
case MBX_READ_SPARM64:
|
||||||
case MBX_READ_LA:
|
case MBX_READ_LA:
|
||||||
@ -2518,97 +2557,199 @@ static uint32_t
|
|||||||
lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
||||||
struct lpfc_vport *vport)
|
struct lpfc_vport *vport)
|
||||||
{
|
{
|
||||||
LPFC_MBOXQ_t *pmboxq;
|
LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
|
||||||
MAILBOX_t *pmb;
|
MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
|
||||||
MAILBOX_t *mb;
|
/* a 4k buffer to hold the mb and extended data from/to the bsg */
|
||||||
struct bsg_job_data *dd_data;
|
MAILBOX_t *mb = NULL;
|
||||||
|
struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
|
||||||
uint32_t size;
|
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;
|
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->outWxtWLen > MAILBOX_EXT_SIZE)) {
|
||||||
|
rc = -ERANGE;
|
||||||
|
goto job_done;
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate our bsg tracking structure */
|
/* allocate our bsg tracking structure */
|
||||||
dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
|
dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
|
||||||
if (!dd_data) {
|
if (!dd_data) {
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
||||||
"2727 Failed allocation of dd_data\n");
|
"2727 Failed allocation of dd_data\n");
|
||||||
return -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
goto job_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
if (!mb) {
|
if (!mb) {
|
||||||
kfree(dd_data);
|
rc = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto job_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||||
if (!pmboxq) {
|
if (!pmboxq) {
|
||||||
kfree(dd_data);
|
rc = -ENOMEM;
|
||||||
kfree(mb);
|
goto job_done;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
|
||||||
|
|
||||||
size = job->request_payload.payload_len;
|
size = job->request_payload.payload_len;
|
||||||
job->reply->reply_payload_rcv_len =
|
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
job->request_payload.sg_cnt,
|
||||||
job->request_payload.sg_cnt,
|
mb, size);
|
||||||
mb, size);
|
|
||||||
|
|
||||||
rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
|
rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
|
||||||
if (rc != 0) {
|
if (rc != 0)
|
||||||
kfree(dd_data);
|
goto job_done; /* must be negative */
|
||||||
kfree(mb);
|
|
||||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
||||||
return rc; /* must be negative */
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
|
|
||||||
pmb = &pmboxq->u.mb;
|
pmb = &pmboxq->u.mb;
|
||||||
memcpy(pmb, mb, sizeof(*pmb));
|
memcpy(pmb, mb, sizeof(*pmb));
|
||||||
pmb->mbxOwner = OWN_HOST;
|
pmb->mbxOwner = OWN_HOST;
|
||||||
pmboxq->context1 = NULL;
|
|
||||||
pmboxq->vport = vport;
|
pmboxq->vport = vport;
|
||||||
|
|
||||||
if ((vport->fc_flag & FC_OFFLINE_MODE) ||
|
/* extended mailbox commands will need an extended buffer */
|
||||||
(!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
|
if (mbox_req->inExtWLen || mbox_req->outWxtWLen) {
|
||||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
|
ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL);
|
||||||
if (rc != MBX_SUCCESS) {
|
if (!ext) {
|
||||||
if (rc != MBX_TIMEOUT) {
|
rc = -ENOMEM;
|
||||||
kfree(dd_data);
|
goto job_done;
|
||||||
kfree(mb);
|
|
||||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
||||||
}
|
|
||||||
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(mb, pmb, sizeof(*pmb));
|
/* any data for the device? */
|
||||||
job->reply->reply_payload_rcv_len =
|
if (mbox_req->inExtWLen) {
|
||||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
from = (uint8_t *)mb;
|
||||||
job->reply_payload.sg_cnt,
|
from += sizeof(MAILBOX_t);
|
||||||
mb, size);
|
memcpy((uint8_t *)ext, from,
|
||||||
kfree(dd_data);
|
mbox_req->inExtWLen * sizeof(uint32_t));
|
||||||
kfree(mb);
|
}
|
||||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
||||||
/* not waiting mbox already done */
|
pmboxq->context2 = ext;
|
||||||
return 0;
|
pmboxq->in_ext_byte_len =
|
||||||
|
mbox_req->inExtWLen *
|
||||||
|
sizeof(uint32_t);
|
||||||
|
pmboxq->out_ext_byte_len =
|
||||||
|
mbox_req->outWxtWLen *
|
||||||
|
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->outWxtWLen * 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) {
|
||||||
|
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||||
|
if (!rxbmp) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto job_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||||
|
INIT_LIST_HEAD(&rxbmp->list);
|
||||||
|
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||||
|
dmp = diag_cmd_data_alloc(phba, rxbpl, PAGE_SIZE, 0);
|
||||||
|
if (!dmp) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto job_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmp->size = PAGE_SIZE;
|
||||||
|
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);
|
||||||
|
dd_data->context_un.mbox.rxbmp = rxbmp;
|
||||||
|
dd_data->context_un.mbox.dmp = dmp;
|
||||||
|
} else {
|
||||||
|
dd_data->context_un.mbox.rxbmp = NULL;
|
||||||
|
dd_data->context_un.mbox.dmp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup wake call as IOCB callback */
|
/* setup wake call as IOCB callback */
|
||||||
pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
|
pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
|
||||||
|
|
||||||
/* setup context field to pass wait_queue pointer to wake function */
|
/* setup context field to pass wait_queue pointer to wake function */
|
||||||
pmboxq->context1 = dd_data;
|
pmboxq->context1 = dd_data;
|
||||||
dd_data->type = TYPE_MBOX;
|
dd_data->type = TYPE_MBOX;
|
||||||
dd_data->context_un.mbox.pmboxq = pmboxq;
|
dd_data->context_un.mbox.pmboxq = pmboxq;
|
||||||
dd_data->context_un.mbox.mb = mb;
|
dd_data->context_un.mbox.mb = mb;
|
||||||
dd_data->context_un.mbox.set_job = job;
|
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.outWxtWLen = mbox_req->outWxtWLen;
|
||||||
job->dd_data = dd_data;
|
job->dd_data = dd_data;
|
||||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
|
|
||||||
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
|
if ((vport->fc_flag & FC_OFFLINE_MODE) ||
|
||||||
kfree(dd_data);
|
(!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
|
||||||
kfree(mb);
|
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
|
||||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
if (rc != MBX_SUCCESS) {
|
||||||
return -EIO;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
|
||||||
|
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);
|
||||||
|
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 rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2638,6 +2779,11 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
|
|||||||
goto job_error;
|
goto job_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (job->reply_payload.payload_len != PAGE_SIZE) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto job_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
|
if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
|
||||||
rc = -EAGAIN;
|
rc = -EAGAIN;
|
||||||
goto job_error;
|
goto job_error;
|
||||||
@ -3094,6 +3240,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
|
|||||||
job->dd_data = NULL;
|
job->dd_data = NULL;
|
||||||
job->reply->reply_payload_rcv_len = 0;
|
job->reply->reply_payload_rcv_len = 0;
|
||||||
job->reply->result = -EAGAIN;
|
job->reply->result = -EAGAIN;
|
||||||
|
/* the mbox completion handler can now be run */
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||||
job->job_done(job);
|
job->job_done(job);
|
||||||
break;
|
break;
|
||||||
|
@ -93,9 +93,9 @@ struct get_mgmt_rev_reply {
|
|||||||
|
|
||||||
struct dfc_mbox_req {
|
struct dfc_mbox_req {
|
||||||
uint32_t command;
|
uint32_t command;
|
||||||
|
uint32_t mbOffset;
|
||||||
uint32_t inExtWLen;
|
uint32_t inExtWLen;
|
||||||
uint32_t outExtWLen;
|
uint32_t outWxtWLen;
|
||||||
uint8_t mbOffset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used for menlo command or menlo data. The xri is only used for menlo data */
|
/* Used for menlo command or menlo data. The xri is only used for menlo data */
|
||||||
|
@ -2934,6 +2934,12 @@ typedef struct {
|
|||||||
/* Union of all Mailbox Command types */
|
/* Union of all Mailbox Command types */
|
||||||
#define MAILBOX_CMD_WSIZE 32
|
#define MAILBOX_CMD_WSIZE 32
|
||||||
#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
|
#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
|
||||||
|
/* ext_wsize times 4 bytes should not be greater than max xmit size */
|
||||||
|
#define MAILBOX_EXT_WSIZE 512
|
||||||
|
#define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t))
|
||||||
|
#define MAILBOX_HBA_EXT_OFFSET 0x100
|
||||||
|
/* max mbox xmit size is a page size for sysfs IO operations */
|
||||||
|
#define MAILBOX_MAX_XMIT_SIZE PAGE_SIZE
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
|
uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
|
||||||
@ -3652,7 +3658,8 @@ typedef struct _IOCB { /* IOCB structure */
|
|||||||
/* Maximum IOCBs that will fit in SLI2 slim */
|
/* Maximum IOCBs that will fit in SLI2 slim */
|
||||||
#define MAX_SLI2_IOCB 498
|
#define MAX_SLI2_IOCB 498
|
||||||
#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
|
#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
|
||||||
(sizeof(MAILBOX_t) + sizeof(PCB_t)))
|
(sizeof(MAILBOX_t) + sizeof(PCB_t) + \
|
||||||
|
sizeof(uint32_t) * MAILBOX_EXT_WSIZE))
|
||||||
|
|
||||||
/* HBQ entries are 4 words each = 4k */
|
/* HBQ entries are 4 words each = 4k */
|
||||||
#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \
|
#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \
|
||||||
@ -3660,6 +3667,7 @@ typedef struct _IOCB { /* IOCB structure */
|
|||||||
|
|
||||||
struct lpfc_sli2_slim {
|
struct lpfc_sli2_slim {
|
||||||
MAILBOX_t mbx;
|
MAILBOX_t mbx;
|
||||||
|
uint32_t mbx_ext_words[MAILBOX_EXT_WSIZE];
|
||||||
PCB_t pcb;
|
PCB_t pcb;
|
||||||
IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
|
IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
|
||||||
};
|
};
|
||||||
|
@ -5059,6 +5059,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
|
|||||||
|
|
||||||
memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
|
memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
|
||||||
phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
|
phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
|
||||||
|
phba->mbox_ext = (phba->slim2p.virt +
|
||||||
|
offsetof(struct lpfc_sli2_slim, mbx_ext_words));
|
||||||
phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
|
phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
|
||||||
phba->IOCBs = (phba->slim2p.virt +
|
phba->IOCBs = (phba->slim2p.virt +
|
||||||
offsetof(struct lpfc_sli2_slim, IOCBs));
|
offsetof(struct lpfc_sli2_slim, IOCBs));
|
||||||
|
@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||||||
phba->pcb->feature = FEATURE_INITIAL_SLI2;
|
phba->pcb->feature = FEATURE_INITIAL_SLI2;
|
||||||
|
|
||||||
/* Setup Mailbox pointers */
|
/* Setup Mailbox pointers */
|
||||||
phba->pcb->mailBoxSize = sizeof(MAILBOX_t);
|
phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE;
|
||||||
offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;
|
offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;
|
||||||
pdma_addr = phba->slim2p.phys + offset;
|
pdma_addr = phba->slim2p.phys + offset;
|
||||||
phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr);
|
phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr);
|
||||||
@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (phba->sli_rev == 3) {
|
if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) {
|
||||||
phba->host_gp = &mb_slim->us.s3.host[0];
|
phba->host_gp = &phba->mbox->us.s2.host[0];
|
||||||
phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
|
|
||||||
} else {
|
|
||||||
phba->host_gp = &mb_slim->us.s2.host[0];
|
|
||||||
phba->hbq_put = NULL;
|
phba->hbq_put = NULL;
|
||||||
}
|
offset = (uint8_t *)&phba->mbox->us.s2.host -
|
||||||
|
(uint8_t *)phba->slim2p.virt;
|
||||||
|
pdma_addr = phba->slim2p.phys + offset;
|
||||||
|
phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr);
|
||||||
|
phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr);
|
||||||
|
} else {
|
||||||
|
/* Always Host Group Pointer is in SLIM */
|
||||||
|
mb->un.varCfgPort.hps = 1;
|
||||||
|
|
||||||
/* mask off BAR0's flag bits 0 - 3 */
|
if (phba->sli_rev == 3) {
|
||||||
phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
|
phba->host_gp = &mb_slim->us.s3.host[0];
|
||||||
(void __iomem *)phba->host_gp -
|
phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
|
||||||
(void __iomem *)phba->MBslimaddr;
|
} else {
|
||||||
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
phba->host_gp = &mb_slim->us.s2.host[0];
|
||||||
phba->pcb->hgpAddrHigh = bar_high;
|
phba->hbq_put = NULL;
|
||||||
else
|
}
|
||||||
phba->pcb->hgpAddrHigh = 0;
|
|
||||||
/* write HGP data to SLIM at the required longword offset */
|
|
||||||
memset(&hgp, 0, sizeof(struct lpfc_hgp));
|
|
||||||
|
|
||||||
for (i=0; i < phba->sli.num_rings; i++) {
|
/* mask off BAR0's flag bits 0 - 3 */
|
||||||
lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
|
phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
|
||||||
|
(void __iomem *)phba->host_gp -
|
||||||
|
(void __iomem *)phba->MBslimaddr;
|
||||||
|
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||||
|
phba->pcb->hgpAddrHigh = bar_high;
|
||||||
|
else
|
||||||
|
phba->pcb->hgpAddrHigh = 0;
|
||||||
|
/* write HGP data to SLIM at the required longword offset */
|
||||||
|
memset(&hgp, 0, sizeof(struct lpfc_hgp));
|
||||||
|
|
||||||
|
for (i = 0; i < phba->sli.num_rings; i++) {
|
||||||
|
lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
|
||||||
sizeof(*phba->host_gp));
|
sizeof(*phba->host_gp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup Port Group offset */
|
/* Setup Port Group offset */
|
||||||
|
@ -4891,9 +4891,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
|
|||||||
mb->mbxOwner = OWN_CHIP;
|
mb->mbxOwner = OWN_CHIP;
|
||||||
|
|
||||||
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
||||||
/* First copy command data to host SLIM area */
|
/* Populate mbox extension offset word. */
|
||||||
|
if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) {
|
||||||
|
*(((uint32_t *)mb) + pmbox->mbox_offset_word)
|
||||||
|
= (uint8_t *)phba->mbox_ext
|
||||||
|
- (uint8_t *)phba->mbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the mailbox extension data */
|
||||||
|
if (pmbox->in_ext_byte_len && pmbox->context2) {
|
||||||
|
lpfc_sli_pcimem_bcopy(pmbox->context2,
|
||||||
|
(uint8_t *)phba->mbox_ext,
|
||||||
|
pmbox->in_ext_byte_len);
|
||||||
|
}
|
||||||
|
/* Copy command data to host SLIM area */
|
||||||
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
||||||
} else {
|
} else {
|
||||||
|
/* Populate mbox extension offset word. */
|
||||||
|
if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len)
|
||||||
|
*(((uint32_t *)mb) + pmbox->mbox_offset_word)
|
||||||
|
= MAILBOX_HBA_EXT_OFFSET;
|
||||||
|
|
||||||
|
/* Copy the mailbox extension data */
|
||||||
|
if (pmbox->in_ext_byte_len && pmbox->context2) {
|
||||||
|
lpfc_memcpy_to_slim(phba->MBslimaddr +
|
||||||
|
MAILBOX_HBA_EXT_OFFSET,
|
||||||
|
pmbox->context2, pmbox->in_ext_byte_len);
|
||||||
|
|
||||||
|
}
|
||||||
if (mb->mbxCommand == MBX_CONFIG_PORT) {
|
if (mb->mbxCommand == MBX_CONFIG_PORT) {
|
||||||
/* copy command data into host mbox for cmpl */
|
/* copy command data into host mbox for cmpl */
|
||||||
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
||||||
@ -5003,15 +5028,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
|
|||||||
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
||||||
/* copy results back to user */
|
/* copy results back to user */
|
||||||
lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
|
lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
|
||||||
|
/* Copy the mailbox extension data */
|
||||||
|
if (pmbox->out_ext_byte_len && pmbox->context2) {
|
||||||
|
lpfc_sli_pcimem_bcopy(phba->mbox_ext,
|
||||||
|
pmbox->context2,
|
||||||
|
pmbox->out_ext_byte_len);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* First copy command data */
|
/* First copy command data */
|
||||||
lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
|
lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
|
||||||
MAILBOX_CMD_SIZE);
|
MAILBOX_CMD_SIZE);
|
||||||
if ((mb->mbxCommand == MBX_DUMP_MEMORY) &&
|
/* Copy the mailbox extension data */
|
||||||
pmbox->context2) {
|
if (pmbox->out_ext_byte_len && pmbox->context2) {
|
||||||
lpfc_memcpy_from_slim((void *)pmbox->context2,
|
lpfc_memcpy_from_slim(pmbox->context2,
|
||||||
phba->MBslimaddr + DMP_RSP_OFFSET,
|
phba->MBslimaddr +
|
||||||
mb->un.varDmp.word_cnt);
|
MAILBOX_HBA_EXT_OFFSET,
|
||||||
|
pmbox->out_ext_byte_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8133,6 +8165,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
|
|||||||
if (pmb->mbox_cmpl) {
|
if (pmb->mbox_cmpl) {
|
||||||
lpfc_sli_pcimem_bcopy(mbox, pmbox,
|
lpfc_sli_pcimem_bcopy(mbox, pmbox,
|
||||||
MAILBOX_CMD_SIZE);
|
MAILBOX_CMD_SIZE);
|
||||||
|
if (pmb->out_ext_byte_len &&
|
||||||
|
pmb->context2)
|
||||||
|
lpfc_sli_pcimem_bcopy(
|
||||||
|
phba->mbox_ext,
|
||||||
|
pmb->context2,
|
||||||
|
pmb->out_ext_byte_len);
|
||||||
}
|
}
|
||||||
if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
|
if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
|
||||||
pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
|
pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
|
||||||
|
@ -110,6 +110,9 @@ typedef struct lpfcMboxq {
|
|||||||
|
|
||||||
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
|
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
|
||||||
uint8_t mbox_flag;
|
uint8_t mbox_flag;
|
||||||
|
uint16_t in_ext_byte_len;
|
||||||
|
uint16_t out_ext_byte_len;
|
||||||
|
uint8_t mbox_offset_word;
|
||||||
struct lpfc_mcqe mcqe;
|
struct lpfc_mcqe mcqe;
|
||||||
struct lpfc_mbx_nembed_sge_virt *sge_array;
|
struct lpfc_mbx_nembed_sge_virt *sge_array;
|
||||||
} LPFC_MBOXQ_t;
|
} LPFC_MBOXQ_t;
|
||||||
|
Loading…
Reference in New Issue
Block a user