diff options
-rw-r--r-- | drivers/target/target_core_cdb.c | 150 | ||||
-rw-r--r-- | include/target/target_core_base.h | 2 |
2 files changed, 37 insertions, 115 deletions
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index f3d71fa88a28..ef8034b60d8d 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c | |||
@@ -66,24 +66,11 @@ target_fill_alua_data(struct se_port *port, unsigned char *buf) | |||
66 | } | 66 | } |
67 | 67 | ||
68 | static int | 68 | static int |
69 | target_emulate_inquiry_std(struct se_cmd *cmd) | 69 | target_emulate_inquiry_std(struct se_cmd *cmd, char *buf) |
70 | { | 70 | { |
71 | struct se_lun *lun = cmd->se_lun; | 71 | struct se_lun *lun = cmd->se_lun; |
72 | struct se_device *dev = cmd->se_dev; | 72 | struct se_device *dev = cmd->se_dev; |
73 | struct se_portal_group *tpg = lun->lun_sep->sep_tpg; | 73 | struct se_portal_group *tpg = lun->lun_sep->sep_tpg; |
74 | unsigned char *buf; | ||
75 | |||
76 | /* | ||
77 | * Make sure we at least have 6 bytes of INQUIRY response | ||
78 | * payload going back for EVPD=0 | ||
79 | */ | ||
80 | if (cmd->data_length < 6) { | ||
81 | pr_err("SCSI Inquiry payload length: %u" | ||
82 | " too small for EVPD=0\n", cmd->data_length); | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
86 | buf = transport_kmap_data_sg(cmd); | ||
87 | 74 | ||
88 | if (dev == tpg->tpg_virt_lun0.lun_se_dev) { | 75 | if (dev == tpg->tpg_virt_lun0.lun_se_dev) { |
89 | buf[0] = 0x3f; /* Not connected */ | 76 | buf[0] = 0x3f; /* Not connected */ |
@@ -112,29 +99,13 @@ target_emulate_inquiry_std(struct se_cmd *cmd) | |||
112 | if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) | 99 | if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) |
113 | target_fill_alua_data(lun->lun_sep, buf); | 100 | target_fill_alua_data(lun->lun_sep, buf); |
114 | 101 | ||
115 | if (cmd->data_length < 8) { | ||
116 | buf[4] = 1; /* Set additional length to 1 */ | ||
117 | goto out; | ||
118 | } | ||
119 | |||
120 | buf[7] = 0x32; /* Sync=1 and CmdQue=1 */ | 102 | buf[7] = 0x32; /* Sync=1 and CmdQue=1 */ |
121 | 103 | ||
122 | /* | ||
123 | * Do not include vendor, product, reversion info in INQUIRY | ||
124 | * response payload for cdbs with a small allocation length. | ||
125 | */ | ||
126 | if (cmd->data_length < 36) { | ||
127 | buf[4] = 3; /* Set additional length to 3 */ | ||
128 | goto out; | ||
129 | } | ||
130 | |||
131 | snprintf(&buf[8], 8, "LIO-ORG"); | 104 | snprintf(&buf[8], 8, "LIO-ORG"); |
132 | snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); | 105 | snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); |
133 | snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); | 106 | snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); |
134 | buf[4] = 31; /* Set additional length to 31 */ | 107 | buf[4] = 31; /* Set additional length to 31 */ |
135 | 108 | ||
136 | out: | ||
137 | transport_kunmap_data_sg(cmd); | ||
138 | return 0; | 109 | return 0; |
139 | } | 110 | } |
140 | 111 | ||
@@ -152,12 +123,6 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | |||
152 | unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); | 123 | unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); |
153 | unit_serial_len++; /* For NULL Terminator */ | 124 | unit_serial_len++; /* For NULL Terminator */ |
154 | 125 | ||
155 | if (((len + 4) + unit_serial_len) > cmd->data_length) { | ||
156 | len += unit_serial_len; | ||
157 | buf[2] = ((len >> 8) & 0xff); | ||
158 | buf[3] = (len & 0xff); | ||
159 | return 0; | ||
160 | } | ||
161 | len += sprintf(&buf[4], "%s", | 126 | len += sprintf(&buf[4], "%s", |
162 | dev->se_sub_dev->t10_wwn.unit_serial); | 127 | dev->se_sub_dev->t10_wwn.unit_serial); |
163 | len++; /* Extra Byte for NULL Terminator */ | 128 | len++; /* Extra Byte for NULL Terminator */ |
@@ -229,9 +194,6 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) | |||
229 | if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) | 194 | if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) |
230 | goto check_t10_vend_desc; | 195 | goto check_t10_vend_desc; |
231 | 196 | ||
232 | if (off + 20 > cmd->data_length) | ||
233 | goto check_t10_vend_desc; | ||
234 | |||
235 | /* CODE SET == Binary */ | 197 | /* CODE SET == Binary */ |
236 | buf[off++] = 0x1; | 198 | buf[off++] = 0x1; |
237 | 199 | ||
@@ -283,12 +245,6 @@ check_t10_vend_desc: | |||
283 | strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); | 245 | strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); |
284 | unit_serial_len++; /* For NULL Terminator */ | 246 | unit_serial_len++; /* For NULL Terminator */ |
285 | 247 | ||
286 | if ((len + (id_len + 4) + | ||
287 | (prod_len + unit_serial_len)) > | ||
288 | cmd->data_length) { | ||
289 | len += (prod_len + unit_serial_len); | ||
290 | goto check_port; | ||
291 | } | ||
292 | id_len += sprintf(&buf[off+12], "%s:%s", prod, | 248 | id_len += sprintf(&buf[off+12], "%s:%s", prod, |
293 | &dev->se_sub_dev->t10_wwn.unit_serial[0]); | 249 | &dev->se_sub_dev->t10_wwn.unit_serial[0]); |
294 | } | 250 | } |
@@ -306,7 +262,6 @@ check_t10_vend_desc: | |||
306 | /* | 262 | /* |
307 | * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD | 263 | * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD |
308 | */ | 264 | */ |
309 | check_port: | ||
310 | port = lun->lun_sep; | 265 | port = lun->lun_sep; |
311 | if (port) { | 266 | if (port) { |
312 | struct t10_alua_lu_gp *lu_gp; | 267 | struct t10_alua_lu_gp *lu_gp; |
@@ -323,10 +278,6 @@ check_port: | |||
323 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 | 278 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 |
324 | * section 7.5.1 Table 362 | 279 | * section 7.5.1 Table 362 |
325 | */ | 280 | */ |
326 | if (((len + 4) + 8) > cmd->data_length) { | ||
327 | len += 8; | ||
328 | goto check_tpgi; | ||
329 | } | ||
330 | buf[off] = | 281 | buf[off] = |
331 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); | 282 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); |
332 | buf[off++] |= 0x1; /* CODE SET == Binary */ | 283 | buf[off++] |= 0x1; /* CODE SET == Binary */ |
@@ -350,15 +301,10 @@ check_port: | |||
350 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 | 301 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 |
351 | * section 7.5.1 Table 362 | 302 | * section 7.5.1 Table 362 |
352 | */ | 303 | */ |
353 | check_tpgi: | ||
354 | if (dev->se_sub_dev->t10_alua.alua_type != | 304 | if (dev->se_sub_dev->t10_alua.alua_type != |
355 | SPC3_ALUA_EMULATED) | 305 | SPC3_ALUA_EMULATED) |
356 | goto check_scsi_name; | 306 | goto check_scsi_name; |
357 | 307 | ||
358 | if (((len + 4) + 8) > cmd->data_length) { | ||
359 | len += 8; | ||
360 | goto check_lu_gp; | ||
361 | } | ||
362 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; | 308 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; |
363 | if (!tg_pt_gp_mem) | 309 | if (!tg_pt_gp_mem) |
364 | goto check_lu_gp; | 310 | goto check_lu_gp; |
@@ -391,10 +337,6 @@ check_tpgi: | |||
391 | * section 7.7.3.8 | 337 | * section 7.7.3.8 |
392 | */ | 338 | */ |
393 | check_lu_gp: | 339 | check_lu_gp: |
394 | if (((len + 4) + 8) > cmd->data_length) { | ||
395 | len += 8; | ||
396 | goto check_scsi_name; | ||
397 | } | ||
398 | lu_gp_mem = dev->dev_alua_lu_gp_mem; | 340 | lu_gp_mem = dev->dev_alua_lu_gp_mem; |
399 | if (!lu_gp_mem) | 341 | if (!lu_gp_mem) |
400 | goto check_scsi_name; | 342 | goto check_scsi_name; |
@@ -435,10 +377,6 @@ check_scsi_name: | |||
435 | /* Header size + Designation descriptor */ | 377 | /* Header size + Designation descriptor */ |
436 | scsi_name_len += 4; | 378 | scsi_name_len += 4; |
437 | 379 | ||
438 | if (((len + 4) + scsi_name_len) > cmd->data_length) { | ||
439 | len += scsi_name_len; | ||
440 | goto set_len; | ||
441 | } | ||
442 | buf[off] = | 380 | buf[off] = |
443 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); | 381 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); |
444 | buf[off++] |= 0x3; /* CODE SET == UTF-8 */ | 382 | buf[off++] |= 0x3; /* CODE SET == UTF-8 */ |
@@ -474,7 +412,6 @@ check_scsi_name: | |||
474 | /* Header size + Designation descriptor */ | 412 | /* Header size + Designation descriptor */ |
475 | len += (scsi_name_len + 4); | 413 | len += (scsi_name_len + 4); |
476 | } | 414 | } |
477 | set_len: | ||
478 | buf[2] = ((len >> 8) & 0xff); | 415 | buf[2] = ((len >> 8) & 0xff); |
479 | buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ | 416 | buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ |
480 | return 0; | 417 | return 0; |
@@ -484,9 +421,6 @@ set_len: | |||
484 | static int | 421 | static int |
485 | target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) | 422 | target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) |
486 | { | 423 | { |
487 | if (cmd->data_length < 60) | ||
488 | return 0; | ||
489 | |||
490 | buf[3] = 0x3c; | 424 | buf[3] = 0x3c; |
491 | /* Set HEADSUP, ORDSUP, SIMPSUP */ | 425 | /* Set HEADSUP, ORDSUP, SIMPSUP */ |
492 | buf[5] = 0x07; | 426 | buf[5] = 0x07; |
@@ -512,20 +446,6 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) | |||
512 | if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) | 446 | if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) |
513 | have_tp = 1; | 447 | have_tp = 1; |
514 | 448 | ||
515 | if (cmd->data_length < (0x10 + 4)) { | ||
516 | pr_debug("Received data_length: %u" | ||
517 | " too small for EVPD 0xb0\n", | ||
518 | cmd->data_length); | ||
519 | return -EINVAL; | ||
520 | } | ||
521 | |||
522 | if (have_tp && cmd->data_length < (0x3c + 4)) { | ||
523 | pr_debug("Received data_length: %u" | ||
524 | " too small for TPE=1 EVPD 0xb0\n", | ||
525 | cmd->data_length); | ||
526 | have_tp = 0; | ||
527 | } | ||
528 | |||
529 | buf[0] = dev->transport->get_device_type(dev); | 449 | buf[0] = dev->transport->get_device_type(dev); |
530 | buf[3] = have_tp ? 0x3c : 0x10; | 450 | buf[3] = have_tp ? 0x3c : 0x10; |
531 | 451 | ||
@@ -548,10 +468,9 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) | |||
548 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); | 468 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); |
549 | 469 | ||
550 | /* | 470 | /* |
551 | * Exit now if we don't support TP or the initiator sent a too | 471 | * Exit now if we don't support TP. |
552 | * short buffer. | ||
553 | */ | 472 | */ |
554 | if (!have_tp || cmd->data_length < (0x3c + 4)) | 473 | if (!have_tp) |
555 | return 0; | 474 | return 0; |
556 | 475 | ||
557 | /* | 476 | /* |
@@ -589,10 +508,7 @@ target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) | |||
589 | 508 | ||
590 | buf[0] = dev->transport->get_device_type(dev); | 509 | buf[0] = dev->transport->get_device_type(dev); |
591 | buf[3] = 0x3c; | 510 | buf[3] = 0x3c; |
592 | 511 | buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0; | |
593 | if (cmd->data_length >= 5 && | ||
594 | dev->se_sub_dev->se_dev_attrib.is_nonrot) | ||
595 | buf[5] = 1; | ||
596 | 512 | ||
597 | return 0; | 513 | return 0; |
598 | } | 514 | } |
@@ -671,8 +587,6 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) | |||
671 | { | 587 | { |
672 | int p; | 588 | int p; |
673 | 589 | ||
674 | if (cmd->data_length < 8) | ||
675 | return 0; | ||
676 | /* | 590 | /* |
677 | * Only report the INQUIRY EVPD=1 pages after a valid NAA | 591 | * Only report the INQUIRY EVPD=1 pages after a valid NAA |
678 | * Registered Extended LUN WWN has been set via ConfigFS | 592 | * Registered Extended LUN WWN has been set via ConfigFS |
@@ -681,8 +595,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) | |||
681 | if (cmd->se_dev->se_sub_dev->su_dev_flags & | 595 | if (cmd->se_dev->se_sub_dev->su_dev_flags & |
682 | SDF_EMULATED_VPD_UNIT_SERIAL) { | 596 | SDF_EMULATED_VPD_UNIT_SERIAL) { |
683 | buf[3] = ARRAY_SIZE(evpd_handlers); | 597 | buf[3] = ARRAY_SIZE(evpd_handlers); |
684 | for (p = 0; p < min_t(int, ARRAY_SIZE(evpd_handlers), | 598 | for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) |
685 | cmd->data_length - 4); ++p) | ||
686 | buf[p + 4] = evpd_handlers[p].page; | 599 | buf[p + 4] = evpd_handlers[p].page; |
687 | } | 600 | } |
688 | 601 | ||
@@ -693,45 +606,50 @@ int target_emulate_inquiry(struct se_task *task) | |||
693 | { | 606 | { |
694 | struct se_cmd *cmd = task->task_se_cmd; | 607 | struct se_cmd *cmd = task->task_se_cmd; |
695 | struct se_device *dev = cmd->se_dev; | 608 | struct se_device *dev = cmd->se_dev; |
696 | unsigned char *buf; | 609 | unsigned char *buf, *map_buf; |
697 | unsigned char *cdb = cmd->t_task_cdb; | 610 | unsigned char *cdb = cmd->t_task_cdb; |
698 | int p, ret; | 611 | int p, ret; |
699 | 612 | ||
613 | map_buf = transport_kmap_data_sg(cmd); | ||
614 | /* | ||
615 | * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we | ||
616 | * know we actually allocated a full page. Otherwise, if the | ||
617 | * data buffer is too small, allocate a temporary buffer so we | ||
618 | * don't have to worry about overruns in all our INQUIRY | ||
619 | * emulation handling. | ||
620 | */ | ||
621 | if (cmd->data_length < SE_INQUIRY_BUF && | ||
622 | (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { | ||
623 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); | ||
624 | if (!buf) { | ||
625 | transport_kunmap_data_sg(cmd); | ||
626 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
627 | return -ENOMEM; | ||
628 | } | ||
629 | } else { | ||
630 | buf = map_buf; | ||
631 | } | ||
632 | |||
700 | if (!(cdb[1] & 0x1)) { | 633 | if (!(cdb[1] & 0x1)) { |
701 | if (cdb[2]) { | 634 | if (cdb[2]) { |
702 | pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", | 635 | pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", |
703 | cdb[2]); | 636 | cdb[2]); |
704 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 637 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
705 | return -EINVAL; | 638 | ret = -EINVAL; |
639 | goto out; | ||
706 | } | 640 | } |
707 | 641 | ||
708 | ret = target_emulate_inquiry_std(cmd); | 642 | ret = target_emulate_inquiry_std(cmd, buf); |
709 | goto out; | 643 | goto out; |
710 | } | 644 | } |
711 | 645 | ||
712 | /* | ||
713 | * Make sure we at least have 4 bytes of INQUIRY response | ||
714 | * payload for 0x00 going back for EVPD=1. Note that 0x80 | ||
715 | * and 0x83 will check for enough payload data length and | ||
716 | * jump to set_len: label when there is not enough inquiry EVPD | ||
717 | * payload length left for the next outgoing EVPD metadata | ||
718 | */ | ||
719 | if (cmd->data_length < 4) { | ||
720 | pr_err("SCSI Inquiry payload length: %u" | ||
721 | " too small for EVPD=1\n", cmd->data_length); | ||
722 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
723 | return -EINVAL; | ||
724 | } | ||
725 | |||
726 | buf = transport_kmap_data_sg(cmd); | ||
727 | |||
728 | buf[0] = dev->transport->get_device_type(dev); | 646 | buf[0] = dev->transport->get_device_type(dev); |
729 | 647 | ||
730 | for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { | 648 | for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { |
731 | if (cdb[2] == evpd_handlers[p].page) { | 649 | if (cdb[2] == evpd_handlers[p].page) { |
732 | buf[1] = cdb[2]; | 650 | buf[1] = cdb[2]; |
733 | ret = evpd_handlers[p].emulate(cmd, buf); | 651 | ret = evpd_handlers[p].emulate(cmd, buf); |
734 | goto out_unmap; | 652 | goto out; |
735 | } | 653 | } |
736 | } | 654 | } |
737 | 655 | ||
@@ -739,9 +657,13 @@ int target_emulate_inquiry(struct se_task *task) | |||
739 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 657 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
740 | ret = -EINVAL; | 658 | ret = -EINVAL; |
741 | 659 | ||
742 | out_unmap: | ||
743 | transport_kunmap_data_sg(cmd); | ||
744 | out: | 660 | out: |
661 | if (buf != map_buf) { | ||
662 | memcpy(map_buf, buf, cmd->data_length); | ||
663 | kfree(buf); | ||
664 | } | ||
665 | transport_kunmap_data_sg(cmd); | ||
666 | |||
745 | if (!ret) { | 667 | if (!ret) { |
746 | task->task_scsi_status = GOOD; | 668 | task->task_scsi_status = GOOD; |
747 | transport_complete_task(task, 1); | 669 | transport_complete_task(task, 1); |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index bbcf803e0916..99d7373ef834 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -118,9 +118,9 @@ | |||
118 | /* Queue Algorithm Modifier default for restricted reordering in control mode page */ | 118 | /* Queue Algorithm Modifier default for restricted reordering in control mode page */ |
119 | #define DA_EMULATE_REST_REORD 0 | 119 | #define DA_EMULATE_REST_REORD 0 |
120 | 120 | ||
121 | #define SE_INQUIRY_BUF 512 | ||
121 | #define SE_MODE_PAGE_BUF 512 | 122 | #define SE_MODE_PAGE_BUF 512 |
122 | 123 | ||
123 | |||
124 | /* struct se_hba->hba_flags */ | 124 | /* struct se_hba->hba_flags */ |
125 | enum hba_flags_table { | 125 | enum hba_flags_table { |
126 | HBA_FLAGS_INTERNAL_USE = 0x01, | 126 | HBA_FLAGS_INTERNAL_USE = 0x01, |