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 /drivers/scsi | |
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>
Diffstat (limited to 'drivers/scsi')
-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 */ |