[SCSI] lpfc 8.3.23: BSG additions and fixes
[pandora-kernel.git] / drivers / scsi / lpfc / lpfc_bsg.c
index 77b2871..37e2a12 100644 (file)
@@ -2426,6 +2426,7 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
        struct bsg_job_data *dd_data;
        struct fc_bsg_job *job;
+       struct lpfc_mbx_nembed_cmd *nembed_sge;
        uint32_t size;
        unsigned long flags;
        uint8_t *to;
@@ -2469,9 +2470,8 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
                        memcpy(to, from, size);
                } else if ((phba->sli_rev == LPFC_SLI_REV4) &&
                        (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) {
-                       struct lpfc_mbx_nembed_cmd *nembed_sge =
-                               (struct lpfc_mbx_nembed_cmd *)
-                               &pmboxq->u.mb.un.varWords[0];
+                       nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+                                       &pmboxq->u.mb.un.varWords[0];
 
                        from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
                                                virt;
@@ -2496,16 +2496,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
                                        job->reply_payload.sg_cnt,
                                        from, size);
                job->reply->result = 0;
-
+               /* need to hold the lock until we set job->dd_data to NULL
+                * to hold off the timeout handler returning to the mid-layer
+                * while we are still processing the job.
+                */
                job->dd_data = NULL;
+               dd_data->context_un.mbox.set_job = NULL;
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                job->job_done(job);
+       } else {
+               dd_data->context_un.mbox.set_job = NULL;
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
        }
-       dd_data->context_un.mbox.set_job = NULL;
-       /* 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);
@@ -2644,6 +2646,11 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
        struct ulp_bde64 *rxbpl = NULL;
        struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *)
                job->request->rqst_data.h_vendor.vendor_cmd;
+       struct READ_EVENT_LOG_VAR *rdEventLog;
+       uint32_t transmit_length, receive_length, mode;
+       struct lpfc_mbx_nembed_cmd *nembed_sge;
+       struct mbox_header *header;
+       struct ulp_bde64 *bde;
        uint8_t *ext = NULL;
        int rc = 0;
        uint8_t *from;
@@ -2651,9 +2658,16 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
        /* in case no data is transferred */
        job->reply->reply_payload_rcv_len = 0;
 
+       /* sanity check to protect driver */
+       if (job->reply_payload.payload_len > BSG_MBOX_SIZE ||
+           job->request_payload.payload_len > BSG_MBOX_SIZE) {
+               rc = -ERANGE;
+               goto job_done;
+       }
+
        /* check if requested extended data lengths are valid */
-       if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) ||
-               (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) {
+       if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) ||
+           (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) {
                rc = -ERANGE;
                goto job_done;
        }
@@ -2744,8 +2758,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
         * 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 = pmb->un.varWords[1];
+               receive_length = pmb->un.varWords[4];
                /* transmit length cannot be greater than receive length or
                 * mailbox extension size
                 */
@@ -2795,10 +2809,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                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);
+               rdEventLog = &pmb->un.varRdEventLog;
+               receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
+               mode = bf_get(lpfc_event_log, rdEventLog);
 
                /* receive length cannot be greater than mailbox
                 * extension size
@@ -2843,7 +2856,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        /* 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 = pmb->un.varWords[2];
                        /* receive length cannot be greater than mailbox
                         * extension size
                         */
@@ -2879,8 +2892,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        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 = (struct ulp_bde64 *)&pmb->un.varWords[4];
 
                        /* bde size cannot be greater than mailbox ext size */
                        if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
@@ -2921,10 +2933,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        memcpy((uint8_t *)dmp->dma.virt, from,
                                bde->tus.f.bdeSize);
                } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) {
-                       struct lpfc_mbx_nembed_cmd *nembed_sge;
-                       struct mbox_header *header;
-                       uint32_t receive_length;
-
                        /* rebuild the command for sli4 using our own buffers
                        * like we do for biu diags
                        */
@@ -3386,6 +3394,7 @@ no_dd_data:
        job->dd_data = NULL;
        return rc;
 }
+
 /**
  * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
  * @job: fc_bsg_job to handle