diff options
| author | James Smart <james.smart@emulex.com> | 2009-12-21 17:01:23 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2010-01-04 12:39:42 -0500 |
| commit | eeead8115276a76675dc7cfc823a2461745edd27 (patch) | |
| tree | 3a07e0195d5c8a3ee4c91552dc03d0cf50566a0e | |
| parent | 91e6ecada757a6e2ef7b937634af8a04376772a1 (diff) | |
[SCSI] lpfc 8.3.7: Fix FC protocol errors
Fix FC protocol errors:
- Fix multi-frame unsolicited sequences not queued properly
- Fix frames for unsolicited sequences not being associated with sequence.
- Fix unsolicited frame buffer sizes are not set properly
- Fix Sequence count for unsolicited frame headers not byte swapped.
- Fix Multi-frame sequence response frames go to wrong DID.
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 21 |
2 files changed, 15 insertions, 8 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 1585148a17e5..09c8e362aee3 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h | |||
| @@ -1013,7 +1013,7 @@ struct lpfc_mbx_wq_destroy { | |||
| 1013 | }; | 1013 | }; |
| 1014 | 1014 | ||
| 1015 | #define LPFC_HDR_BUF_SIZE 128 | 1015 | #define LPFC_HDR_BUF_SIZE 128 |
| 1016 | #define LPFC_DATA_BUF_SIZE 4096 | 1016 | #define LPFC_DATA_BUF_SIZE 2048 |
| 1017 | struct rq_context { | 1017 | struct rq_context { |
| 1018 | uint32_t word0; | 1018 | uint32_t word0; |
| 1019 | #define lpfc_rq_context_rq_size_SHIFT 16 | 1019 | #define lpfc_rq_context_rq_size_SHIFT 16 |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 7935667b81a5..50f72bf18256 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
| @@ -5848,7 +5848,6 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
| 5848 | iocbq->iocb.un.ulpWord[3]); | 5848 | iocbq->iocb.un.ulpWord[3]); |
| 5849 | wqe->generic.word3 = 0; | 5849 | wqe->generic.word3 = 0; |
| 5850 | bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext); | 5850 | bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext); |
| 5851 | bf_set(wqe_xc, &wqe->generic, 1); | ||
| 5852 | /* The entire sequence is transmitted for this IOCB */ | 5851 | /* The entire sequence is transmitted for this IOCB */ |
| 5853 | xmit_len = total_len; | 5852 | xmit_len = total_len; |
| 5854 | cmnd = CMD_XMIT_SEQUENCE64_CR; | 5853 | cmnd = CMD_XMIT_SEQUENCE64_CR; |
| @@ -10944,7 +10943,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) | |||
| 10944 | return dmabuf; | 10943 | return dmabuf; |
| 10945 | } | 10944 | } |
| 10946 | temp_hdr = seq_dmabuf->hbuf.virt; | 10945 | temp_hdr = seq_dmabuf->hbuf.virt; |
| 10947 | if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) { | 10946 | if (be16_to_cpu(new_hdr->fh_seq_cnt) < |
| 10947 | be16_to_cpu(temp_hdr->fh_seq_cnt)) { | ||
| 10948 | list_del_init(&seq_dmabuf->hbuf.list); | 10948 | list_del_init(&seq_dmabuf->hbuf.list); |
| 10949 | list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); | 10949 | list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); |
| 10950 | list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); | 10950 | list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); |
| @@ -10955,6 +10955,11 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) | |||
| 10955 | list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list); | 10955 | list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list); |
| 10956 | seq_dmabuf->time_stamp = jiffies; | 10956 | seq_dmabuf->time_stamp = jiffies; |
| 10957 | lpfc_update_rcv_time_stamp(vport); | 10957 | lpfc_update_rcv_time_stamp(vport); |
| 10958 | if (list_empty(&seq_dmabuf->dbuf.list)) { | ||
| 10959 | temp_hdr = dmabuf->hbuf.virt; | ||
| 10960 | list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); | ||
| 10961 | return seq_dmabuf; | ||
| 10962 | } | ||
| 10958 | /* find the correct place in the sequence to insert this frame */ | 10963 | /* find the correct place in the sequence to insert this frame */ |
| 10959 | list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) { | 10964 | list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) { |
| 10960 | temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); | 10965 | temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); |
| @@ -10963,7 +10968,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) | |||
| 10963 | * If the frame's sequence count is greater than the frame on | 10968 | * If the frame's sequence count is greater than the frame on |
| 10964 | * the list then insert the frame right after this frame | 10969 | * the list then insert the frame right after this frame |
| 10965 | */ | 10970 | */ |
| 10966 | if (new_hdr->fh_seq_cnt > temp_hdr->fh_seq_cnt) { | 10971 | if (be16_to_cpu(new_hdr->fh_seq_cnt) > |
| 10972 | be16_to_cpu(temp_hdr->fh_seq_cnt)) { | ||
| 10967 | list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list); | 10973 | list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list); |
| 10968 | return seq_dmabuf; | 10974 | return seq_dmabuf; |
| 10969 | } | 10975 | } |
| @@ -11210,7 +11216,7 @@ lpfc_seq_complete(struct hbq_dmabuf *dmabuf) | |||
| 11210 | seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); | 11216 | seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); |
| 11211 | hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; | 11217 | hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; |
| 11212 | /* If there is a hole in the sequence count then fail. */ | 11218 | /* If there is a hole in the sequence count then fail. */ |
| 11213 | if (++seq_count != hdr->fh_seq_cnt) | 11219 | if (++seq_count != be16_to_cpu(hdr->fh_seq_cnt)) |
| 11214 | return 0; | 11220 | return 0; |
| 11215 | fctl = (hdr->fh_f_ctl[0] << 16 | | 11221 | fctl = (hdr->fh_f_ctl[0] << 16 | |
| 11216 | hdr->fh_f_ctl[1] << 8 | | 11222 | hdr->fh_f_ctl[1] << 8 | |
| @@ -11242,6 +11248,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) | |||
| 11242 | struct lpfc_iocbq *first_iocbq, *iocbq; | 11248 | struct lpfc_iocbq *first_iocbq, *iocbq; |
| 11243 | struct fc_frame_header *fc_hdr; | 11249 | struct fc_frame_header *fc_hdr; |
| 11244 | uint32_t sid; | 11250 | uint32_t sid; |
| 11251 | struct ulp_bde64 *pbde; | ||
| 11245 | 11252 | ||
| 11246 | fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; | 11253 | fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; |
| 11247 | /* remove from receive buffer list */ | 11254 | /* remove from receive buffer list */ |
| @@ -11283,8 +11290,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) | |||
| 11283 | if (!iocbq->context3) { | 11290 | if (!iocbq->context3) { |
| 11284 | iocbq->context3 = d_buf; | 11291 | iocbq->context3 = d_buf; |
| 11285 | iocbq->iocb.ulpBdeCount++; | 11292 | iocbq->iocb.ulpBdeCount++; |
| 11286 | iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize = | 11293 | pbde = (struct ulp_bde64 *) |
| 11287 | LPFC_DATA_BUF_SIZE; | 11294 | &iocbq->iocb.unsli3.sli3Words[4]; |
| 11295 | pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; | ||
| 11288 | first_iocbq->iocb.unsli3.rcvsli3.acc_len += | 11296 | first_iocbq->iocb.unsli3.rcvsli3.acc_len += |
| 11289 | bf_get(lpfc_rcqe_length, | 11297 | bf_get(lpfc_rcqe_length, |
| 11290 | &seq_dmabuf->cq_event.cqe.rcqe_cmpl); | 11298 | &seq_dmabuf->cq_event.cqe.rcqe_cmpl); |
| @@ -11407,7 +11415,6 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, | |||
| 11407 | * frame to be freed when it is finished. | 11415 | * frame to be freed when it is finished. |
| 11408 | **/ | 11416 | **/ |
| 11409 | lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1); | 11417 | lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1); |
| 11410 | dmabuf->tag = -1; | ||
| 11411 | return; | 11418 | return; |
| 11412 | } | 11419 | } |
| 11413 | /* Send the complete sequence to the upper layer protocol */ | 11420 | /* Send the complete sequence to the upper layer protocol */ |
