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 | |
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')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 59 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 130 |
2 files changed, 164 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 |
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index a2c33e7c9152..b542aca6f5ae 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h | |||
@@ -109,3 +109,133 @@ struct menlo_response { | |||
109 | uint32_t xri; /* return the xri of the iocb exchange */ | 109 | uint32_t xri; /* return the xri of the iocb exchange */ |
110 | }; | 110 | }; |
111 | 111 | ||
112 | /* | ||
113 | * macros and data structures for handling sli-config mailbox command | ||
114 | * pass-through support, this header file is shared between user and | ||
115 | * kernel spaces, note the set of macros are duplicates from lpfc_hw4.h, | ||
116 | * with macro names prefixed with bsg_, as the macros defined in | ||
117 | * lpfc_hw4.h are not accessible from user space. | ||
118 | */ | ||
119 | |||
120 | /* Macros to deal with bit fields. Each bit field must have 3 #defines | ||
121 | * associated with it (_SHIFT, _MASK, and _WORD). | ||
122 | * EG. For a bit field that is in the 7th bit of the "field4" field of a | ||
123 | * structure and is 2 bits in size the following #defines must exist: | ||
124 | * struct temp { | ||
125 | * uint32_t field1; | ||
126 | * uint32_t field2; | ||
127 | * uint32_t field3; | ||
128 | * uint32_t field4; | ||
129 | * #define example_bit_field_SHIFT 7 | ||
130 | * #define example_bit_field_MASK 0x03 | ||
131 | * #define example_bit_field_WORD field4 | ||
132 | * uint32_t field5; | ||
133 | * }; | ||
134 | * Then the macros below may be used to get or set the value of that field. | ||
135 | * EG. To get the value of the bit field from the above example: | ||
136 | * struct temp t1; | ||
137 | * value = bsg_bf_get(example_bit_field, &t1); | ||
138 | * And then to set that bit field: | ||
139 | * bsg_bf_set(example_bit_field, &t1, 2); | ||
140 | * Or clear that bit field: | ||
141 | * bsg_bf_set(example_bit_field, &t1, 0); | ||
142 | */ | ||
143 | #define bsg_bf_get_le32(name, ptr) \ | ||
144 | ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) | ||
145 | #define bsg_bf_get(name, ptr) \ | ||
146 | (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) | ||
147 | #define bsg_bf_set_le32(name, ptr, value) \ | ||
148 | ((ptr)->name##_WORD = cpu_to_le32(((((value) & \ | ||
149 | name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ | ||
150 | ~(name##_MASK << name##_SHIFT))))) | ||
151 | #define bsg_bf_set(name, ptr, value) \ | ||
152 | ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ | ||
153 | ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) | ||
154 | |||
155 | /* | ||
156 | * The sli_config structure specified here is based on the following | ||
157 | * restriction: | ||
158 | * | ||
159 | * -- SLI_CONFIG EMB=0, carrying MSEs, will carry subcommands without | ||
160 | * carrying HBD. | ||
161 | * -- SLI_CONFIG EMB=1, not carrying MSE, will carry subcommands with or | ||
162 | * without carrying HBDs. | ||
163 | */ | ||
164 | |||
165 | struct lpfc_sli_config_mse { | ||
166 | uint32_t pa_lo; | ||
167 | uint32_t pa_hi; | ||
168 | uint32_t buf_len; | ||
169 | #define lpfc_mbox_sli_config_mse_len_SHIFT 0 | ||
170 | #define lpfc_mbox_sli_config_mse_len_MASK 0xffffff | ||
171 | #define lpfc_mbox_sli_config_mse_len_WORD buf_len | ||
172 | }; | ||
173 | |||
174 | struct lpfc_sli_config_subcmd_hbd { | ||
175 | uint32_t buf_len; | ||
176 | #define lpfc_mbox_sli_config_ecmn_hbd_len_SHIFT 0 | ||
177 | #define lpfc_mbox_sli_config_ecmn_hbd_len_MASK 0xffffff | ||
178 | #define lpfc_mbox_sli_config_ecmn_hbd_len_WORD buf_len | ||
179 | uint32_t pa_lo; | ||
180 | uint32_t pa_hi; | ||
181 | }; | ||
182 | |||
183 | struct lpfc_sli_config_hdr { | ||
184 | uint32_t word1; | ||
185 | #define lpfc_mbox_hdr_emb_SHIFT 0 | ||
186 | #define lpfc_mbox_hdr_emb_MASK 0x00000001 | ||
187 | #define lpfc_mbox_hdr_emb_WORD word1 | ||
188 | #define lpfc_mbox_hdr_mse_cnt_SHIFT 3 | ||
189 | #define lpfc_mbox_hdr_mse_cnt_MASK 0x0000001f | ||
190 | #define lpfc_mbox_hdr_mse_cnt_WORD word1 | ||
191 | uint32_t payload_length; | ||
192 | uint32_t tag_lo; | ||
193 | uint32_t tag_hi; | ||
194 | uint32_t reserved5; | ||
195 | }; | ||
196 | |||
197 | struct lpfc_sli_config_generic { | ||
198 | struct lpfc_sli_config_hdr sli_config_hdr; | ||
199 | #define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 | ||
200 | struct lpfc_sli_config_mse mse[LPFC_MBX_SLI_CONFIG_MAX_MSE]; | ||
201 | }; | ||
202 | |||
203 | struct lpfc_sli_config_subcmnd { | ||
204 | struct lpfc_sli_config_hdr sli_config_hdr; | ||
205 | uint32_t word6; | ||
206 | #define lpfc_subcmnd_opcode_SHIFT 0 | ||
207 | #define lpfc_subcmnd_opcode_MASK 0xff | ||
208 | #define lpfc_subcmnd_opcode_WORD word6 | ||
209 | #define lpfc_subcmnd_subsys_SHIFT 8 | ||
210 | #define lpfc_subcmnd_subsys_MASK 0xff | ||
211 | #define lpfc_subcmnd_subsys_WORD word6 | ||
212 | uint32_t timeout; | ||
213 | uint32_t request_length; | ||
214 | uint32_t word9; | ||
215 | #define lpfc_subcmnd_version_SHIFT 0 | ||
216 | #define lpfc_subcmnd_version_MASK 0xff | ||
217 | #define lpfc_subcmnd_version_WORD word9 | ||
218 | uint32_t word10; | ||
219 | #define lpfc_subcmnd_ask_rd_len_SHIFT 0 | ||
220 | #define lpfc_subcmnd_ask_rd_len_MASK 0xffffff | ||
221 | #define lpfc_subcmnd_ask_rd_len_WORD word10 | ||
222 | uint32_t rd_offset; | ||
223 | uint32_t obj_name[26]; | ||
224 | uint32_t hbd_count; | ||
225 | #define LPFC_MBX_SLI_CONFIG_MAX_HBD 10 | ||
226 | struct lpfc_sli_config_subcmd_hbd hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD]; | ||
227 | }; | ||
228 | |||
229 | struct lpfc_sli_config_mbox { | ||
230 | uint32_t word0; | ||
231 | #define lpfc_mqe_status_SHIFT 16 | ||
232 | #define lpfc_mqe_status_MASK 0x0000FFFF | ||
233 | #define lpfc_mqe_status_WORD word0 | ||
234 | #define lpfc_mqe_command_SHIFT 8 | ||
235 | #define lpfc_mqe_command_MASK 0x000000FF | ||
236 | #define lpfc_mqe_command_WORD word0 | ||
237 | union { | ||
238 | struct lpfc_sli_config_generic sli_config_generic; | ||
239 | struct lpfc_sli_config_subcmnd sli_config_subcmnd; | ||
240 | } un; | ||
241 | }; | ||