Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 195571
b: refs/heads/master
c: 7a47027
h: refs/heads/master
i:
  195569: 03ac79c
  195567: 94972f4
v: v3
  • Loading branch information
James Smart authored and James Bottomley committed Apr 11, 2010
1 parent a09b2eb commit bff0e5f
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 84 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cb5172eafd9ffdab6bb7b1eec628ea706d5817c8
refs/heads/master: 7a4702774381103e936cae09ec12301090c6c212
2 changes: 2 additions & 0 deletions trunk/drivers/scsi/lpfc/lpfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,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;
Expand Down Expand Up @@ -622,6 +623,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;
Expand Down
257 changes: 202 additions & 55 deletions trunk/drivers/scsi/lpfc/lpfc_bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 outWxtWLen; /* from app */

/* job waiting for this mbox command to finish */
struct fc_bsg_job *set_job;
Expand Down Expand Up @@ -2377,35 +2383,68 @@ 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));
/* 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;
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;
}
Expand Down Expand Up @@ -2468,6 +2507,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
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,
Expand All @@ -2482,7 +2522,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:
Expand Down Expand Up @@ -2518,97 +2557,199 @@ 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->outWxtWLen > 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);
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;

/* extended mailbox commands will need an extended buffer */
if (mbox_req->inExtWLen || mbox_req->outWxtWLen) {
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->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 */
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.outWxtWLen = mbox_req->outWxtWLen;
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) {
if (rc != MBX_TIMEOUT) {
kfree(dd_data);
kfree(mb);
mempool_free(pmboxq, phba->mbox_mem_pool);
}
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
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);
kfree(dd_data);
kfree(mb);
mempool_free(pmboxq, phba->mbox_mem_pool);
/* not waiting mbox already done */
return 0;
rc = 0;
goto job_done;
}

/* 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;
job->dd_data = dd_data;
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;
}

/**
Expand Down Expand Up @@ -2638,6 +2779,11 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
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) {
rc = -EAGAIN;
goto job_error;
Expand Down Expand Up @@ -3094,6 +3240,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;
Expand Down
Loading

0 comments on commit bff0e5f

Please sign in to comment.