diff options
author | Quinn Tran <quinn.tran@cavium.com> | 2016-12-23 21:06:11 -0500 |
---|---|---|
committer | Bart Van Assche <bart.vanassche@sandisk.com> | 2017-01-17 14:26:56 -0500 |
commit | 5f35509db179ca7ed1feaa4b14f841adb06ed220 (patch) | |
tree | f5b4e6bc95ec09eed327291db14d45217ebb6e33 | |
parent | fc1ffd6cb38a1c1af625b9833c41928039e733f5 (diff) |
qla2xxx: Terminate exchange if corrupted
Corrupted ATIO is defined as length of fcp_header & fcp_cmd
payload is less than 0x38. It's the minimum size for a frame to
carry 8..16 bytes SCSI CDB. The exchange will be dropped or
terminated if corrupted.
Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
[ bvanassche: Fixed spelling in patch title ]
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 23 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.h | 22 |
3 files changed, 43 insertions, 5 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index f7df01b76714..1f7c6d2c736d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -1556,7 +1556,8 @@ typedef struct { | |||
1556 | struct atio { | 1556 | struct atio { |
1557 | uint8_t entry_type; /* Entry type. */ | 1557 | uint8_t entry_type; /* Entry type. */ |
1558 | uint8_t entry_count; /* Entry count. */ | 1558 | uint8_t entry_count; /* Entry count. */ |
1559 | uint8_t data[58]; | 1559 | __le16 attr_n_length; |
1560 | uint8_t data[56]; | ||
1560 | uint32_t signature; | 1561 | uint32_t signature; |
1561 | #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ | 1562 | #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ |
1562 | }; | 1563 | }; |
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 6eb051783dc8..85dcd7cdffca 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
@@ -6454,12 +6454,29 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) | |||
6454 | if (!vha->flags.online) | 6454 | if (!vha->flags.online) |
6455 | return; | 6455 | return; |
6456 | 6456 | ||
6457 | while (ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) { | 6457 | while ((ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) || |
6458 | fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr)) { | ||
6458 | pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; | 6459 | pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; |
6459 | cnt = pkt->u.raw.entry_count; | 6460 | cnt = pkt->u.raw.entry_count; |
6460 | 6461 | ||
6461 | qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt, | 6462 | if (unlikely(fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr))) { |
6462 | ha_locked); | 6463 | /* |
6464 | * This packet is corrupted. The header + payload | ||
6465 | * can not be trusted. There is no point in passing | ||
6466 | * it further up. | ||
6467 | */ | ||
6468 | ql_log(ql_log_warn, vha, 0xffff, | ||
6469 | "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n", | ||
6470 | pkt->u.isp24.fcp_hdr.s_id, | ||
6471 | be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id), | ||
6472 | le32_to_cpu(pkt->u.isp24.exchange_addr), pkt); | ||
6473 | |||
6474 | adjust_corrupted_atio(pkt); | ||
6475 | qlt_send_term_exchange(vha, NULL, pkt, ha_locked, 0); | ||
6476 | } else { | ||
6477 | qlt_24xx_atio_pkt_all_vps(vha, | ||
6478 | (struct atio_from_isp *)pkt, ha_locked); | ||
6479 | } | ||
6463 | 6480 | ||
6464 | for (i = 0; i < cnt; i++) { | 6481 | for (i = 0; i < cnt; i++) { |
6465 | ha->tgt.atio_ring_index++; | 6482 | ha->tgt.atio_ring_index++; |
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index f26c5f60eedd..0824a8164a24 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h | |||
@@ -427,13 +427,33 @@ struct atio_from_isp { | |||
427 | struct { | 427 | struct { |
428 | uint8_t entry_type; /* Entry type. */ | 428 | uint8_t entry_type; /* Entry type. */ |
429 | uint8_t entry_count; /* Entry count. */ | 429 | uint8_t entry_count; /* Entry count. */ |
430 | uint8_t data[58]; | 430 | __le16 attr_n_length; |
431 | #define FCP_CMD_LENGTH_MASK 0x0fff | ||
432 | #define FCP_CMD_LENGTH_MIN 0x38 | ||
433 | uint8_t data[56]; | ||
431 | uint32_t signature; | 434 | uint32_t signature; |
432 | #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ | 435 | #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ |
433 | } raw; | 436 | } raw; |
434 | } u; | 437 | } u; |
435 | } __packed; | 438 | } __packed; |
436 | 439 | ||
440 | static inline int fcpcmd_is_corrupted(struct atio *atio) | ||
441 | { | ||
442 | if (atio->entry_type == ATIO_TYPE7 && | ||
443 | (le16_to_cpu(atio->attr_n_length & FCP_CMD_LENGTH_MASK) < | ||
444 | FCP_CMD_LENGTH_MIN)) | ||
445 | return 1; | ||
446 | else | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | /* adjust corrupted atio so we won't trip over the same entry again. */ | ||
451 | static inline void adjust_corrupted_atio(struct atio_from_isp *atio) | ||
452 | { | ||
453 | atio->u.raw.attr_n_length = cpu_to_le16(FCP_CMD_LENGTH_MIN); | ||
454 | atio->u.isp24.fcp_cmnd.add_cdb_len = 0; | ||
455 | } | ||
456 | |||
437 | #define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */ | 457 | #define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */ |
438 | 458 | ||
439 | /* | 459 | /* |