diff options
author | James Smart <james.smart@emulex.com> | 2011-04-16 11:03:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-05-01 12:10:41 -0400 |
commit | b6e3b9c606f271824bdeb6a40a080452eb086598 (patch) | |
tree | 9180f8036f9a729b40b2c8243e241c600d6afa12 /drivers/scsi/lpfc/lpfc_bsg.c | |
parent | c31098cef5e091e22a02ff255f911e0ad71cc393 (diff) |
[SCSI] lpfc 8.3.23: BSG additions and fixes
- Fixed the mixed declarations and codes which violate ISO C90
(declarations in subsections that assign at declaration)
- Add BSG data transfer size protection in mailbox command pass-through path
- Invoke BSG job_done while holding spinlock to fix deadlock
- Added support for checking SLI_CONFIG subcommands
- Fixed bug in BSG mailbox size check to non-embedded external buffer
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>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_bsg.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 59 |
1 files changed, 34 insertions, 25 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 77b2871d96b7..37e2a1272f86 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -2426,6 +2426,7 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
2426 | { | 2426 | { |
2427 | struct bsg_job_data *dd_data; | 2427 | struct bsg_job_data *dd_data; |
2428 | struct fc_bsg_job *job; | 2428 | struct fc_bsg_job *job; |
2429 | struct lpfc_mbx_nembed_cmd *nembed_sge; | ||
2429 | uint32_t size; | 2430 | uint32_t size; |
2430 | unsigned long flags; | 2431 | unsigned long flags; |
2431 | uint8_t *to; | 2432 | uint8_t *to; |
@@ -2469,9 +2470,8 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
2469 | memcpy(to, from, size); | 2470 | memcpy(to, from, size); |
2470 | } else if ((phba->sli_rev == LPFC_SLI_REV4) && | 2471 | } else if ((phba->sli_rev == LPFC_SLI_REV4) && |
2471 | (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { | 2472 | (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { |
2472 | struct lpfc_mbx_nembed_cmd *nembed_sge = | 2473 | nembed_sge = (struct lpfc_mbx_nembed_cmd *) |
2473 | (struct lpfc_mbx_nembed_cmd *) | 2474 | &pmboxq->u.mb.un.varWords[0]; |
2474 | &pmboxq->u.mb.un.varWords[0]; | ||
2475 | 2475 | ||
2476 | from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. | 2476 | from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. |
2477 | virt; | 2477 | virt; |
@@ -2496,16 +2496,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
2496 | job->reply_payload.sg_cnt, | 2496 | job->reply_payload.sg_cnt, |
2497 | from, size); | 2497 | from, size); |
2498 | job->reply->result = 0; | 2498 | job->reply->result = 0; |
2499 | 2499 | /* need to hold the lock until we set job->dd_data to NULL | |
2500 | * to hold off the timeout handler returning to the mid-layer | ||
2501 | * while we are still processing the job. | ||
2502 | */ | ||
2500 | job->dd_data = NULL; | 2503 | job->dd_data = NULL; |
2504 | dd_data->context_un.mbox.set_job = NULL; | ||
2505 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2501 | job->job_done(job); | 2506 | job->job_done(job); |
2507 | } else { | ||
2508 | dd_data->context_un.mbox.set_job = NULL; | ||
2509 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2502 | } | 2510 | } |
2503 | dd_data->context_un.mbox.set_job = NULL; | ||
2504 | /* need to hold the lock until we call job done to hold off | ||
2505 | * the timeout handler returning to the midlayer while | ||
2506 | * we are stillprocessing the job | ||
2507 | */ | ||
2508 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2509 | 2511 | ||
2510 | kfree(dd_data->context_un.mbox.mb); | 2512 | kfree(dd_data->context_un.mbox.mb); |
2511 | mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); | 2513 | 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, | |||
2644 | struct ulp_bde64 *rxbpl = NULL; | 2646 | struct ulp_bde64 *rxbpl = NULL; |
2645 | struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) | 2647 | struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) |
2646 | job->request->rqst_data.h_vendor.vendor_cmd; | 2648 | job->request->rqst_data.h_vendor.vendor_cmd; |
2649 | struct READ_EVENT_LOG_VAR *rdEventLog; | ||
2650 | uint32_t transmit_length, receive_length, mode; | ||
2651 | struct lpfc_mbx_nembed_cmd *nembed_sge; | ||
2652 | struct mbox_header *header; | ||
2653 | struct ulp_bde64 *bde; | ||
2647 | uint8_t *ext = NULL; | 2654 | uint8_t *ext = NULL; |
2648 | int rc = 0; | 2655 | int rc = 0; |
2649 | uint8_t *from; | 2656 | uint8_t *from; |
@@ -2651,9 +2658,16 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | |||
2651 | /* in case no data is transferred */ | 2658 | /* in case no data is transferred */ |
2652 | job->reply->reply_payload_rcv_len = 0; | 2659 | job->reply->reply_payload_rcv_len = 0; |
2653 | 2660 | ||
2661 | /* sanity check to protect driver */ | ||
2662 | if (job->reply_payload.payload_len > BSG_MBOX_SIZE || | ||
2663 | job->request_payload.payload_len > BSG_MBOX_SIZE) { | ||
2664 | rc = -ERANGE; | ||
2665 | goto job_done; | ||
2666 | } | ||
2667 | |||
2654 | /* check if requested extended data lengths are valid */ | 2668 | /* check if requested extended data lengths are valid */ |
2655 | if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || | 2669 | if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || |
2656 | (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { | 2670 | (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { |
2657 | rc = -ERANGE; | 2671 | rc = -ERANGE; |
2658 | goto job_done; | 2672 | goto job_done; |
2659 | } | 2673 | } |
@@ -2744,8 +2758,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | |||
2744 | * use ours | 2758 | * use ours |
2745 | */ | 2759 | */ |
2746 | if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { | 2760 | if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { |
2747 | uint32_t transmit_length = pmb->un.varWords[1]; | 2761 | transmit_length = pmb->un.varWords[1]; |
2748 | uint32_t receive_length = pmb->un.varWords[4]; | 2762 | receive_length = pmb->un.varWords[4]; |
2749 | /* transmit length cannot be greater than receive length or | 2763 | /* transmit length cannot be greater than receive length or |
2750 | * mailbox extension size | 2764 | * mailbox extension size |
2751 | */ | 2765 | */ |
@@ -2795,10 +2809,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | |||
2795 | from += sizeof(MAILBOX_t); | 2809 | from += sizeof(MAILBOX_t); |
2796 | memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); | 2810 | memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); |
2797 | } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { | 2811 | } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { |
2798 | struct READ_EVENT_LOG_VAR *rdEventLog = | 2812 | rdEventLog = &pmb->un.varRdEventLog; |
2799 | &pmb->un.varRdEventLog ; | 2813 | receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; |
2800 | uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; | 2814 | mode = bf_get(lpfc_event_log, rdEventLog); |
2801 | uint32_t mode = bf_get(lpfc_event_log, rdEventLog); | ||
2802 | 2815 | ||
2803 | /* receive length cannot be greater than mailbox | 2816 | /* receive length cannot be greater than mailbox |
2804 | * extension size | 2817 | * extension size |
@@ -2843,7 +2856,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | |||
2843 | /* rebuild the command for sli4 using our own buffers | 2856 | /* rebuild the command for sli4 using our own buffers |
2844 | * like we do for biu diags | 2857 | * like we do for biu diags |
2845 | */ | 2858 | */ |
2846 | uint32_t receive_length = pmb->un.varWords[2]; | 2859 | receive_length = pmb->un.varWords[2]; |
2847 | /* receive length cannot be greater than mailbox | 2860 | /* receive length cannot be greater than mailbox |
2848 | * extension size | 2861 | * extension size |
2849 | */ | 2862 | */ |
@@ -2879,8 +2892,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | |||
2879 | pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); | 2892 | pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); |
2880 | } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && | 2893 | } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && |
2881 | pmb->un.varUpdateCfg.co) { | 2894 | pmb->un.varUpdateCfg.co) { |
2882 | struct ulp_bde64 *bde = | 2895 | bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; |
2883 | (struct ulp_bde64 *)&pmb->un.varWords[4]; | ||
2884 | 2896 | ||
2885 | /* bde size cannot be greater than mailbox ext size */ | 2897 | /* bde size cannot be greater than mailbox ext size */ |
2886 | if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { | 2898 | 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, | |||
2921 | memcpy((uint8_t *)dmp->dma.virt, from, | 2933 | memcpy((uint8_t *)dmp->dma.virt, from, |
2922 | bde->tus.f.bdeSize); | 2934 | bde->tus.f.bdeSize); |
2923 | } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { | 2935 | } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { |
2924 | struct lpfc_mbx_nembed_cmd *nembed_sge; | ||
2925 | struct mbox_header *header; | ||
2926 | uint32_t receive_length; | ||
2927 | |||
2928 | /* rebuild the command for sli4 using our own buffers | 2936 | /* rebuild the command for sli4 using our own buffers |
2929 | * like we do for biu diags | 2937 | * like we do for biu diags |
2930 | */ | 2938 | */ |
@@ -3386,6 +3394,7 @@ no_dd_data: | |||
3386 | job->dd_data = NULL; | 3394 | job->dd_data = NULL; |
3387 | return rc; | 3395 | return rc; |
3388 | } | 3396 | } |
3397 | |||
3389 | /** | 3398 | /** |
3390 | * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job | 3399 | * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job |
3391 | * @job: fc_bsg_job to handle | 3400 | * @job: fc_bsg_job to handle |