11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 288455ec4SChristoph Hellwig /* 388455ec4SChristoph Hellwig * SCSI Primary Commands (SPC) parsing and emulation. 488455ec4SChristoph Hellwig * 54c76251eSNicholas Bellinger * (c) Copyright 2002-2013 Datera, Inc. 688455ec4SChristoph Hellwig * 788455ec4SChristoph Hellwig * Nicholas A. Bellinger <nab@kernel.org> 888455ec4SChristoph Hellwig */ 988455ec4SChristoph Hellwig 1088455ec4SChristoph Hellwig #include <linux/kernel.h> 1188455ec4SChristoph Hellwig #include <linux/module.h> 1288455ec4SChristoph Hellwig #include <asm/unaligned.h> 1388455ec4SChristoph Hellwig 14ba929992SBart Van Assche #include <scsi/scsi_proto.h> 15ba929992SBart Van Assche #include <scsi/scsi_common.h> 1688455ec4SChristoph Hellwig #include <scsi/scsi_tcq.h> 1788455ec4SChristoph Hellwig 1888455ec4SChristoph Hellwig #include <target/target_core_base.h> 1988455ec4SChristoph Hellwig #include <target/target_core_backend.h> 2088455ec4SChristoph Hellwig #include <target/target_core_fabric.h> 2188455ec4SChristoph Hellwig 2288455ec4SChristoph Hellwig #include "target_core_internal.h" 23eba2ca45SNicholas Bellinger #include "target_core_alua.h" 2488455ec4SChristoph Hellwig #include "target_core_pr.h" 2588455ec4SChristoph Hellwig #include "target_core_ua.h" 2604b1b795SNicholas Bellinger #include "target_core_xcopy.h" 2788455ec4SChristoph Hellwig 28adf653f9SChristoph Hellwig static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf) 291fd032eeSChristoph Hellwig { 301fd032eeSChristoph Hellwig struct t10_alua_tg_pt_gp *tg_pt_gp; 311fd032eeSChristoph Hellwig 321fd032eeSChristoph Hellwig /* 331fd032eeSChristoph Hellwig * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. 341fd032eeSChristoph Hellwig */ 351fd032eeSChristoph Hellwig buf[5] = 0x80; 361fd032eeSChristoph Hellwig 371fd032eeSChristoph Hellwig /* 38125d0119SHannes Reinecke * Set TPGS field for explicit and/or implicit ALUA access type 391fd032eeSChristoph Hellwig * and opteration. 401fd032eeSChristoph Hellwig * 411fd032eeSChristoph Hellwig * See spc4r17 section 6.4.2 Table 135 421fd032eeSChristoph Hellwig */ 43e2a49a95SMike Christie rcu_read_lock(); 44e2a49a95SMike Christie tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp); 451fd032eeSChristoph Hellwig if (tg_pt_gp) 461fd032eeSChristoph Hellwig buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; 47e2a49a95SMike Christie rcu_read_unlock(); 481fd032eeSChristoph Hellwig } 491fd032eeSChristoph Hellwig 50b790a56dSKonstantin Shelekhin static u16 51b790a56dSKonstantin Shelekhin spc_find_scsi_transport_vd(int proto_id) 52b790a56dSKonstantin Shelekhin { 53b790a56dSKonstantin Shelekhin switch (proto_id) { 54b790a56dSKonstantin Shelekhin case SCSI_PROTOCOL_FCP: 55b790a56dSKonstantin Shelekhin return SCSI_VERSION_DESCRIPTOR_FCP4; 56b790a56dSKonstantin Shelekhin case SCSI_PROTOCOL_ISCSI: 57b790a56dSKonstantin Shelekhin return SCSI_VERSION_DESCRIPTOR_ISCSI; 58b790a56dSKonstantin Shelekhin case SCSI_PROTOCOL_SAS: 59b790a56dSKonstantin Shelekhin return SCSI_VERSION_DESCRIPTOR_SAS3; 60b790a56dSKonstantin Shelekhin case SCSI_PROTOCOL_SBP: 61b790a56dSKonstantin Shelekhin return SCSI_VERSION_DESCRIPTOR_SBP3; 62b790a56dSKonstantin Shelekhin case SCSI_PROTOCOL_SRP: 63b790a56dSKonstantin Shelekhin return SCSI_VERSION_DESCRIPTOR_SRP; 64b790a56dSKonstantin Shelekhin default: 65b790a56dSKonstantin Shelekhin pr_warn("Cannot find VERSION DESCRIPTOR value for unknown SCSI" 66b790a56dSKonstantin Shelekhin " transport PROTOCOL IDENTIFIER %#x\n", proto_id); 67b790a56dSKonstantin Shelekhin return 0; 68b790a56dSKonstantin Shelekhin } 69b790a56dSKonstantin Shelekhin } 70b790a56dSKonstantin Shelekhin 710dfa1c5dSHannes Reinecke sense_reason_t 720dfa1c5dSHannes Reinecke spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf) 731fd032eeSChristoph Hellwig { 741fd032eeSChristoph Hellwig struct se_lun *lun = cmd->se_lun; 75b790a56dSKonstantin Shelekhin struct se_portal_group *tpg = lun->lun_tpg; 761fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 77d2c5304cSNicholas Bellinger struct se_session *sess = cmd->se_sess; 781fd032eeSChristoph Hellwig 791fd032eeSChristoph Hellwig /* Set RMB (removable media) for tape devices */ 801fd032eeSChristoph Hellwig if (dev->transport->get_device_type(dev) == TYPE_TAPE) 811fd032eeSChristoph Hellwig buf[1] = 0x80; 821fd032eeSChristoph Hellwig 8364ae33efSKonstantin Shelekhin buf[2] = 0x06; /* SPC-4 */ 841fd032eeSChristoph Hellwig 851fd032eeSChristoph Hellwig /* 861fd032eeSChristoph Hellwig * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 871fd032eeSChristoph Hellwig * 881fd032eeSChristoph Hellwig * SPC4 says: 891fd032eeSChristoph Hellwig * A RESPONSE DATA FORMAT field set to 2h indicates that the 901fd032eeSChristoph Hellwig * standard INQUIRY data is in the format defined in this 911fd032eeSChristoph Hellwig * standard. Response data format values less than 2h are 921fd032eeSChristoph Hellwig * obsolete. Response data format values greater than 2h are 931fd032eeSChristoph Hellwig * reserved. 941fd032eeSChristoph Hellwig */ 951fd032eeSChristoph Hellwig buf[3] = 2; 961fd032eeSChristoph Hellwig 971fd032eeSChristoph Hellwig /* 981fd032eeSChristoph Hellwig * Enable SCCS and TPGS fields for Emulated ALUA 991fd032eeSChristoph Hellwig */ 100adf653f9SChristoph Hellwig spc_fill_alua_data(lun, buf); 1011fd032eeSChristoph Hellwig 102d397a445SNicholas Bellinger /* 103d397a445SNicholas Bellinger * Set Third-Party Copy (3PC) bit to indicate support for EXTENDED_COPY 104d397a445SNicholas Bellinger */ 105d397a445SNicholas Bellinger if (dev->dev_attrib.emulate_3pc) 106d397a445SNicholas Bellinger buf[5] |= 0x8; 107bdbad2bdSNicholas Bellinger /* 108d2c5304cSNicholas Bellinger * Set Protection (PROTECT) bit when DIF has been enabled on the 1099ef5466eSNicholas Bellinger * device, and the fabric supports VERIFY + PASS. Also report 1109ef5466eSNicholas Bellinger * PROTECT=1 if sess_prot_type has been configured to allow T10-PI 1119ef5466eSNicholas Bellinger * to unprotected devices. 112bdbad2bdSNicholas Bellinger */ 113d2c5304cSNicholas Bellinger if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) { 1149ef5466eSNicholas Bellinger if (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type) 115bdbad2bdSNicholas Bellinger buf[5] |= 0x1; 116d2c5304cSNicholas Bellinger } 117d397a445SNicholas Bellinger 1185bdd4a8eSDmitry Bogdanov /* 1195bdd4a8eSDmitry Bogdanov * Set MULTIP bit to indicate presence of multiple SCSI target ports 1205bdd4a8eSDmitry Bogdanov */ 1215bdd4a8eSDmitry Bogdanov if (dev->export_count > 1) 1225bdd4a8eSDmitry Bogdanov buf[6] |= 0x10; 1235bdd4a8eSDmitry Bogdanov 1241fd032eeSChristoph Hellwig buf[7] = 0x2; /* CmdQue=1 */ 1251fd032eeSChristoph Hellwig 1260de26357SDavid Disseldorp /* 1270de26357SDavid Disseldorp * ASCII data fields described as being left-aligned shall have any 1280de26357SDavid Disseldorp * unused bytes at the end of the field (i.e., highest offset) and the 1290de26357SDavid Disseldorp * unused bytes shall be filled with ASCII space characters (20h). 1300de26357SDavid Disseldorp */ 131b2da4abfSDavid Disseldorp memset(&buf[8], 0x20, 132b2da4abfSDavid Disseldorp INQUIRY_VENDOR_LEN + INQUIRY_MODEL_LEN + INQUIRY_REVISION_LEN); 1332d882847SDavid Disseldorp memcpy(&buf[8], dev->t10_wwn.vendor, 1342d882847SDavid Disseldorp strnlen(dev->t10_wwn.vendor, INQUIRY_VENDOR_LEN)); 135ee60bddbSNicholas Bellinger memcpy(&buf[16], dev->t10_wwn.model, 136b2da4abfSDavid Disseldorp strnlen(dev->t10_wwn.model, INQUIRY_MODEL_LEN)); 137ee60bddbSNicholas Bellinger memcpy(&buf[32], dev->t10_wwn.revision, 138b2da4abfSDavid Disseldorp strnlen(dev->t10_wwn.revision, INQUIRY_REVISION_LEN)); 139b790a56dSKonstantin Shelekhin 140b790a56dSKonstantin Shelekhin /* 141b790a56dSKonstantin Shelekhin * Set the VERSION DESCRIPTOR fields 142b790a56dSKonstantin Shelekhin */ 143b790a56dSKonstantin Shelekhin put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SAM5, &buf[58]); 144b790a56dSKonstantin Shelekhin put_unaligned_be16(spc_find_scsi_transport_vd(tpg->proto_id), &buf[60]); 145b790a56dSKonstantin Shelekhin put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SPC4, &buf[62]); 146b790a56dSKonstantin Shelekhin if (cmd->se_dev->transport->get_device_type(dev) == TYPE_DISK) 147b790a56dSKonstantin Shelekhin put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SBC3, &buf[64]); 148b790a56dSKonstantin Shelekhin 149b790a56dSKonstantin Shelekhin buf[4] = 91; /* Set additional length to 91 */ 1501fd032eeSChristoph Hellwig 1511fd032eeSChristoph Hellwig return 0; 1521fd032eeSChristoph Hellwig } 1530dfa1c5dSHannes Reinecke EXPORT_SYMBOL(spc_emulate_inquiry_std); 1541fd032eeSChristoph Hellwig 1551fd032eeSChristoph Hellwig /* unit serial number */ 156de103c93SChristoph Hellwig static sense_reason_t 157de103c93SChristoph Hellwig spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) 1581fd032eeSChristoph Hellwig { 1591fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 1609aff64e1SChristophe Vu-Brugier u16 len; 1611fd032eeSChristoph Hellwig 1620fd97ccfSChristoph Hellwig if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { 1639aff64e1SChristophe Vu-Brugier len = sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); 1641fd032eeSChristoph Hellwig len++; /* Extra Byte for NULL Terminator */ 1651fd032eeSChristoph Hellwig buf[3] = len; 1661fd032eeSChristoph Hellwig } 1671fd032eeSChristoph Hellwig return 0; 1681fd032eeSChristoph Hellwig } 1691fd032eeSChristoph Hellwig 17017f947b8SSergey Samoylenko /* 17117f947b8SSergey Samoylenko * Generate NAA IEEE Registered Extended designator 17217f947b8SSergey Samoylenko */ 17317f947b8SSergey Samoylenko void spc_gen_naa_6h_vendor_specific(struct se_device *dev, 1741fd032eeSChristoph Hellwig unsigned char *buf) 1751fd032eeSChristoph Hellwig { 1760fd97ccfSChristoph Hellwig unsigned char *p = &dev->t10_wwn.unit_serial[0]; 1772469f1e0SSergey Samoylenko u32 company_id = dev->t10_wwn.company_id; 17817f947b8SSergey Samoylenko int cnt, off = 0; 1791fd032eeSChristoph Hellwig bool next = true; 1801fd032eeSChristoph Hellwig 1811fd032eeSChristoph Hellwig /* 18217f947b8SSergey Samoylenko * Start NAA IEEE Registered Extended Identifier/Designator 18317f947b8SSergey Samoylenko */ 1842469f1e0SSergey Samoylenko buf[off] = 0x6 << 4; 18517f947b8SSergey Samoylenko 1862469f1e0SSergey Samoylenko /* IEEE COMPANY_ID */ 1872469f1e0SSergey Samoylenko buf[off++] |= (company_id >> 20) & 0xf; 1882469f1e0SSergey Samoylenko buf[off++] = (company_id >> 12) & 0xff; 1892469f1e0SSergey Samoylenko buf[off++] = (company_id >> 4) & 0xff; 1902469f1e0SSergey Samoylenko buf[off] = (company_id & 0xf) << 4; 19117f947b8SSergey Samoylenko 19217f947b8SSergey Samoylenko /* 1931fd032eeSChristoph Hellwig * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on 1941fd032eeSChristoph Hellwig * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field 1951fd032eeSChristoph Hellwig * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION 1961fd032eeSChristoph Hellwig * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL 1971fd032eeSChristoph Hellwig * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure 1981fd032eeSChristoph Hellwig * per device uniqeness. 1991fd032eeSChristoph Hellwig */ 20017f947b8SSergey Samoylenko for (cnt = off + 13; *p && off < cnt; p++) { 2011fd032eeSChristoph Hellwig int val = hex_to_bin(*p); 2021fd032eeSChristoph Hellwig 2031fd032eeSChristoph Hellwig if (val < 0) 2041fd032eeSChristoph Hellwig continue; 2051fd032eeSChristoph Hellwig 2061fd032eeSChristoph Hellwig if (next) { 2071fd032eeSChristoph Hellwig next = false; 20817f947b8SSergey Samoylenko buf[off++] |= val; 2091fd032eeSChristoph Hellwig } else { 2101fd032eeSChristoph Hellwig next = true; 21117f947b8SSergey Samoylenko buf[off] = val << 4; 2121fd032eeSChristoph Hellwig } 2131fd032eeSChristoph Hellwig } 2141fd032eeSChristoph Hellwig } 2151fd032eeSChristoph Hellwig 2161fd032eeSChristoph Hellwig /* 2171fd032eeSChristoph Hellwig * Device identification VPD, for a complete list of 2181fd032eeSChristoph Hellwig * DESIGNATOR TYPEs see spc4r17 Table 459. 2191fd032eeSChristoph Hellwig */ 2200dfa1c5dSHannes Reinecke sense_reason_t 221de103c93SChristoph Hellwig spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) 2221fd032eeSChristoph Hellwig { 2231fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 2241fd032eeSChristoph Hellwig struct se_lun *lun = cmd->se_lun; 2251fd032eeSChristoph Hellwig struct se_portal_group *tpg = NULL; 2261fd032eeSChristoph Hellwig struct t10_alua_lu_gp_member *lu_gp_mem; 2271fd032eeSChristoph Hellwig struct t10_alua_tg_pt_gp *tg_pt_gp; 2280fd97ccfSChristoph Hellwig unsigned char *prod = &dev->t10_wwn.model[0]; 2291fd032eeSChristoph Hellwig u32 prod_len; 230bc811318SColin Ian King u32 off = 0; 2311fd032eeSChristoph Hellwig u16 len = 0, id_len; 2321fd032eeSChristoph Hellwig 2331fd032eeSChristoph Hellwig off = 4; 2341fd032eeSChristoph Hellwig 2351fd032eeSChristoph Hellwig /* 2361fd032eeSChristoph Hellwig * NAA IEEE Registered Extended Assigned designator format, see 2371fd032eeSChristoph Hellwig * spc4r17 section 7.7.3.6.5 2381fd032eeSChristoph Hellwig * 2391fd032eeSChristoph Hellwig * We depend upon a target_core_mod/ConfigFS provided 2401fd032eeSChristoph Hellwig * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial 2411fd032eeSChristoph Hellwig * value in order to return the NAA id. 2421fd032eeSChristoph Hellwig */ 2430fd97ccfSChristoph Hellwig if (!(dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL)) 2441fd032eeSChristoph Hellwig goto check_t10_vend_desc; 2451fd032eeSChristoph Hellwig 2461fd032eeSChristoph Hellwig /* CODE SET == Binary */ 2471fd032eeSChristoph Hellwig buf[off++] = 0x1; 2481fd032eeSChristoph Hellwig 2491fd032eeSChristoph Hellwig /* Set ASSOCIATION == addressed logical unit: 0)b */ 2501fd032eeSChristoph Hellwig buf[off] = 0x00; 2511fd032eeSChristoph Hellwig 2521fd032eeSChristoph Hellwig /* Identifier/Designator type == NAA identifier */ 2531fd032eeSChristoph Hellwig buf[off++] |= 0x3; 2541fd032eeSChristoph Hellwig off++; 2551fd032eeSChristoph Hellwig 2561fd032eeSChristoph Hellwig /* Identifier/Designator length */ 2571fd032eeSChristoph Hellwig buf[off++] = 0x10; 2581fd032eeSChristoph Hellwig 25917f947b8SSergey Samoylenko /* NAA IEEE Registered Extended designator */ 26017f947b8SSergey Samoylenko spc_gen_naa_6h_vendor_specific(dev, &buf[off]); 2611fd032eeSChristoph Hellwig 2621fd032eeSChristoph Hellwig len = 20; 2631fd032eeSChristoph Hellwig off = (len + 4); 2641fd032eeSChristoph Hellwig 2651fd032eeSChristoph Hellwig check_t10_vend_desc: 2661fd032eeSChristoph Hellwig /* 2671fd032eeSChristoph Hellwig * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4 2681fd032eeSChristoph Hellwig */ 2691fd032eeSChristoph Hellwig id_len = 8; /* For Vendor field */ 2701fd032eeSChristoph Hellwig prod_len = 4; /* For VPD Header */ 2711fd032eeSChristoph Hellwig prod_len += 8; /* For Vendor field */ 2721fd032eeSChristoph Hellwig prod_len += strlen(prod); 2731fd032eeSChristoph Hellwig prod_len++; /* For : */ 2741fd032eeSChristoph Hellwig 275bc811318SColin Ian King if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) 2761fd032eeSChristoph Hellwig id_len += sprintf(&buf[off+12], "%s:%s", prod, 2770fd97ccfSChristoph Hellwig &dev->t10_wwn.unit_serial[0]); 2781fd032eeSChristoph Hellwig buf[off] = 0x2; /* ASCII */ 2791fd032eeSChristoph Hellwig buf[off+1] = 0x1; /* T10 Vendor ID */ 2801fd032eeSChristoph Hellwig buf[off+2] = 0x0; 2810de26357SDavid Disseldorp /* left align Vendor ID and pad with spaces */ 2822d882847SDavid Disseldorp memset(&buf[off+4], 0x20, INQUIRY_VENDOR_LEN); 2832d882847SDavid Disseldorp memcpy(&buf[off+4], dev->t10_wwn.vendor, 2842d882847SDavid Disseldorp strnlen(dev->t10_wwn.vendor, INQUIRY_VENDOR_LEN)); 2851fd032eeSChristoph Hellwig /* Extra Byte for NULL Terminator */ 2861fd032eeSChristoph Hellwig id_len++; 2871fd032eeSChristoph Hellwig /* Identifier Length */ 2881fd032eeSChristoph Hellwig buf[off+3] = id_len; 2891fd032eeSChristoph Hellwig /* Header size for Designation descriptor */ 2901fd032eeSChristoph Hellwig len += (id_len + 4); 2911fd032eeSChristoph Hellwig off += (id_len + 4); 292adf653f9SChristoph Hellwig 293adf653f9SChristoph Hellwig if (1) { 2941fd032eeSChristoph Hellwig struct t10_alua_lu_gp *lu_gp; 295fbfe858fSHannes Reinecke u32 padding, scsi_name_len, scsi_target_len; 2961fd032eeSChristoph Hellwig u16 lu_gp_id = 0; 2971fd032eeSChristoph Hellwig u16 tg_pt_gp_id = 0; 2981fd032eeSChristoph Hellwig u16 tpgt; 2991fd032eeSChristoph Hellwig 300adf653f9SChristoph Hellwig tpg = lun->lun_tpg; 3011fd032eeSChristoph Hellwig /* 3021fd032eeSChristoph Hellwig * Relative target port identifer, see spc4r17 3031fd032eeSChristoph Hellwig * section 7.7.3.7 3041fd032eeSChristoph Hellwig * 3051fd032eeSChristoph Hellwig * Get the PROTOCOL IDENTIFIER as defined by spc4r17 3061fd032eeSChristoph Hellwig * section 7.5.1 Table 362 3071fd032eeSChristoph Hellwig */ 3082aeeafaeSChristoph Hellwig buf[off] = tpg->proto_id << 4; 3091fd032eeSChristoph Hellwig buf[off++] |= 0x1; /* CODE SET == Binary */ 3101fd032eeSChristoph Hellwig buf[off] = 0x80; /* Set PIV=1 */ 3111fd032eeSChristoph Hellwig /* Set ASSOCIATION == target port: 01b */ 3121fd032eeSChristoph Hellwig buf[off] |= 0x10; 3131fd032eeSChristoph Hellwig /* DESIGNATOR TYPE == Relative target port identifer */ 3141fd032eeSChristoph Hellwig buf[off++] |= 0x4; 3151fd032eeSChristoph Hellwig off++; /* Skip over Reserved */ 3161fd032eeSChristoph Hellwig buf[off++] = 4; /* DESIGNATOR LENGTH */ 3171fd032eeSChristoph Hellwig /* Skip over Obsolete field in RTPI payload 3181fd032eeSChristoph Hellwig * in Table 472 */ 3191fd032eeSChristoph Hellwig off += 2; 320a85d667eSBart Van Assche put_unaligned_be16(lun->lun_rtpi, &buf[off]); 321a85d667eSBart Van Assche off += 2; 3221fd032eeSChristoph Hellwig len += 8; /* Header size + Designation descriptor */ 3231fd032eeSChristoph Hellwig /* 3241fd032eeSChristoph Hellwig * Target port group identifier, see spc4r17 3251fd032eeSChristoph Hellwig * section 7.7.3.8 3261fd032eeSChristoph Hellwig * 3271fd032eeSChristoph Hellwig * Get the PROTOCOL IDENTIFIER as defined by spc4r17 3281fd032eeSChristoph Hellwig * section 7.5.1 Table 362 3291fd032eeSChristoph Hellwig */ 330e2a49a95SMike Christie rcu_read_lock(); 331e2a49a95SMike Christie tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp); 3321fd032eeSChristoph Hellwig if (!tg_pt_gp) { 333e2a49a95SMike Christie rcu_read_unlock(); 3341fd032eeSChristoph Hellwig goto check_lu_gp; 3351fd032eeSChristoph Hellwig } 3361fd032eeSChristoph Hellwig tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; 337e2a49a95SMike Christie rcu_read_unlock(); 3381fd032eeSChristoph Hellwig 3392aeeafaeSChristoph Hellwig buf[off] = tpg->proto_id << 4; 3401fd032eeSChristoph Hellwig buf[off++] |= 0x1; /* CODE SET == Binary */ 3411fd032eeSChristoph Hellwig buf[off] = 0x80; /* Set PIV=1 */ 3421fd032eeSChristoph Hellwig /* Set ASSOCIATION == target port: 01b */ 3431fd032eeSChristoph Hellwig buf[off] |= 0x10; 3441fd032eeSChristoph Hellwig /* DESIGNATOR TYPE == Target port group identifier */ 3451fd032eeSChristoph Hellwig buf[off++] |= 0x5; 3461fd032eeSChristoph Hellwig off++; /* Skip over Reserved */ 3471fd032eeSChristoph Hellwig buf[off++] = 4; /* DESIGNATOR LENGTH */ 3481fd032eeSChristoph Hellwig off += 2; /* Skip over Reserved Field */ 349a85d667eSBart Van Assche put_unaligned_be16(tg_pt_gp_id, &buf[off]); 350a85d667eSBart Van Assche off += 2; 3511fd032eeSChristoph Hellwig len += 8; /* Header size + Designation descriptor */ 3521fd032eeSChristoph Hellwig /* 3531fd032eeSChristoph Hellwig * Logical Unit Group identifier, see spc4r17 3541fd032eeSChristoph Hellwig * section 7.7.3.8 3551fd032eeSChristoph Hellwig */ 3561fd032eeSChristoph Hellwig check_lu_gp: 3571fd032eeSChristoph Hellwig lu_gp_mem = dev->dev_alua_lu_gp_mem; 3581fd032eeSChristoph Hellwig if (!lu_gp_mem) 3591fd032eeSChristoph Hellwig goto check_scsi_name; 3601fd032eeSChristoph Hellwig 3611fd032eeSChristoph Hellwig spin_lock(&lu_gp_mem->lu_gp_mem_lock); 3621fd032eeSChristoph Hellwig lu_gp = lu_gp_mem->lu_gp; 3631fd032eeSChristoph Hellwig if (!lu_gp) { 3641fd032eeSChristoph Hellwig spin_unlock(&lu_gp_mem->lu_gp_mem_lock); 3651fd032eeSChristoph Hellwig goto check_scsi_name; 3661fd032eeSChristoph Hellwig } 3671fd032eeSChristoph Hellwig lu_gp_id = lu_gp->lu_gp_id; 3681fd032eeSChristoph Hellwig spin_unlock(&lu_gp_mem->lu_gp_mem_lock); 3691fd032eeSChristoph Hellwig 3701fd032eeSChristoph Hellwig buf[off++] |= 0x1; /* CODE SET == Binary */ 3711fd032eeSChristoph Hellwig /* DESIGNATOR TYPE == Logical Unit Group identifier */ 3721fd032eeSChristoph Hellwig buf[off++] |= 0x6; 3731fd032eeSChristoph Hellwig off++; /* Skip over Reserved */ 3741fd032eeSChristoph Hellwig buf[off++] = 4; /* DESIGNATOR LENGTH */ 3751fd032eeSChristoph Hellwig off += 2; /* Skip over Reserved Field */ 376a85d667eSBart Van Assche put_unaligned_be16(lu_gp_id, &buf[off]); 377a85d667eSBart Van Assche off += 2; 3781fd032eeSChristoph Hellwig len += 8; /* Header size + Designation descriptor */ 3791fd032eeSChristoph Hellwig /* 3801fd032eeSChristoph Hellwig * SCSI name string designator, see spc4r17 3811fd032eeSChristoph Hellwig * section 7.7.3.11 3821fd032eeSChristoph Hellwig * 3831fd032eeSChristoph Hellwig * Get the PROTOCOL IDENTIFIER as defined by spc4r17 3841fd032eeSChristoph Hellwig * section 7.5.1 Table 362 3851fd032eeSChristoph Hellwig */ 3861fd032eeSChristoph Hellwig check_scsi_name: 3872aeeafaeSChristoph Hellwig buf[off] = tpg->proto_id << 4; 3881fd032eeSChristoph Hellwig buf[off++] |= 0x3; /* CODE SET == UTF-8 */ 3891fd032eeSChristoph Hellwig buf[off] = 0x80; /* Set PIV=1 */ 3901fd032eeSChristoph Hellwig /* Set ASSOCIATION == target port: 01b */ 3911fd032eeSChristoph Hellwig buf[off] |= 0x10; 3921fd032eeSChristoph Hellwig /* DESIGNATOR TYPE == SCSI name string */ 3931fd032eeSChristoph Hellwig buf[off++] |= 0x8; 3941fd032eeSChristoph Hellwig off += 2; /* Skip over Reserved and length */ 3951fd032eeSChristoph Hellwig /* 3961fd032eeSChristoph Hellwig * SCSI name string identifer containing, $FABRIC_MOD 3971fd032eeSChristoph Hellwig * dependent information. For LIO-Target and iSCSI 3981fd032eeSChristoph Hellwig * Target Port, this means "<iSCSI name>,t,0x<TPGT> in 3991fd032eeSChristoph Hellwig * UTF-8 encoding. 4001fd032eeSChristoph Hellwig */ 4011fd032eeSChristoph Hellwig tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); 4021fd032eeSChristoph Hellwig scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x", 4031fd032eeSChristoph Hellwig tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt); 4041fd032eeSChristoph Hellwig scsi_name_len += 1 /* Include NULL terminator */; 4051fd032eeSChristoph Hellwig /* 4061fd032eeSChristoph Hellwig * The null-terminated, null-padded (see 4.4.2) SCSI 4071fd032eeSChristoph Hellwig * NAME STRING field contains a UTF-8 format string. 4081fd032eeSChristoph Hellwig * The number of bytes in the SCSI NAME STRING field 4091fd032eeSChristoph Hellwig * (i.e., the value in the DESIGNATOR LENGTH field) 4101fd032eeSChristoph Hellwig * shall be no larger than 256 and shall be a multiple 4111fd032eeSChristoph Hellwig * of four. 4121fd032eeSChristoph Hellwig */ 41303ba84caSHannes Reinecke padding = ((-scsi_name_len) & 3); 4141fd032eeSChristoph Hellwig if (padding) 4151fd032eeSChristoph Hellwig scsi_name_len += padding; 41603ba84caSHannes Reinecke if (scsi_name_len > 256) 41703ba84caSHannes Reinecke scsi_name_len = 256; 4181fd032eeSChristoph Hellwig 4191fd032eeSChristoph Hellwig buf[off-1] = scsi_name_len; 4201fd032eeSChristoph Hellwig off += scsi_name_len; 4211fd032eeSChristoph Hellwig /* Header size + Designation descriptor */ 4221fd032eeSChristoph Hellwig len += (scsi_name_len + 4); 423fbfe858fSHannes Reinecke 424fbfe858fSHannes Reinecke /* 425fbfe858fSHannes Reinecke * Target device designator 426fbfe858fSHannes Reinecke */ 4272aeeafaeSChristoph Hellwig buf[off] = tpg->proto_id << 4; 428fbfe858fSHannes Reinecke buf[off++] |= 0x3; /* CODE SET == UTF-8 */ 429fbfe858fSHannes Reinecke buf[off] = 0x80; /* Set PIV=1 */ 430fbfe858fSHannes Reinecke /* Set ASSOCIATION == target device: 10b */ 431fbfe858fSHannes Reinecke buf[off] |= 0x20; 432fbfe858fSHannes Reinecke /* DESIGNATOR TYPE == SCSI name string */ 433fbfe858fSHannes Reinecke buf[off++] |= 0x8; 434fbfe858fSHannes Reinecke off += 2; /* Skip over Reserved and length */ 435fbfe858fSHannes Reinecke /* 436fbfe858fSHannes Reinecke * SCSI name string identifer containing, $FABRIC_MOD 437fbfe858fSHannes Reinecke * dependent information. For LIO-Target and iSCSI 438fbfe858fSHannes Reinecke * Target Port, this means "<iSCSI name>" in 439fbfe858fSHannes Reinecke * UTF-8 encoding. 440fbfe858fSHannes Reinecke */ 441fbfe858fSHannes Reinecke scsi_target_len = sprintf(&buf[off], "%s", 442fbfe858fSHannes Reinecke tpg->se_tpg_tfo->tpg_get_wwn(tpg)); 443fbfe858fSHannes Reinecke scsi_target_len += 1 /* Include NULL terminator */; 444fbfe858fSHannes Reinecke /* 445fbfe858fSHannes Reinecke * The null-terminated, null-padded (see 4.4.2) SCSI 446fbfe858fSHannes Reinecke * NAME STRING field contains a UTF-8 format string. 447fbfe858fSHannes Reinecke * The number of bytes in the SCSI NAME STRING field 448fbfe858fSHannes Reinecke * (i.e., the value in the DESIGNATOR LENGTH field) 449fbfe858fSHannes Reinecke * shall be no larger than 256 and shall be a multiple 450fbfe858fSHannes Reinecke * of four. 451fbfe858fSHannes Reinecke */ 452fbfe858fSHannes Reinecke padding = ((-scsi_target_len) & 3); 453fbfe858fSHannes Reinecke if (padding) 454fbfe858fSHannes Reinecke scsi_target_len += padding; 4556a16d7beSRoland Dreier if (scsi_target_len > 256) 4566a16d7beSRoland Dreier scsi_target_len = 256; 457fbfe858fSHannes Reinecke 458fbfe858fSHannes Reinecke buf[off-1] = scsi_target_len; 459fbfe858fSHannes Reinecke off += scsi_target_len; 460fbfe858fSHannes Reinecke 461fbfe858fSHannes Reinecke /* Header size + Designation descriptor */ 462fbfe858fSHannes Reinecke len += (scsi_target_len + 4); 4631fd032eeSChristoph Hellwig } 464a85d667eSBart Van Assche put_unaligned_be16(len, &buf[2]); /* Page Length for VPD 0x83 */ 4651fd032eeSChristoph Hellwig return 0; 4661fd032eeSChristoph Hellwig } 4670dfa1c5dSHannes Reinecke EXPORT_SYMBOL(spc_emulate_evpd_83); 4681fd032eeSChristoph Hellwig 4691fd032eeSChristoph Hellwig /* Extended INQUIRY Data VPD Page */ 470de103c93SChristoph Hellwig static sense_reason_t 471de103c93SChristoph Hellwig spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) 4721fd032eeSChristoph Hellwig { 473d0c8b259SNicholas Bellinger struct se_device *dev = cmd->se_dev; 474d2c5304cSNicholas Bellinger struct se_session *sess = cmd->se_sess; 475d0c8b259SNicholas Bellinger 4761fd032eeSChristoph Hellwig buf[3] = 0x3c; 47743bb95c7SNicholas Bellinger /* 47843bb95c7SNicholas Bellinger * Set GRD_CHK + REF_CHK for TYPE1 protection, or GRD_CHK 47943bb95c7SNicholas Bellinger * only for TYPE3 protection. 48043bb95c7SNicholas Bellinger */ 481d2c5304cSNicholas Bellinger if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) { 4829ef5466eSNicholas Bellinger if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT || 4839ef5466eSNicholas Bellinger cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT) 48443bb95c7SNicholas Bellinger buf[4] = 0x5; 4859ef5466eSNicholas Bellinger else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT || 4869ef5466eSNicholas Bellinger cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT) 48743bb95c7SNicholas Bellinger buf[4] = 0x4; 488d2c5304cSNicholas Bellinger } 48943bb95c7SNicholas Bellinger 49027e6772bSSagi Grimberg /* logical unit supports type 1 and type 3 protection */ 4913aa3c67bSNicholas Bellinger if ((dev->transport->get_device_type(dev) == TYPE_DISK) && 4923aa3c67bSNicholas Bellinger (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) && 4933aa3c67bSNicholas Bellinger (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)) { 49427e6772bSSagi Grimberg buf[4] |= (0x3 << 3); 4953aa3c67bSNicholas Bellinger } 49627e6772bSSagi Grimberg 4971fd032eeSChristoph Hellwig /* Set HEADSUP, ORDSUP, SIMPSUP */ 4981fd032eeSChristoph Hellwig buf[5] = 0x07; 4991fd032eeSChristoph Hellwig 5001fd032eeSChristoph Hellwig /* If WriteCache emulation is enabled, set V_SUP */ 501814e5b45SChristoph Hellwig if (target_check_wce(dev)) 5021fd032eeSChristoph Hellwig buf[6] = 0x01; 503c66094bfSHannes Reinecke /* If an LBA map is present set R_SUP */ 504c66094bfSHannes Reinecke spin_lock(&cmd->se_dev->t10_alua.lba_map_lock); 505c66094bfSHannes Reinecke if (!list_empty(&dev->t10_alua.lba_map_list)) 506c66094bfSHannes Reinecke buf[8] = 0x10; 507c66094bfSHannes Reinecke spin_unlock(&cmd->se_dev->t10_alua.lba_map_lock); 5081fd032eeSChristoph Hellwig return 0; 5091fd032eeSChristoph Hellwig } 5101fd032eeSChristoph Hellwig 5111fd032eeSChristoph Hellwig /* Block Limits VPD page */ 512de103c93SChristoph Hellwig static sense_reason_t 513de103c93SChristoph Hellwig spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) 5141fd032eeSChristoph Hellwig { 5151fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 5168f9b5654SNicholas Bellinger u32 mtl = 0; 5178f9b5654SNicholas Bellinger int have_tp = 0, opt, min; 5187870d248SAnastasia Kovaleva u32 io_max_blocks; 5191fd032eeSChristoph Hellwig 5201fd032eeSChristoph Hellwig /* 5211fd032eeSChristoph Hellwig * Following spc3r22 section 6.5.3 Block Limits VPD page, when 5221fd032eeSChristoph Hellwig * emulate_tpu=1 or emulate_tpws=1 we will be expect a 5231fd032eeSChristoph Hellwig * different page length for Thin Provisioning. 5241fd032eeSChristoph Hellwig */ 5250fd97ccfSChristoph Hellwig if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws) 5261fd032eeSChristoph Hellwig have_tp = 1; 5271fd032eeSChristoph Hellwig 5281fd032eeSChristoph Hellwig buf[0] = dev->transport->get_device_type(dev); 5291fd032eeSChristoph Hellwig buf[3] = have_tp ? 0x3c : 0x10; 5301fd032eeSChristoph Hellwig 5311fd032eeSChristoph Hellwig /* Set WSNZ to 1 */ 5321fd032eeSChristoph Hellwig buf[4] = 0x01; 5330123a9ecSNicholas Bellinger /* 5340123a9ecSNicholas Bellinger * Set MAXIMUM COMPARE AND WRITE LENGTH 5350123a9ecSNicholas Bellinger */ 5360123a9ecSNicholas Bellinger if (dev->dev_attrib.emulate_caw) 5370123a9ecSNicholas Bellinger buf[5] = 0x01; 5381fd032eeSChristoph Hellwig 5391fd032eeSChristoph Hellwig /* 5401fd032eeSChristoph Hellwig * Set OPTIMAL TRANSFER LENGTH GRANULARITY 5411fd032eeSChristoph Hellwig */ 5427f7caf6aSAndy Grover if (dev->transport->get_io_min && (min = dev->transport->get_io_min(dev))) 5437f7caf6aSAndy Grover put_unaligned_be16(min / dev->dev_attrib.block_size, &buf[6]); 5447f7caf6aSAndy Grover else 5451fd032eeSChristoph Hellwig put_unaligned_be16(1, &buf[6]); 5461fd032eeSChristoph Hellwig 5471fd032eeSChristoph Hellwig /* 5481fd032eeSChristoph Hellwig * Set MAXIMUM TRANSFER LENGTH 5498f9b5654SNicholas Bellinger * 5508f9b5654SNicholas Bellinger * XXX: Currently assumes single PAGE_SIZE per scatterlist for fabrics 5518f9b5654SNicholas Bellinger * enforcing maximum HW scatter-gather-list entry limit 5521fd032eeSChristoph Hellwig */ 5538f9b5654SNicholas Bellinger if (cmd->se_tfo->max_data_sg_nents) { 5548f9b5654SNicholas Bellinger mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE) / 5558f9b5654SNicholas Bellinger dev->dev_attrib.block_size; 5568f9b5654SNicholas Bellinger } 5577870d248SAnastasia Kovaleva io_max_blocks = mult_frac(dev->dev_attrib.hw_max_sectors, 5587870d248SAnastasia Kovaleva dev->dev_attrib.hw_block_size, 5597870d248SAnastasia Kovaleva dev->dev_attrib.block_size); 5607870d248SAnastasia Kovaleva put_unaligned_be32(min_not_zero(mtl, io_max_blocks), &buf[8]); 5611fd032eeSChristoph Hellwig 5621fd032eeSChristoph Hellwig /* 5631fd032eeSChristoph Hellwig * Set OPTIMAL TRANSFER LENGTH 5641fd032eeSChristoph Hellwig */ 5657f7caf6aSAndy Grover if (dev->transport->get_io_opt && (opt = dev->transport->get_io_opt(dev))) 5667f7caf6aSAndy Grover put_unaligned_be32(opt / dev->dev_attrib.block_size, &buf[12]); 5677f7caf6aSAndy Grover else 5680fd97ccfSChristoph Hellwig put_unaligned_be32(dev->dev_attrib.optimal_sectors, &buf[12]); 5691fd032eeSChristoph Hellwig 5701fd032eeSChristoph Hellwig /* 5711fd032eeSChristoph Hellwig * Exit now if we don't support TP. 5721fd032eeSChristoph Hellwig */ 5731fd032eeSChristoph Hellwig if (!have_tp) 574773cbaf7SNicholas Bellinger goto max_write_same; 5751fd032eeSChristoph Hellwig 5761fd032eeSChristoph Hellwig /* 5771fd032eeSChristoph Hellwig * Set MAXIMUM UNMAP LBA COUNT 5781fd032eeSChristoph Hellwig */ 5790fd97ccfSChristoph Hellwig put_unaligned_be32(dev->dev_attrib.max_unmap_lba_count, &buf[20]); 5801fd032eeSChristoph Hellwig 5811fd032eeSChristoph Hellwig /* 5821fd032eeSChristoph Hellwig * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT 5831fd032eeSChristoph Hellwig */ 5840fd97ccfSChristoph Hellwig put_unaligned_be32(dev->dev_attrib.max_unmap_block_desc_count, 5851fd032eeSChristoph Hellwig &buf[24]); 5861fd032eeSChristoph Hellwig 5871fd032eeSChristoph Hellwig /* 5881fd032eeSChristoph Hellwig * Set OPTIMAL UNMAP GRANULARITY 5891fd032eeSChristoph Hellwig */ 5900fd97ccfSChristoph Hellwig put_unaligned_be32(dev->dev_attrib.unmap_granularity, &buf[28]); 5911fd032eeSChristoph Hellwig 5921fd032eeSChristoph Hellwig /* 5931fd032eeSChristoph Hellwig * UNMAP GRANULARITY ALIGNMENT 5941fd032eeSChristoph Hellwig */ 5950fd97ccfSChristoph Hellwig put_unaligned_be32(dev->dev_attrib.unmap_granularity_alignment, 5961fd032eeSChristoph Hellwig &buf[32]); 5970fd97ccfSChristoph Hellwig if (dev->dev_attrib.unmap_granularity_alignment != 0) 5981fd032eeSChristoph Hellwig buf[32] |= 0x80; /* Set the UGAVALID bit */ 5991fd032eeSChristoph Hellwig 600773cbaf7SNicholas Bellinger /* 601773cbaf7SNicholas Bellinger * MAXIMUM WRITE SAME LENGTH 602773cbaf7SNicholas Bellinger */ 603773cbaf7SNicholas Bellinger max_write_same: 604773cbaf7SNicholas Bellinger put_unaligned_be64(dev->dev_attrib.max_write_same_len, &buf[36]); 605773cbaf7SNicholas Bellinger 6061fd032eeSChristoph Hellwig return 0; 6071fd032eeSChristoph Hellwig } 6081fd032eeSChristoph Hellwig 6091fd032eeSChristoph Hellwig /* Block Device Characteristics VPD page */ 610de103c93SChristoph Hellwig static sense_reason_t 611de103c93SChristoph Hellwig spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) 6121fd032eeSChristoph Hellwig { 6131fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 6141fd032eeSChristoph Hellwig 6151fd032eeSChristoph Hellwig buf[0] = dev->transport->get_device_type(dev); 6161fd032eeSChristoph Hellwig buf[3] = 0x3c; 6170fd97ccfSChristoph Hellwig buf[5] = dev->dev_attrib.is_nonrot ? 1 : 0; 6181fd032eeSChristoph Hellwig 6191fd032eeSChristoph Hellwig return 0; 6201fd032eeSChristoph Hellwig } 6211fd032eeSChristoph Hellwig 6221fd032eeSChristoph Hellwig /* Thin Provisioning VPD */ 623de103c93SChristoph Hellwig static sense_reason_t 624de103c93SChristoph Hellwig spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) 6251fd032eeSChristoph Hellwig { 6261fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 6271fd032eeSChristoph Hellwig 6281fd032eeSChristoph Hellwig /* 6291fd032eeSChristoph Hellwig * From spc3r22 section 6.5.4 Thin Provisioning VPD page: 6301fd032eeSChristoph Hellwig * 6311fd032eeSChristoph Hellwig * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to 6321fd032eeSChristoph Hellwig * zero, then the page length shall be set to 0004h. If the DP bit 6331fd032eeSChristoph Hellwig * is set to one, then the page length shall be set to the value 6341fd032eeSChristoph Hellwig * defined in table 162. 6351fd032eeSChristoph Hellwig */ 6361fd032eeSChristoph Hellwig buf[0] = dev->transport->get_device_type(dev); 6371fd032eeSChristoph Hellwig 6381fd032eeSChristoph Hellwig /* 6391fd032eeSChristoph Hellwig * Set Hardcoded length mentioned above for DP=0 6401fd032eeSChristoph Hellwig */ 6411fd032eeSChristoph Hellwig put_unaligned_be16(0x0004, &buf[2]); 6421fd032eeSChristoph Hellwig 6431fd032eeSChristoph Hellwig /* 6441fd032eeSChristoph Hellwig * The THRESHOLD EXPONENT field indicates the threshold set size in 6451fd032eeSChristoph Hellwig * LBAs as a power of 2 (i.e., the threshold set size is equal to 6461fd032eeSChristoph Hellwig * 2(threshold exponent)). 6471fd032eeSChristoph Hellwig * 6481fd032eeSChristoph Hellwig * Note that this is currently set to 0x00 as mkp says it will be 6491fd032eeSChristoph Hellwig * changing again. We can enable this once it has settled in T10 6501fd032eeSChristoph Hellwig * and is actually used by Linux/SCSI ML code. 6511fd032eeSChristoph Hellwig */ 6521fd032eeSChristoph Hellwig buf[4] = 0x00; 6531fd032eeSChristoph Hellwig 6541fd032eeSChristoph Hellwig /* 6551fd032eeSChristoph Hellwig * A TPU bit set to one indicates that the device server supports 6561fd032eeSChristoph Hellwig * the UNMAP command (see 5.25). A TPU bit set to zero indicates 6571fd032eeSChristoph Hellwig * that the device server does not support the UNMAP command. 6581fd032eeSChristoph Hellwig */ 6590fd97ccfSChristoph Hellwig if (dev->dev_attrib.emulate_tpu != 0) 6601fd032eeSChristoph Hellwig buf[5] = 0x80; 6611fd032eeSChristoph Hellwig 6621fd032eeSChristoph Hellwig /* 6631fd032eeSChristoph Hellwig * A TPWS bit set to one indicates that the device server supports 6641fd032eeSChristoph Hellwig * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs. 6651fd032eeSChristoph Hellwig * A TPWS bit set to zero indicates that the device server does not 6661fd032eeSChristoph Hellwig * support the use of the WRITE SAME (16) command to unmap LBAs. 6671fd032eeSChristoph Hellwig */ 6680fd97ccfSChristoph Hellwig if (dev->dev_attrib.emulate_tpws != 0) 669aa04dae4SNicholas Bellinger buf[5] |= 0x40 | 0x20; 6701fd032eeSChristoph Hellwig 671e6f41633SJamie Pocas /* 672e6f41633SJamie Pocas * The unmap_zeroes_data set means that the underlying device supports 6739305455aSBart Van Assche * REQ_OP_DISCARD and has the discard_zeroes_data bit set. This 6749305455aSBart Van Assche * satisfies the SBC requirements for LBPRZ, meaning that a subsequent 6759305455aSBart Van Assche * read will return zeroes after an UNMAP or WRITE SAME (16) to an LBA 676e6f41633SJamie Pocas * See sbc4r36 6.6.4. 677e6f41633SJamie Pocas */ 678e6f41633SJamie Pocas if (((dev->dev_attrib.emulate_tpu != 0) || 679e6f41633SJamie Pocas (dev->dev_attrib.emulate_tpws != 0)) && 680e6f41633SJamie Pocas (dev->dev_attrib.unmap_zeroes_data != 0)) 681e6f41633SJamie Pocas buf[5] |= 0x04; 682e6f41633SJamie Pocas 6831fd032eeSChristoph Hellwig return 0; 6841fd032eeSChristoph Hellwig } 6851fd032eeSChristoph Hellwig 686c66094bfSHannes Reinecke /* Referrals VPD page */ 687c66094bfSHannes Reinecke static sense_reason_t 688c66094bfSHannes Reinecke spc_emulate_evpd_b3(struct se_cmd *cmd, unsigned char *buf) 689c66094bfSHannes Reinecke { 690c66094bfSHannes Reinecke struct se_device *dev = cmd->se_dev; 691c66094bfSHannes Reinecke 692c66094bfSHannes Reinecke buf[0] = dev->transport->get_device_type(dev); 693c66094bfSHannes Reinecke buf[3] = 0x0c; 694c66094bfSHannes Reinecke put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[8]); 695096b4995SSebastian Herbszt put_unaligned_be32(dev->t10_alua.lba_map_segment_multiplier, &buf[12]); 696c66094bfSHannes Reinecke 697c66094bfSHannes Reinecke return 0; 698c66094bfSHannes Reinecke } 699c66094bfSHannes Reinecke 700de103c93SChristoph Hellwig static sense_reason_t 701de103c93SChristoph Hellwig spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); 7021fd032eeSChristoph Hellwig 7031fd032eeSChristoph Hellwig static struct { 7041fd032eeSChristoph Hellwig uint8_t page; 705de103c93SChristoph Hellwig sense_reason_t (*emulate)(struct se_cmd *, unsigned char *); 7061fd032eeSChristoph Hellwig } evpd_handlers[] = { 7071fd032eeSChristoph Hellwig { .page = 0x00, .emulate = spc_emulate_evpd_00 }, 7081fd032eeSChristoph Hellwig { .page = 0x80, .emulate = spc_emulate_evpd_80 }, 7091fd032eeSChristoph Hellwig { .page = 0x83, .emulate = spc_emulate_evpd_83 }, 7101fd032eeSChristoph Hellwig { .page = 0x86, .emulate = spc_emulate_evpd_86 }, 7111fd032eeSChristoph Hellwig { .page = 0xb0, .emulate = spc_emulate_evpd_b0 }, 7121fd032eeSChristoph Hellwig { .page = 0xb1, .emulate = spc_emulate_evpd_b1 }, 7131fd032eeSChristoph Hellwig { .page = 0xb2, .emulate = spc_emulate_evpd_b2 }, 714c66094bfSHannes Reinecke { .page = 0xb3, .emulate = spc_emulate_evpd_b3 }, 7151fd032eeSChristoph Hellwig }; 7161fd032eeSChristoph Hellwig 7171fd032eeSChristoph Hellwig /* supported vital product data pages */ 718de103c93SChristoph Hellwig static sense_reason_t 719de103c93SChristoph Hellwig spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) 7201fd032eeSChristoph Hellwig { 7211fd032eeSChristoph Hellwig int p; 7221fd032eeSChristoph Hellwig 7231fd032eeSChristoph Hellwig /* 7241fd032eeSChristoph Hellwig * Only report the INQUIRY EVPD=1 pages after a valid NAA 7251fd032eeSChristoph Hellwig * Registered Extended LUN WWN has been set via ConfigFS 7261fd032eeSChristoph Hellwig * during device creation/restart. 7271fd032eeSChristoph Hellwig */ 7280fd97ccfSChristoph Hellwig if (cmd->se_dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { 7291fd032eeSChristoph Hellwig buf[3] = ARRAY_SIZE(evpd_handlers); 7301fd032eeSChristoph Hellwig for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) 7311fd032eeSChristoph Hellwig buf[p + 4] = evpd_handlers[p].page; 7321fd032eeSChristoph Hellwig } 7331fd032eeSChristoph Hellwig 7341fd032eeSChristoph Hellwig return 0; 7351fd032eeSChristoph Hellwig } 7361fd032eeSChristoph Hellwig 737de103c93SChristoph Hellwig static sense_reason_t 738de103c93SChristoph Hellwig spc_emulate_inquiry(struct se_cmd *cmd) 7391fd032eeSChristoph Hellwig { 7401fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 741ffe7b0e9SPaolo Bonzini unsigned char *rbuf; 7421fd032eeSChristoph Hellwig unsigned char *cdb = cmd->t_task_cdb; 743f82f320eSNicholas Bellinger unsigned char *buf; 744de103c93SChristoph Hellwig sense_reason_t ret; 745de103c93SChristoph Hellwig int p; 7462426bd45SRoland Dreier int len = 0; 7471fd032eeSChristoph Hellwig 748f82f320eSNicholas Bellinger buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); 749f82f320eSNicholas Bellinger if (!buf) { 750f82f320eSNicholas Bellinger pr_err("Unable to allocate response buffer for INQUIRY\n"); 751f82f320eSNicholas Bellinger return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 752f82f320eSNicholas Bellinger } 753dea5f099SNicholas Bellinger 7541fd032eeSChristoph Hellwig buf[0] = dev->transport->get_device_type(dev); 7551fd032eeSChristoph Hellwig 7561fd032eeSChristoph Hellwig if (!(cdb[1] & 0x1)) { 7571fd032eeSChristoph Hellwig if (cdb[2]) { 7581fd032eeSChristoph Hellwig pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", 7591fd032eeSChristoph Hellwig cdb[2]); 760de103c93SChristoph Hellwig ret = TCM_INVALID_CDB_FIELD; 7611fd032eeSChristoph Hellwig goto out; 7621fd032eeSChristoph Hellwig } 7631fd032eeSChristoph Hellwig 7641fd032eeSChristoph Hellwig ret = spc_emulate_inquiry_std(cmd, buf); 7652426bd45SRoland Dreier len = buf[4] + 5; 7661fd032eeSChristoph Hellwig goto out; 7671fd032eeSChristoph Hellwig } 7681fd032eeSChristoph Hellwig 7691fd032eeSChristoph Hellwig for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { 7701fd032eeSChristoph Hellwig if (cdb[2] == evpd_handlers[p].page) { 7711fd032eeSChristoph Hellwig buf[1] = cdb[2]; 7721fd032eeSChristoph Hellwig ret = evpd_handlers[p].emulate(cmd, buf); 7732426bd45SRoland Dreier len = get_unaligned_be16(&buf[2]) + 4; 7741fd032eeSChristoph Hellwig goto out; 7751fd032eeSChristoph Hellwig } 7761fd032eeSChristoph Hellwig } 7771fd032eeSChristoph Hellwig 77895af09faSKonstantin Shelekhin pr_debug("Unknown VPD Code: 0x%02x\n", cdb[2]); 779de103c93SChristoph Hellwig ret = TCM_INVALID_CDB_FIELD; 7801fd032eeSChristoph Hellwig 7811fd032eeSChristoph Hellwig out: 782ffe7b0e9SPaolo Bonzini rbuf = transport_kmap_data_sg(cmd); 78349df9fc9SNicholas Bellinger if (rbuf) { 784f82f320eSNicholas Bellinger memcpy(rbuf, buf, min_t(u32, SE_INQUIRY_BUF, cmd->data_length)); 7851fd032eeSChristoph Hellwig transport_kunmap_data_sg(cmd); 78649df9fc9SNicholas Bellinger } 787f82f320eSNicholas Bellinger kfree(buf); 7881fd032eeSChristoph Hellwig 7891fd032eeSChristoph Hellwig if (!ret) 79014b40c1eSHannes Reinecke target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, len); 7911fd032eeSChristoph Hellwig return ret; 7921fd032eeSChristoph Hellwig } 7931fd032eeSChristoph Hellwig 794d45aca42SNicholas Bellinger static int spc_modesense_rwrecovery(struct se_cmd *cmd, u8 pc, u8 *p) 7951fd032eeSChristoph Hellwig { 7961fd032eeSChristoph Hellwig p[0] = 0x01; 7971fd032eeSChristoph Hellwig p[1] = 0x0a; 7981fd032eeSChristoph Hellwig 799d4b2b867SRoland Dreier /* No changeable values for now */ 800d4b2b867SRoland Dreier if (pc == 1) 801d4b2b867SRoland Dreier goto out; 802d4b2b867SRoland Dreier 803d4b2b867SRoland Dreier out: 8041fd032eeSChristoph Hellwig return 12; 8051fd032eeSChristoph Hellwig } 8061fd032eeSChristoph Hellwig 807d45aca42SNicholas Bellinger static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p) 8081fd032eeSChristoph Hellwig { 809d45aca42SNicholas Bellinger struct se_device *dev = cmd->se_dev; 810d45aca42SNicholas Bellinger struct se_session *sess = cmd->se_sess; 811d45aca42SNicholas Bellinger 8121fd032eeSChristoph Hellwig p[0] = 0x0a; 8131fd032eeSChristoph Hellwig p[1] = 0x0a; 814d4b2b867SRoland Dreier 815d4b2b867SRoland Dreier /* No changeable values for now */ 816d4b2b867SRoland Dreier if (pc == 1) 817d4b2b867SRoland Dreier goto out; 818d4b2b867SRoland Dreier 8194e4937e8SSagi Grimberg /* GLTSD: No implicit save of log parameters */ 8204e4937e8SSagi Grimberg p[2] = (1 << 1); 8214e4937e8SSagi Grimberg if (target_sense_desc_format(dev)) 8224e4937e8SSagi Grimberg /* D_SENSE: Descriptor format sense data for 64bit sectors */ 8234e4937e8SSagi Grimberg p[2] |= (1 << 2); 8244e4937e8SSagi Grimberg 8251fd032eeSChristoph Hellwig /* 8261fd032eeSChristoph Hellwig * From spc4r23, 7.4.7 Control mode page 8271fd032eeSChristoph Hellwig * 8281fd032eeSChristoph Hellwig * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies 8291fd032eeSChristoph Hellwig * restrictions on the algorithm used for reordering commands 8301fd032eeSChristoph Hellwig * having the SIMPLE task attribute (see SAM-4). 8311fd032eeSChristoph Hellwig * 8321fd032eeSChristoph Hellwig * Table 368 -- QUEUE ALGORITHM MODIFIER field 8331fd032eeSChristoph Hellwig * Code Description 8341fd032eeSChristoph Hellwig * 0h Restricted reordering 8351fd032eeSChristoph Hellwig * 1h Unrestricted reordering allowed 8361fd032eeSChristoph Hellwig * 2h to 7h Reserved 8371fd032eeSChristoph Hellwig * 8h to Fh Vendor specific 8381fd032eeSChristoph Hellwig * 8391fd032eeSChristoph Hellwig * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that 8401fd032eeSChristoph Hellwig * the device server shall order the processing sequence of commands 8411fd032eeSChristoph Hellwig * having the SIMPLE task attribute such that data integrity is maintained 8421fd032eeSChristoph Hellwig * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol 8431fd032eeSChristoph Hellwig * requests is halted at any time, the final value of all data observable 8441fd032eeSChristoph Hellwig * on the medium shall be the same as if all the commands had been processed 8451fd032eeSChristoph Hellwig * with the ORDERED task attribute). 8461fd032eeSChristoph Hellwig * 8471fd032eeSChristoph Hellwig * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the 8481fd032eeSChristoph Hellwig * device server may reorder the processing sequence of commands having the 8491fd032eeSChristoph Hellwig * SIMPLE task attribute in any manner. Any data integrity exposures related to 8501fd032eeSChristoph Hellwig * command sequence order shall be explicitly handled by the application client 8511fd032eeSChristoph Hellwig * through the selection of appropriate ommands and task attributes. 8521fd032eeSChristoph Hellwig */ 8530fd97ccfSChristoph Hellwig p[3] = (dev->dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; 8541fd032eeSChristoph Hellwig /* 8551fd032eeSChristoph Hellwig * From spc4r17, section 7.4.6 Control mode Page 8561fd032eeSChristoph Hellwig * 8571fd032eeSChristoph Hellwig * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b 8581fd032eeSChristoph Hellwig * 8591fd032eeSChristoph Hellwig * 00b: The logical unit shall clear any unit attention condition 8601fd032eeSChristoph Hellwig * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION 8611fd032eeSChristoph Hellwig * status and shall not establish a unit attention condition when a com- 8621fd032eeSChristoph Hellwig * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT 8631fd032eeSChristoph Hellwig * status. 8641fd032eeSChristoph Hellwig * 8651fd032eeSChristoph Hellwig * 10b: The logical unit shall not clear any unit attention condition 8661fd032eeSChristoph Hellwig * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION 8671fd032eeSChristoph Hellwig * status and shall not establish a unit attention condition when 8681fd032eeSChristoph Hellwig * a command is completed with BUSY, TASK SET FULL, or RESERVATION 8691fd032eeSChristoph Hellwig * CONFLICT status. 8701fd032eeSChristoph Hellwig * 8711fd032eeSChristoph Hellwig * 11b a The logical unit shall not clear any unit attention condition 8721fd032eeSChristoph Hellwig * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION 8731fd032eeSChristoph Hellwig * status and shall establish a unit attention condition for the 8741fd032eeSChristoph Hellwig * initiator port associated with the I_T nexus on which the BUSY, 8751fd032eeSChristoph Hellwig * TASK SET FULL, or RESERVATION CONFLICT status is being returned. 8761fd032eeSChristoph Hellwig * Depending on the status, the additional sense code shall be set to 8771fd032eeSChristoph Hellwig * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS 8781fd032eeSChristoph Hellwig * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE 8791fd032eeSChristoph Hellwig * command, a unit attention condition shall be established only once 8801fd032eeSChristoph Hellwig * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless 8811fd032eeSChristoph Hellwig * to the number of commands completed with one of those status codes. 8821fd032eeSChristoph Hellwig */ 8831bf630fdSDavid Disseldorp switch (dev->dev_attrib.emulate_ua_intlck_ctrl) { 8841bf630fdSDavid Disseldorp case TARGET_UA_INTLCK_CTRL_ESTABLISH_UA: 8851bf630fdSDavid Disseldorp p[4] = 0x30; 8861bf630fdSDavid Disseldorp break; 8871bf630fdSDavid Disseldorp case TARGET_UA_INTLCK_CTRL_NO_CLEAR: 8881bf630fdSDavid Disseldorp p[4] = 0x20; 8891bf630fdSDavid Disseldorp break; 8901bf630fdSDavid Disseldorp default: /* TARGET_UA_INTLCK_CTRL_CLEAR */ 8911bf630fdSDavid Disseldorp p[4] = 0x00; 8921bf630fdSDavid Disseldorp break; 8931bf630fdSDavid Disseldorp } 8941fd032eeSChristoph Hellwig /* 8951fd032eeSChristoph Hellwig * From spc4r17, section 7.4.6 Control mode Page 8961fd032eeSChristoph Hellwig * 8971fd032eeSChristoph Hellwig * Task Aborted Status (TAS) bit set to zero. 8981fd032eeSChristoph Hellwig * 8991fd032eeSChristoph Hellwig * A task aborted status (TAS) bit set to zero specifies that aborted 9001fd032eeSChristoph Hellwig * tasks shall be terminated by the device server without any response 9011fd032eeSChristoph Hellwig * to the application client. A TAS bit set to one specifies that tasks 9021fd032eeSChristoph Hellwig * aborted by the actions of an I_T nexus other than the I_T nexus on 9031fd032eeSChristoph Hellwig * which the command was received shall be completed with TASK ABORTED 9041fd032eeSChristoph Hellwig * status (see SAM-4). 9051fd032eeSChristoph Hellwig */ 9060fd97ccfSChristoph Hellwig p[5] = (dev->dev_attrib.emulate_tas) ? 0x40 : 0x00; 9070c30f421SNicholas Bellinger /* 9080c30f421SNicholas Bellinger * From spc4r30, section 7.5.7 Control mode page 9090c30f421SNicholas Bellinger * 9100c30f421SNicholas Bellinger * Application Tag Owner (ATO) bit set to one. 9110c30f421SNicholas Bellinger * 9120c30f421SNicholas Bellinger * If the ATO bit is set to one the device server shall not modify the 9130c30f421SNicholas Bellinger * LOGICAL BLOCK APPLICATION TAG field and, depending on the protection 9140c30f421SNicholas Bellinger * type, shall not modify the contents of the LOGICAL BLOCK REFERENCE 9150c30f421SNicholas Bellinger * TAG field. 9160c30f421SNicholas Bellinger */ 917d45aca42SNicholas Bellinger if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) { 9189ef5466eSNicholas Bellinger if (dev->dev_attrib.pi_prot_type || sess->sess_prot_type) 9190c30f421SNicholas Bellinger p[5] |= 0x80; 920d45aca42SNicholas Bellinger } 9210c30f421SNicholas Bellinger 9221fd032eeSChristoph Hellwig p[8] = 0xff; 9231fd032eeSChristoph Hellwig p[9] = 0xff; 9241fd032eeSChristoph Hellwig p[11] = 30; 9251fd032eeSChristoph Hellwig 926d4b2b867SRoland Dreier out: 9271fd032eeSChristoph Hellwig return 12; 9281fd032eeSChristoph Hellwig } 9291fd032eeSChristoph Hellwig 930d45aca42SNicholas Bellinger static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p) 9311fd032eeSChristoph Hellwig { 932d45aca42SNicholas Bellinger struct se_device *dev = cmd->se_dev; 933d45aca42SNicholas Bellinger 9341fd032eeSChristoph Hellwig p[0] = 0x08; 9351fd032eeSChristoph Hellwig p[1] = 0x12; 936d4b2b867SRoland Dreier 937d4b2b867SRoland Dreier /* No changeable values for now */ 938d4b2b867SRoland Dreier if (pc == 1) 939d4b2b867SRoland Dreier goto out; 940d4b2b867SRoland Dreier 941814e5b45SChristoph Hellwig if (target_check_wce(dev)) 9421fd032eeSChristoph Hellwig p[2] = 0x04; /* Write Cache Enable */ 9431fd032eeSChristoph Hellwig p[12] = 0x20; /* Disabled Read Ahead */ 9441fd032eeSChristoph Hellwig 945d4b2b867SRoland Dreier out: 9461fd032eeSChristoph Hellwig return 20; 9471fd032eeSChristoph Hellwig } 9481fd032eeSChristoph Hellwig 949d45aca42SNicholas Bellinger static int spc_modesense_informational_exceptions(struct se_cmd *cmd, u8 pc, unsigned char *p) 9500f6d64ceSRoland Dreier { 9510f6d64ceSRoland Dreier p[0] = 0x1c; 9520f6d64ceSRoland Dreier p[1] = 0x0a; 9530f6d64ceSRoland Dreier 9540f6d64ceSRoland Dreier /* No changeable values for now */ 9550f6d64ceSRoland Dreier if (pc == 1) 9560f6d64ceSRoland Dreier goto out; 9570f6d64ceSRoland Dreier 9580f6d64ceSRoland Dreier out: 9590f6d64ceSRoland Dreier return 12; 9600f6d64ceSRoland Dreier } 9610f6d64ceSRoland Dreier 962d4b2b867SRoland Dreier static struct { 963d4b2b867SRoland Dreier uint8_t page; 964d4b2b867SRoland Dreier uint8_t subpage; 965d45aca42SNicholas Bellinger int (*emulate)(struct se_cmd *, u8, unsigned char *); 966d4b2b867SRoland Dreier } modesense_handlers[] = { 967d4b2b867SRoland Dreier { .page = 0x01, .subpage = 0x00, .emulate = spc_modesense_rwrecovery }, 968d4b2b867SRoland Dreier { .page = 0x08, .subpage = 0x00, .emulate = spc_modesense_caching }, 969d4b2b867SRoland Dreier { .page = 0x0a, .subpage = 0x00, .emulate = spc_modesense_control }, 9700f6d64ceSRoland Dreier { .page = 0x1c, .subpage = 0x00, .emulate = spc_modesense_informational_exceptions }, 971d4b2b867SRoland Dreier }; 972d4b2b867SRoland Dreier 9731fd032eeSChristoph Hellwig static void spc_modesense_write_protect(unsigned char *buf, int type) 9741fd032eeSChristoph Hellwig { 9751fd032eeSChristoph Hellwig /* 9761fd032eeSChristoph Hellwig * I believe that the WP bit (bit 7) in the mode header is the same for 9771fd032eeSChristoph Hellwig * all device types.. 9781fd032eeSChristoph Hellwig */ 9791fd032eeSChristoph Hellwig switch (type) { 9801fd032eeSChristoph Hellwig case TYPE_DISK: 9811fd032eeSChristoph Hellwig case TYPE_TAPE: 9821fd032eeSChristoph Hellwig default: 9831fd032eeSChristoph Hellwig buf[0] |= 0x80; /* WP bit */ 9841fd032eeSChristoph Hellwig break; 9851fd032eeSChristoph Hellwig } 9861fd032eeSChristoph Hellwig } 9871fd032eeSChristoph Hellwig 9881fd032eeSChristoph Hellwig static void spc_modesense_dpofua(unsigned char *buf, int type) 9891fd032eeSChristoph Hellwig { 9901fd032eeSChristoph Hellwig switch (type) { 9911fd032eeSChristoph Hellwig case TYPE_DISK: 9921fd032eeSChristoph Hellwig buf[0] |= 0x10; /* DPOFUA bit */ 9931fd032eeSChristoph Hellwig break; 9941fd032eeSChristoph Hellwig default: 9951fd032eeSChristoph Hellwig break; 9961fd032eeSChristoph Hellwig } 9971fd032eeSChristoph Hellwig } 9981fd032eeSChristoph Hellwig 999d4b2b867SRoland Dreier static int spc_modesense_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) 1000d4b2b867SRoland Dreier { 1001d4b2b867SRoland Dreier *buf++ = 8; 1002d4b2b867SRoland Dreier put_unaligned_be32(min(blocks, 0xffffffffull), buf); 1003d4b2b867SRoland Dreier buf += 4; 1004d4b2b867SRoland Dreier put_unaligned_be32(block_size, buf); 1005d4b2b867SRoland Dreier return 9; 1006d4b2b867SRoland Dreier } 1007d4b2b867SRoland Dreier 1008d4b2b867SRoland Dreier static int spc_modesense_long_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) 1009d4b2b867SRoland Dreier { 1010d4b2b867SRoland Dreier if (blocks <= 0xffffffff) 1011d4b2b867SRoland Dreier return spc_modesense_blockdesc(buf + 3, blocks, block_size) + 3; 1012d4b2b867SRoland Dreier 1013d4b2b867SRoland Dreier *buf++ = 1; /* LONGLBA */ 1014d4b2b867SRoland Dreier buf += 2; 1015d4b2b867SRoland Dreier *buf++ = 16; 1016d4b2b867SRoland Dreier put_unaligned_be64(blocks, buf); 1017d4b2b867SRoland Dreier buf += 12; 1018d4b2b867SRoland Dreier put_unaligned_be32(block_size, buf); 1019d4b2b867SRoland Dreier 1020d4b2b867SRoland Dreier return 17; 1021d4b2b867SRoland Dreier } 1022d4b2b867SRoland Dreier 1023de103c93SChristoph Hellwig static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) 10241fd032eeSChristoph Hellwig { 10251fd032eeSChristoph Hellwig struct se_device *dev = cmd->se_dev; 10261fd032eeSChristoph Hellwig char *cdb = cmd->t_task_cdb; 1027cab9609bSNicholas Bellinger unsigned char buf[SE_MODE_PAGE_BUF], *rbuf; 10281fd032eeSChristoph Hellwig int type = dev->transport->get_device_type(dev); 10291fd032eeSChristoph Hellwig int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); 1030d4b2b867SRoland Dreier bool dbd = !!(cdb[1] & 0x08); 1031d4b2b867SRoland Dreier bool llba = ten ? !!(cdb[1] & 0x10) : false; 1032d4b2b867SRoland Dreier u8 pc = cdb[2] >> 6; 1033d4b2b867SRoland Dreier u8 page = cdb[2] & 0x3f; 1034d4b2b867SRoland Dreier u8 subpage = cdb[3]; 10351fd032eeSChristoph Hellwig int length = 0; 1036d4b2b867SRoland Dreier int ret; 1037d4b2b867SRoland Dreier int i; 10381fd032eeSChristoph Hellwig 1039cab9609bSNicholas Bellinger memset(buf, 0, SE_MODE_PAGE_BUF); 1040cab9609bSNicholas Bellinger 1041fecae40aSNicholas Bellinger /* 1042fecae40aSNicholas Bellinger * Skip over MODE DATA LENGTH + MEDIUM TYPE fields to byte 3 for 1043fecae40aSNicholas Bellinger * MODE_SENSE_10 and byte 2 for MODE_SENSE (6). 1044fecae40aSNicholas Bellinger */ 1045fecae40aSNicholas Bellinger length = ten ? 3 : 2; 1046d4b2b867SRoland Dreier 1047d4b2b867SRoland Dreier /* DEVICE-SPECIFIC PARAMETER */ 104803a68b44SAndy Grover if (cmd->se_lun->lun_access_ro || target_lun_is_rdonly(cmd)) 1049d4b2b867SRoland Dreier spc_modesense_write_protect(&buf[length], type); 1050d4b2b867SRoland Dreier 1051814e5b45SChristoph Hellwig /* 1052814e5b45SChristoph Hellwig * SBC only allows us to enable FUA and DPO together. Fortunately 1053814e5b45SChristoph Hellwig * DPO is explicitly specified as a hint, so a noop is a perfectly 1054814e5b45SChristoph Hellwig * valid implementation. 1055814e5b45SChristoph Hellwig */ 1056814e5b45SChristoph Hellwig if (target_check_fua(dev)) 1057d4b2b867SRoland Dreier spc_modesense_dpofua(&buf[length], type); 1058d4b2b867SRoland Dreier 1059d4b2b867SRoland Dreier ++length; 1060d4b2b867SRoland Dreier 1061d4b2b867SRoland Dreier /* BLOCK DESCRIPTOR */ 1062d4b2b867SRoland Dreier 1063d4b2b867SRoland Dreier /* 1064d4b2b867SRoland Dreier * For now we only include a block descriptor for disk (SBC) 1065d4b2b867SRoland Dreier * devices; other command sets use a slightly different format. 1066d4b2b867SRoland Dreier */ 1067d4b2b867SRoland Dreier if (!dbd && type == TYPE_DISK) { 1068d4b2b867SRoland Dreier u64 blocks = dev->transport->get_blocks(dev); 1069d4b2b867SRoland Dreier u32 block_size = dev->dev_attrib.block_size; 10701fd032eeSChristoph Hellwig 10711fd032eeSChristoph Hellwig if (ten) { 1072d4b2b867SRoland Dreier if (llba) { 1073d4b2b867SRoland Dreier length += spc_modesense_long_blockdesc(&buf[length], 1074d4b2b867SRoland Dreier blocks, block_size); 10751fd032eeSChristoph Hellwig } else { 1076d4b2b867SRoland Dreier length += 3; 1077d4b2b867SRoland Dreier length += spc_modesense_blockdesc(&buf[length], 1078d4b2b867SRoland Dreier blocks, block_size); 1079d4b2b867SRoland Dreier } 1080d4b2b867SRoland Dreier } else { 1081d4b2b867SRoland Dreier length += spc_modesense_blockdesc(&buf[length], blocks, 1082d4b2b867SRoland Dreier block_size); 1083d4b2b867SRoland Dreier } 1084d4b2b867SRoland Dreier } else { 1085d4b2b867SRoland Dreier if (ten) 1086d4b2b867SRoland Dreier length += 4; 1087d4b2b867SRoland Dreier else 1088d4b2b867SRoland Dreier length += 1; 10891fd032eeSChristoph Hellwig } 10901fd032eeSChristoph Hellwig 1091d4b2b867SRoland Dreier if (page == 0x3f) { 1092d4b2b867SRoland Dreier if (subpage != 0x00 && subpage != 0xff) { 1093de103c93SChristoph Hellwig pr_warn("MODE_SENSE: Invalid subpage code: 0x%02x\n", subpage); 1094de103c93SChristoph Hellwig return TCM_INVALID_CDB_FIELD; 1095d4b2b867SRoland Dreier } 1096d4b2b867SRoland Dreier 1097d4b2b867SRoland Dreier for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) { 1098d4b2b867SRoland Dreier /* 1099d4b2b867SRoland Dreier * Tricky way to say all subpage 00h for 1100d4b2b867SRoland Dreier * subpage==0, all subpages for subpage==0xff 1101d4b2b867SRoland Dreier * (and we just checked above that those are 1102d4b2b867SRoland Dreier * the only two possibilities). 1103d4b2b867SRoland Dreier */ 1104d4b2b867SRoland Dreier if ((modesense_handlers[i].subpage & ~subpage) == 0) { 1105d45aca42SNicholas Bellinger ret = modesense_handlers[i].emulate(cmd, pc, &buf[length]); 1106d4b2b867SRoland Dreier if (!ten && length + ret >= 255) 1107d4b2b867SRoland Dreier break; 1108d4b2b867SRoland Dreier length += ret; 1109d4b2b867SRoland Dreier } 1110d4b2b867SRoland Dreier } 1111d4b2b867SRoland Dreier 1112d4b2b867SRoland Dreier goto set_length; 1113d4b2b867SRoland Dreier } 1114d4b2b867SRoland Dreier 1115d4b2b867SRoland Dreier for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) 1116d4b2b867SRoland Dreier if (modesense_handlers[i].page == page && 1117d4b2b867SRoland Dreier modesense_handlers[i].subpage == subpage) { 1118d45aca42SNicholas Bellinger length += modesense_handlers[i].emulate(cmd, pc, &buf[length]); 1119d4b2b867SRoland Dreier goto set_length; 1120d4b2b867SRoland Dreier } 1121d4b2b867SRoland Dreier 1122d4b2b867SRoland Dreier /* 1123d4b2b867SRoland Dreier * We don't intend to implement: 1124d4b2b867SRoland Dreier * - obsolete page 03h "format parameters" (checked by Solaris) 1125d4b2b867SRoland Dreier */ 1126d4b2b867SRoland Dreier if (page != 0x03) 1127d4b2b867SRoland Dreier pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", 1128d4b2b867SRoland Dreier page, subpage); 1129d4b2b867SRoland Dreier 1130de103c93SChristoph Hellwig return TCM_UNKNOWN_MODE_PAGE; 1131d4b2b867SRoland Dreier 1132d4b2b867SRoland Dreier set_length: 1133d4b2b867SRoland Dreier if (ten) 1134d4b2b867SRoland Dreier put_unaligned_be16(length - 2, buf); 1135d4b2b867SRoland Dreier else 1136d4b2b867SRoland Dreier buf[0] = length - 1; 1137d4b2b867SRoland Dreier 1138cab9609bSNicholas Bellinger rbuf = transport_kmap_data_sg(cmd); 1139cab9609bSNicholas Bellinger if (rbuf) { 1140cab9609bSNicholas Bellinger memcpy(rbuf, buf, min_t(u32, SE_MODE_PAGE_BUF, cmd->data_length)); 1141cab9609bSNicholas Bellinger transport_kunmap_data_sg(cmd); 1142d4b2b867SRoland Dreier } 1143d4b2b867SRoland Dreier 114414b40c1eSHannes Reinecke target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, length); 11451fd032eeSChristoph Hellwig return 0; 11461fd032eeSChristoph Hellwig } 11471fd032eeSChristoph Hellwig 1148de103c93SChristoph Hellwig static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd) 11493a3c5e4aSRoland Dreier { 11503a3c5e4aSRoland Dreier char *cdb = cmd->t_task_cdb; 11513a3c5e4aSRoland Dreier bool ten = cdb[0] == MODE_SELECT_10; 11523a3c5e4aSRoland Dreier int off = ten ? 8 : 4; 11533a3c5e4aSRoland Dreier bool pf = !!(cdb[1] & 0x10); 11543a3c5e4aSRoland Dreier u8 page, subpage; 11553a3c5e4aSRoland Dreier unsigned char *buf; 11563a3c5e4aSRoland Dreier unsigned char tbuf[SE_MODE_PAGE_BUF]; 11573a3c5e4aSRoland Dreier int length; 11583abff1e5SChristoph Hellwig sense_reason_t ret = 0; 11593a3c5e4aSRoland Dreier int i; 11603a3c5e4aSRoland Dreier 116171f41fe1SRoland Dreier if (!cmd->data_length) { 116214b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 116371f41fe1SRoland Dreier return 0; 116471f41fe1SRoland Dreier } 116571f41fe1SRoland Dreier 116671f41fe1SRoland Dreier if (cmd->data_length < off + 2) 116771f41fe1SRoland Dreier return TCM_PARAMETER_LIST_LENGTH_ERROR; 116871f41fe1SRoland Dreier 11693a3c5e4aSRoland Dreier buf = transport_kmap_data_sg(cmd); 1170de103c93SChristoph Hellwig if (!buf) 1171de103c93SChristoph Hellwig return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 11723a3c5e4aSRoland Dreier 11733a3c5e4aSRoland Dreier if (!pf) { 1174de103c93SChristoph Hellwig ret = TCM_INVALID_CDB_FIELD; 11753a3c5e4aSRoland Dreier goto out; 11763a3c5e4aSRoland Dreier } 11773a3c5e4aSRoland Dreier 11783a3c5e4aSRoland Dreier page = buf[off] & 0x3f; 11793a3c5e4aSRoland Dreier subpage = buf[off] & 0x40 ? buf[off + 1] : 0; 11803a3c5e4aSRoland Dreier 11813a3c5e4aSRoland Dreier for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) 11823a3c5e4aSRoland Dreier if (modesense_handlers[i].page == page && 11833a3c5e4aSRoland Dreier modesense_handlers[i].subpage == subpage) { 11843a3c5e4aSRoland Dreier memset(tbuf, 0, SE_MODE_PAGE_BUF); 1185d45aca42SNicholas Bellinger length = modesense_handlers[i].emulate(cmd, 0, tbuf); 11863a3c5e4aSRoland Dreier goto check_contents; 11873a3c5e4aSRoland Dreier } 11883a3c5e4aSRoland Dreier 1189de103c93SChristoph Hellwig ret = TCM_UNKNOWN_MODE_PAGE; 11903a3c5e4aSRoland Dreier goto out; 11913a3c5e4aSRoland Dreier 11923a3c5e4aSRoland Dreier check_contents: 119371f41fe1SRoland Dreier if (cmd->data_length < off + length) { 119471f41fe1SRoland Dreier ret = TCM_PARAMETER_LIST_LENGTH_ERROR; 119571f41fe1SRoland Dreier goto out; 119671f41fe1SRoland Dreier } 119771f41fe1SRoland Dreier 1198de103c93SChristoph Hellwig if (memcmp(buf + off, tbuf, length)) 1199de103c93SChristoph Hellwig ret = TCM_INVALID_PARAMETER_LIST; 12003a3c5e4aSRoland Dreier 12013a3c5e4aSRoland Dreier out: 12023a3c5e4aSRoland Dreier transport_kunmap_data_sg(cmd); 12033a3c5e4aSRoland Dreier 12043a3c5e4aSRoland Dreier if (!ret) 120514b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 12063a3c5e4aSRoland Dreier return ret; 12073a3c5e4aSRoland Dreier } 12083a3c5e4aSRoland Dreier 1209de103c93SChristoph Hellwig static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) 12101fd032eeSChristoph Hellwig { 12111fd032eeSChristoph Hellwig unsigned char *cdb = cmd->t_task_cdb; 121232a8811fSPaolo Bonzini unsigned char *rbuf; 12131fd032eeSChristoph Hellwig u8 ua_asc = 0, ua_ascq = 0; 121432a8811fSPaolo Bonzini unsigned char buf[SE_SENSE_BUF]; 12154e4937e8SSagi Grimberg bool desc_format = target_sense_desc_format(cmd->se_dev); 121632a8811fSPaolo Bonzini 121732a8811fSPaolo Bonzini memset(buf, 0, SE_SENSE_BUF); 12181fd032eeSChristoph Hellwig 12191fd032eeSChristoph Hellwig if (cdb[1] & 0x01) { 12201fd032eeSChristoph Hellwig pr_err("REQUEST_SENSE description emulation not" 12211fd032eeSChristoph Hellwig " supported\n"); 1222de103c93SChristoph Hellwig return TCM_INVALID_CDB_FIELD; 12231fd032eeSChristoph Hellwig } 12241fd032eeSChristoph Hellwig 122532a8811fSPaolo Bonzini rbuf = transport_kmap_data_sg(cmd); 1226de103c93SChristoph Hellwig if (!rbuf) 1227de103c93SChristoph Hellwig return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 1228de103c93SChristoph Hellwig 12299ec1e1ceSSagi Grimberg if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) 12304e4937e8SSagi Grimberg scsi_build_sense_buffer(desc_format, buf, UNIT_ATTENTION, 12319ec1e1ceSSagi Grimberg ua_asc, ua_ascq); 12329ec1e1ceSSagi Grimberg else 12334e4937e8SSagi Grimberg scsi_build_sense_buffer(desc_format, buf, NO_SENSE, 0x0, 0x0); 12341fd032eeSChristoph Hellwig 123532a8811fSPaolo Bonzini memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); 12361fd032eeSChristoph Hellwig transport_kunmap_data_sg(cmd); 123732a8811fSPaolo Bonzini 123814b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 12391fd032eeSChristoph Hellwig return 0; 12401fd032eeSChristoph Hellwig } 12411fd032eeSChristoph Hellwig 1242de103c93SChristoph Hellwig sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) 1243d1b1f805SChristoph Hellwig { 1244d1b1f805SChristoph Hellwig struct se_dev_entry *deve; 1245d1b1f805SChristoph Hellwig struct se_session *sess = cmd->se_sess; 124629a05deeSNicholas Bellinger struct se_node_acl *nacl; 12470f69a387SRoland Dreier struct scsi_lun slun; 1248d1b1f805SChristoph Hellwig unsigned char *buf; 124929a05deeSNicholas Bellinger u32 lun_count = 0, offset = 8; 12500f69a387SRoland Dreier __be32 len; 1251d1b1f805SChristoph Hellwig 1252d1b1f805SChristoph Hellwig buf = transport_kmap_data_sg(cmd); 12530f69a387SRoland Dreier if (cmd->data_length && !buf) 1254de103c93SChristoph Hellwig return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 1255d1b1f805SChristoph Hellwig 1256d1b1f805SChristoph Hellwig /* 1257d1b1f805SChristoph Hellwig * If no struct se_session pointer is present, this struct se_cmd is 1258d1b1f805SChristoph Hellwig * coming via a target_core_mod PASSTHROUGH op, and not through 1259d1b1f805SChristoph Hellwig * a $FABRIC_MOD. In that case, report LUN=0 only. 1260d1b1f805SChristoph Hellwig */ 12619c395170SRoland Dreier if (!sess) 1262d1b1f805SChristoph Hellwig goto done; 12639c395170SRoland Dreier 126429a05deeSNicholas Bellinger nacl = sess->se_node_acl; 1265d1b1f805SChristoph Hellwig 126629a05deeSNicholas Bellinger rcu_read_lock(); 126729a05deeSNicholas Bellinger hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { 1268d1b1f805SChristoph Hellwig /* 1269d1b1f805SChristoph Hellwig * We determine the correct LUN LIST LENGTH even once we 1270d1b1f805SChristoph Hellwig * have reached the initial allocation length. 1271d1b1f805SChristoph Hellwig * See SPC2-R20 7.19. 1272d1b1f805SChristoph Hellwig */ 1273d1b1f805SChristoph Hellwig lun_count++; 12740f69a387SRoland Dreier if (offset >= cmd->data_length) 1275d1b1f805SChristoph Hellwig continue; 1276d1b1f805SChristoph Hellwig 12770f69a387SRoland Dreier int_to_scsilun(deve->mapped_lun, &slun); 12780f69a387SRoland Dreier memcpy(buf + offset, &slun, 12790f69a387SRoland Dreier min(8u, cmd->data_length - offset)); 1280d1b1f805SChristoph Hellwig offset += 8; 1281d1b1f805SChristoph Hellwig } 128229a05deeSNicholas Bellinger rcu_read_unlock(); 1283d1b1f805SChristoph Hellwig 1284d1b1f805SChristoph Hellwig /* 1285d1b1f805SChristoph Hellwig * See SPC3 r07, page 159. 1286d1b1f805SChristoph Hellwig */ 1287d1b1f805SChristoph Hellwig done: 12889c395170SRoland Dreier /* 12899c395170SRoland Dreier * If no LUNs are accessible, report virtual LUN 0. 12909c395170SRoland Dreier */ 12919c395170SRoland Dreier if (lun_count == 0) { 12920f69a387SRoland Dreier int_to_scsilun(0, &slun); 12930f69a387SRoland Dreier if (cmd->data_length > 8) 12940f69a387SRoland Dreier memcpy(buf + offset, &slun, 12950f69a387SRoland Dreier min(8u, cmd->data_length - offset)); 12969c395170SRoland Dreier lun_count = 1; 12979c395170SRoland Dreier } 12989c395170SRoland Dreier 12990f69a387SRoland Dreier if (buf) { 13000f69a387SRoland Dreier len = cpu_to_be32(lun_count * 8); 13010f69a387SRoland Dreier memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length)); 1302d1b1f805SChristoph Hellwig transport_kunmap_data_sg(cmd); 13030f69a387SRoland Dreier } 1304d1b1f805SChristoph Hellwig 130514b40c1eSHannes Reinecke target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, 8 + lun_count * 8); 1306d1b1f805SChristoph Hellwig return 0; 1307d1b1f805SChristoph Hellwig } 13088de530a5SChristoph Hellwig EXPORT_SYMBOL(spc_emulate_report_luns); 1309d1b1f805SChristoph Hellwig 1310de103c93SChristoph Hellwig static sense_reason_t 1311de103c93SChristoph Hellwig spc_emulate_testunitready(struct se_cmd *cmd) 13121fd032eeSChristoph Hellwig { 131314b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 13141fd032eeSChristoph Hellwig return 0; 13151fd032eeSChristoph Hellwig } 13161fd032eeSChristoph Hellwig 1317415d82b4SDmitry Bogdanov static void set_dpofua_usage_bits(u8 *usage_bits, struct se_device *dev) 1318415d82b4SDmitry Bogdanov { 1319415d82b4SDmitry Bogdanov if (!target_check_fua(dev)) 1320415d82b4SDmitry Bogdanov usage_bits[1] &= ~0x18; 1321415d82b4SDmitry Bogdanov else 1322415d82b4SDmitry Bogdanov usage_bits[1] |= 0x18; 1323415d82b4SDmitry Bogdanov } 1324415d82b4SDmitry Bogdanov 1325415d82b4SDmitry Bogdanov static void set_dpofua_usage_bits32(u8 *usage_bits, struct se_device *dev) 1326415d82b4SDmitry Bogdanov { 1327415d82b4SDmitry Bogdanov if (!target_check_fua(dev)) 1328415d82b4SDmitry Bogdanov usage_bits[10] &= ~0x18; 1329415d82b4SDmitry Bogdanov else 1330415d82b4SDmitry Bogdanov usage_bits[10] |= 0x18; 1331415d82b4SDmitry Bogdanov } 1332415d82b4SDmitry Bogdanov 13330016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read6 = { 13340016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13350016e820SDmitry Bogdanov .opcode = READ_6, 13360016e820SDmitry Bogdanov .cdb_size = 6, 13370016e820SDmitry Bogdanov .usage_bits = {READ_6, 0x1f, 0xff, 0xff, 13380016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 13390016e820SDmitry Bogdanov }; 13400016e820SDmitry Bogdanov 13410016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read10 = { 13420016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13430016e820SDmitry Bogdanov .opcode = READ_10, 13440016e820SDmitry Bogdanov .cdb_size = 10, 13450016e820SDmitry Bogdanov .usage_bits = {READ_10, 0xf8, 0xff, 0xff, 13460016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 13470016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1348415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 13490016e820SDmitry Bogdanov }; 13500016e820SDmitry Bogdanov 13510016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read12 = { 13520016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13530016e820SDmitry Bogdanov .opcode = READ_12, 13540016e820SDmitry Bogdanov .cdb_size = 12, 13550016e820SDmitry Bogdanov .usage_bits = {READ_12, 0xf8, 0xff, 0xff, 13560016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 13570016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1358415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 13590016e820SDmitry Bogdanov }; 13600016e820SDmitry Bogdanov 13610016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read16 = { 13620016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13630016e820SDmitry Bogdanov .opcode = READ_16, 13640016e820SDmitry Bogdanov .cdb_size = 16, 13650016e820SDmitry Bogdanov .usage_bits = {READ_16, 0xf8, 0xff, 0xff, 13660016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 13670016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 13680016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1369415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 13700016e820SDmitry Bogdanov }; 13710016e820SDmitry Bogdanov 13720016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write6 = { 13730016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13740016e820SDmitry Bogdanov .opcode = WRITE_6, 13750016e820SDmitry Bogdanov .cdb_size = 6, 13760016e820SDmitry Bogdanov .usage_bits = {WRITE_6, 0x1f, 0xff, 0xff, 13770016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 13780016e820SDmitry Bogdanov }; 13790016e820SDmitry Bogdanov 13800016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write10 = { 13810016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13820016e820SDmitry Bogdanov .opcode = WRITE_10, 13830016e820SDmitry Bogdanov .cdb_size = 10, 13840016e820SDmitry Bogdanov .usage_bits = {WRITE_10, 0xf8, 0xff, 0xff, 13850016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 13860016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1387415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 13880016e820SDmitry Bogdanov }; 13890016e820SDmitry Bogdanov 13900016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write_verify10 = { 13910016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 13920016e820SDmitry Bogdanov .opcode = WRITE_VERIFY, 13930016e820SDmitry Bogdanov .cdb_size = 10, 13940016e820SDmitry Bogdanov .usage_bits = {WRITE_VERIFY, 0xf0, 0xff, 0xff, 13950016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 13960016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1397415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 13980016e820SDmitry Bogdanov }; 13990016e820SDmitry Bogdanov 14000016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write12 = { 14010016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14020016e820SDmitry Bogdanov .opcode = WRITE_12, 14030016e820SDmitry Bogdanov .cdb_size = 12, 14040016e820SDmitry Bogdanov .usage_bits = {WRITE_12, 0xf8, 0xff, 0xff, 14050016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14060016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1407415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 14080016e820SDmitry Bogdanov }; 14090016e820SDmitry Bogdanov 14100016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write16 = { 14110016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14120016e820SDmitry Bogdanov .opcode = WRITE_16, 14130016e820SDmitry Bogdanov .cdb_size = 16, 14140016e820SDmitry Bogdanov .usage_bits = {WRITE_16, 0xf8, 0xff, 0xff, 14150016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14160016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14170016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1418415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 14190016e820SDmitry Bogdanov }; 14200016e820SDmitry Bogdanov 14210016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write_verify16 = { 14220016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14230016e820SDmitry Bogdanov .opcode = WRITE_VERIFY_16, 14240016e820SDmitry Bogdanov .cdb_size = 16, 14250016e820SDmitry Bogdanov .usage_bits = {WRITE_VERIFY_16, 0xf0, 0xff, 0xff, 14260016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14270016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14280016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1429415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 14300016e820SDmitry Bogdanov }; 14310016e820SDmitry Bogdanov 1432553b08d9SDmitry Bogdanov static bool tcm_is_ws_enabled(struct se_cmd *cmd) 1433553b08d9SDmitry Bogdanov { 1434*0217da08SMike Christie struct exec_cmd_ops *ops = cmd->protocol_data; 1435553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1436553b08d9SDmitry Bogdanov 1437553b08d9SDmitry Bogdanov return (dev->dev_attrib.emulate_tpws && !!ops->execute_unmap) || 1438553b08d9SDmitry Bogdanov !!ops->execute_write_same; 1439553b08d9SDmitry Bogdanov } 1440553b08d9SDmitry Bogdanov 14410016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write_same32 = { 14420016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14430016e820SDmitry Bogdanov .serv_action_valid = 1, 14440016e820SDmitry Bogdanov .opcode = VARIABLE_LENGTH_CMD, 14450016e820SDmitry Bogdanov .service_action = WRITE_SAME_32, 14460016e820SDmitry Bogdanov .cdb_size = 32, 14470016e820SDmitry Bogdanov .usage_bits = {VARIABLE_LENGTH_CMD, SCSI_CONTROL_MASK, 0x00, 0x00, 14480016e820SDmitry Bogdanov 0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0x18, 14490016e820SDmitry Bogdanov 0x00, WRITE_SAME_32, 0xe8, 0x00, 14500016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14510016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14520016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 14530016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 14540016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff}, 1455553b08d9SDmitry Bogdanov .enabled = tcm_is_ws_enabled, 1456415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits32, 14570016e820SDmitry Bogdanov }; 14580016e820SDmitry Bogdanov 1459553b08d9SDmitry Bogdanov static bool tcm_is_caw_enabled(struct se_cmd *cmd) 1460553b08d9SDmitry Bogdanov { 1461553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1462553b08d9SDmitry Bogdanov 1463553b08d9SDmitry Bogdanov return dev->dev_attrib.emulate_caw; 1464553b08d9SDmitry Bogdanov } 1465553b08d9SDmitry Bogdanov 14660016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_compare_write = { 14670016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14680016e820SDmitry Bogdanov .opcode = COMPARE_AND_WRITE, 14690016e820SDmitry Bogdanov .cdb_size = 16, 14700016e820SDmitry Bogdanov .usage_bits = {COMPARE_AND_WRITE, 0x18, 0xff, 0xff, 14710016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 14720016e820SDmitry Bogdanov 0xff, 0xff, 0x00, 0x00, 14730016e820SDmitry Bogdanov 0x00, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1474553b08d9SDmitry Bogdanov .enabled = tcm_is_caw_enabled, 1475415d82b4SDmitry Bogdanov .update_usage_bits = set_dpofua_usage_bits, 14760016e820SDmitry Bogdanov }; 14770016e820SDmitry Bogdanov 14780016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read_capacity = { 14790016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14800016e820SDmitry Bogdanov .opcode = READ_CAPACITY, 14810016e820SDmitry Bogdanov .cdb_size = 10, 14820016e820SDmitry Bogdanov .usage_bits = {READ_CAPACITY, 0x00, 0xff, 0xff, 14830016e820SDmitry Bogdanov 0xff, 0xff, 0x00, 0x00, 14840016e820SDmitry Bogdanov 0x01, SCSI_CONTROL_MASK}, 14850016e820SDmitry Bogdanov }; 14860016e820SDmitry Bogdanov 14870016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read_capacity16 = { 14880016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 14890016e820SDmitry Bogdanov .serv_action_valid = 1, 14900016e820SDmitry Bogdanov .opcode = SERVICE_ACTION_IN_16, 14910016e820SDmitry Bogdanov .service_action = SAI_READ_CAPACITY_16, 14920016e820SDmitry Bogdanov .cdb_size = 16, 14930016e820SDmitry Bogdanov .usage_bits = {SERVICE_ACTION_IN_16, SAI_READ_CAPACITY_16, 0x00, 0x00, 14940016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 14950016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 14960016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 14970016e820SDmitry Bogdanov }; 14980016e820SDmitry Bogdanov 1499553b08d9SDmitry Bogdanov static bool tcm_is_rep_ref_enabled(struct se_cmd *cmd) 1500553b08d9SDmitry Bogdanov { 1501553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1502553b08d9SDmitry Bogdanov 1503553b08d9SDmitry Bogdanov spin_lock(&dev->t10_alua.lba_map_lock); 1504553b08d9SDmitry Bogdanov if (list_empty(&dev->t10_alua.lba_map_list)) { 1505553b08d9SDmitry Bogdanov spin_unlock(&dev->t10_alua.lba_map_lock); 1506553b08d9SDmitry Bogdanov return false; 1507553b08d9SDmitry Bogdanov } 1508553b08d9SDmitry Bogdanov spin_unlock(&dev->t10_alua.lba_map_lock); 1509553b08d9SDmitry Bogdanov return true; 1510553b08d9SDmitry Bogdanov 1511553b08d9SDmitry Bogdanov } 1512553b08d9SDmitry Bogdanov 15130016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { 15140016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15150016e820SDmitry Bogdanov .serv_action_valid = 1, 15160016e820SDmitry Bogdanov .opcode = SERVICE_ACTION_IN_16, 15170016e820SDmitry Bogdanov .service_action = SAI_REPORT_REFERRALS, 15180016e820SDmitry Bogdanov .cdb_size = 16, 15190016e820SDmitry Bogdanov .usage_bits = {SERVICE_ACTION_IN_16, SAI_REPORT_REFERRALS, 0x00, 0x00, 15200016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 15210016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 15220016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 1523553b08d9SDmitry Bogdanov .enabled = tcm_is_rep_ref_enabled, 15240016e820SDmitry Bogdanov }; 15250016e820SDmitry Bogdanov 15260016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_sync_cache = { 15270016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15280016e820SDmitry Bogdanov .opcode = SYNCHRONIZE_CACHE, 15290016e820SDmitry Bogdanov .cdb_size = 10, 15300016e820SDmitry Bogdanov .usage_bits = {SYNCHRONIZE_CACHE, 0x02, 0xff, 0xff, 15310016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 15320016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 15330016e820SDmitry Bogdanov }; 15340016e820SDmitry Bogdanov 15350016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_sync_cache16 = { 15360016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15370016e820SDmitry Bogdanov .opcode = SYNCHRONIZE_CACHE_16, 15380016e820SDmitry Bogdanov .cdb_size = 16, 15390016e820SDmitry Bogdanov .usage_bits = {SYNCHRONIZE_CACHE_16, 0x02, 0xff, 0xff, 15400016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 15410016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 15420016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 15430016e820SDmitry Bogdanov }; 15440016e820SDmitry Bogdanov 1545553b08d9SDmitry Bogdanov static bool tcm_is_unmap_enabled(struct se_cmd *cmd) 1546553b08d9SDmitry Bogdanov { 1547*0217da08SMike Christie struct exec_cmd_ops *ops = cmd->protocol_data; 1548553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1549553b08d9SDmitry Bogdanov 1550553b08d9SDmitry Bogdanov return ops->execute_unmap && dev->dev_attrib.emulate_tpu; 1551553b08d9SDmitry Bogdanov } 1552553b08d9SDmitry Bogdanov 15530016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_unmap = { 15540016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15550016e820SDmitry Bogdanov .opcode = UNMAP, 15560016e820SDmitry Bogdanov .cdb_size = 10, 15570016e820SDmitry Bogdanov .usage_bits = {UNMAP, 0x00, 0x00, 0x00, 15580016e820SDmitry Bogdanov 0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0xff, 15590016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1560553b08d9SDmitry Bogdanov .enabled = tcm_is_unmap_enabled, 15610016e820SDmitry Bogdanov }; 15620016e820SDmitry Bogdanov 15630016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write_same = { 15640016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15650016e820SDmitry Bogdanov .opcode = WRITE_SAME, 15660016e820SDmitry Bogdanov .cdb_size = 10, 15670016e820SDmitry Bogdanov .usage_bits = {WRITE_SAME, 0xe8, 0xff, 0xff, 15680016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 15690016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1570553b08d9SDmitry Bogdanov .enabled = tcm_is_ws_enabled, 15710016e820SDmitry Bogdanov }; 15720016e820SDmitry Bogdanov 15730016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_write_same16 = { 15740016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15750016e820SDmitry Bogdanov .opcode = WRITE_SAME_16, 15760016e820SDmitry Bogdanov .cdb_size = 16, 15770016e820SDmitry Bogdanov .usage_bits = {WRITE_SAME_16, 0xe8, 0xff, 0xff, 15780016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 15790016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 15800016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 1581553b08d9SDmitry Bogdanov .enabled = tcm_is_ws_enabled, 15820016e820SDmitry Bogdanov }; 15830016e820SDmitry Bogdanov 15840016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_verify = { 15850016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15860016e820SDmitry Bogdanov .opcode = VERIFY, 15870016e820SDmitry Bogdanov .cdb_size = 10, 15880016e820SDmitry Bogdanov .usage_bits = {VERIFY, 0x00, 0xff, 0xff, 15890016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff, 15900016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 15910016e820SDmitry Bogdanov }; 15920016e820SDmitry Bogdanov 15930016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_verify16 = { 15940016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 15950016e820SDmitry Bogdanov .opcode = VERIFY_16, 15960016e820SDmitry Bogdanov .cdb_size = 16, 15970016e820SDmitry Bogdanov .usage_bits = {VERIFY_16, 0x00, 0xff, 0xff, 15980016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 15990016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 16000016e820SDmitry Bogdanov 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, 16010016e820SDmitry Bogdanov }; 16020016e820SDmitry Bogdanov 16030016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_start_stop = { 16040016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16050016e820SDmitry Bogdanov .opcode = START_STOP, 16060016e820SDmitry Bogdanov .cdb_size = 6, 16070016e820SDmitry Bogdanov .usage_bits = {START_STOP, 0x01, 0x00, 0x00, 16080016e820SDmitry Bogdanov 0x01, SCSI_CONTROL_MASK}, 16090016e820SDmitry Bogdanov }; 16100016e820SDmitry Bogdanov 16110016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_mode_select = { 16120016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16130016e820SDmitry Bogdanov .opcode = MODE_SELECT, 16140016e820SDmitry Bogdanov .cdb_size = 6, 16150016e820SDmitry Bogdanov .usage_bits = {MODE_SELECT, 0x10, 0x00, 0x00, 16160016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16170016e820SDmitry Bogdanov }; 16180016e820SDmitry Bogdanov 16190016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_mode_select10 = { 16200016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16210016e820SDmitry Bogdanov .opcode = MODE_SELECT_10, 16220016e820SDmitry Bogdanov .cdb_size = 10, 16230016e820SDmitry Bogdanov .usage_bits = {MODE_SELECT_10, 0x10, 0x00, 0x00, 16240016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16250016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16260016e820SDmitry Bogdanov }; 16270016e820SDmitry Bogdanov 16280016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_mode_sense = { 16290016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16300016e820SDmitry Bogdanov .opcode = MODE_SENSE, 16310016e820SDmitry Bogdanov .cdb_size = 6, 16320016e820SDmitry Bogdanov .usage_bits = {MODE_SENSE, 0x08, 0xff, 0xff, 16330016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16340016e820SDmitry Bogdanov }; 16350016e820SDmitry Bogdanov 16360016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_mode_sense10 = { 16370016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16380016e820SDmitry Bogdanov .opcode = MODE_SENSE_10, 16390016e820SDmitry Bogdanov .cdb_size = 10, 16400016e820SDmitry Bogdanov .usage_bits = {MODE_SENSE_10, 0x18, 0xff, 0xff, 16410016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16420016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16430016e820SDmitry Bogdanov }; 16440016e820SDmitry Bogdanov 16450016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pri_read_keys = { 16460016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16470016e820SDmitry Bogdanov .serv_action_valid = 1, 16480016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_IN, 16490016e820SDmitry Bogdanov .service_action = PRI_READ_KEYS, 16500016e820SDmitry Bogdanov .cdb_size = 10, 16510016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_KEYS, 0x00, 0x00, 16520016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16530016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16540016e820SDmitry Bogdanov }; 16550016e820SDmitry Bogdanov 16560016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { 16570016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16580016e820SDmitry Bogdanov .serv_action_valid = 1, 16590016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_IN, 16600016e820SDmitry Bogdanov .service_action = PRI_READ_RESERVATION, 16610016e820SDmitry Bogdanov .cdb_size = 10, 16620016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_RESERVATION, 0x00, 0x00, 16630016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16640016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 16650016e820SDmitry Bogdanov }; 16660016e820SDmitry Bogdanov 1667553b08d9SDmitry Bogdanov static bool tcm_is_pr_enabled(struct se_cmd *cmd) 1668553b08d9SDmitry Bogdanov { 1669553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1670553b08d9SDmitry Bogdanov 1671553b08d9SDmitry Bogdanov return dev->dev_attrib.emulate_pr; 1672553b08d9SDmitry Bogdanov } 1673553b08d9SDmitry Bogdanov 16740016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { 16750016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16760016e820SDmitry Bogdanov .serv_action_valid = 1, 16770016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_IN, 16780016e820SDmitry Bogdanov .service_action = PRI_REPORT_CAPABILITIES, 16790016e820SDmitry Bogdanov .cdb_size = 10, 16800016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_IN, PRI_REPORT_CAPABILITIES, 0x00, 0x00, 16810016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16820016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1683553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 16840016e820SDmitry Bogdanov }; 16850016e820SDmitry Bogdanov 16860016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { 16870016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 16880016e820SDmitry Bogdanov .serv_action_valid = 1, 16890016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_IN, 16900016e820SDmitry Bogdanov .service_action = PRI_READ_FULL_STATUS, 16910016e820SDmitry Bogdanov .cdb_size = 10, 16920016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_FULL_STATUS, 0x00, 0x00, 16930016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 16940016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1695553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 16960016e820SDmitry Bogdanov }; 16970016e820SDmitry Bogdanov 16980016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_register = { 16990016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17000016e820SDmitry Bogdanov .serv_action_valid = 1, 17010016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17020016e820SDmitry Bogdanov .service_action = PRO_REGISTER, 17030016e820SDmitry Bogdanov .cdb_size = 10, 17040016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER, 0xff, 0x00, 17050016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17060016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1707553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17080016e820SDmitry Bogdanov }; 17090016e820SDmitry Bogdanov 17100016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_reserve = { 17110016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17120016e820SDmitry Bogdanov .serv_action_valid = 1, 17130016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17140016e820SDmitry Bogdanov .service_action = PRO_RESERVE, 17150016e820SDmitry Bogdanov .cdb_size = 10, 17160016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RESERVE, 0xff, 0x00, 17170016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17180016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1719553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17200016e820SDmitry Bogdanov }; 17210016e820SDmitry Bogdanov 17220016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_release = { 17230016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17240016e820SDmitry Bogdanov .serv_action_valid = 1, 17250016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17260016e820SDmitry Bogdanov .service_action = PRO_RELEASE, 17270016e820SDmitry Bogdanov .cdb_size = 10, 17280016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RELEASE, 0xff, 0x00, 17290016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17300016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1731553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17320016e820SDmitry Bogdanov }; 17330016e820SDmitry Bogdanov 17340016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_clear = { 17350016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17360016e820SDmitry Bogdanov .serv_action_valid = 1, 17370016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17380016e820SDmitry Bogdanov .service_action = PRO_CLEAR, 17390016e820SDmitry Bogdanov .cdb_size = 10, 17400016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_CLEAR, 0xff, 0x00, 17410016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17420016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1743553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17440016e820SDmitry Bogdanov }; 17450016e820SDmitry Bogdanov 17460016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_preempt = { 17470016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17480016e820SDmitry Bogdanov .serv_action_valid = 1, 17490016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17500016e820SDmitry Bogdanov .service_action = PRO_PREEMPT, 17510016e820SDmitry Bogdanov .cdb_size = 10, 17520016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT, 0xff, 0x00, 17530016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17540016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1755553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17560016e820SDmitry Bogdanov }; 17570016e820SDmitry Bogdanov 17580016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { 17590016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17600016e820SDmitry Bogdanov .serv_action_valid = 1, 17610016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17620016e820SDmitry Bogdanov .service_action = PRO_PREEMPT_AND_ABORT, 17630016e820SDmitry Bogdanov .cdb_size = 10, 17640016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT_AND_ABORT, 0xff, 0x00, 17650016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17660016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1767553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17680016e820SDmitry Bogdanov }; 17690016e820SDmitry Bogdanov 17700016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { 17710016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17720016e820SDmitry Bogdanov .serv_action_valid = 1, 17730016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17740016e820SDmitry Bogdanov .service_action = PRO_REGISTER_AND_IGNORE_EXISTING_KEY, 17750016e820SDmitry Bogdanov .cdb_size = 10, 17760016e820SDmitry Bogdanov .usage_bits = { 17770016e820SDmitry Bogdanov PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_IGNORE_EXISTING_KEY, 17780016e820SDmitry Bogdanov 0xff, 0x00, 17790016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17800016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1781553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17820016e820SDmitry Bogdanov }; 17830016e820SDmitry Bogdanov 17840016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_pro_register_move = { 17850016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 17860016e820SDmitry Bogdanov .serv_action_valid = 1, 17870016e820SDmitry Bogdanov .opcode = PERSISTENT_RESERVE_OUT, 17880016e820SDmitry Bogdanov .service_action = PRO_REGISTER_AND_MOVE, 17890016e820SDmitry Bogdanov .cdb_size = 10, 17900016e820SDmitry Bogdanov .usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_MOVE, 0xff, 0x00, 17910016e820SDmitry Bogdanov 0x00, 0xff, 0xff, 0xff, 17920016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1793553b08d9SDmitry Bogdanov .enabled = tcm_is_pr_enabled, 17940016e820SDmitry Bogdanov }; 17950016e820SDmitry Bogdanov 1796553b08d9SDmitry Bogdanov static bool tcm_is_scsi2_reservations_enabled(struct se_cmd *cmd) 1797553b08d9SDmitry Bogdanov { 1798553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1799553b08d9SDmitry Bogdanov 1800553b08d9SDmitry Bogdanov return dev->dev_attrib.emulate_pr; 1801553b08d9SDmitry Bogdanov } 1802553b08d9SDmitry Bogdanov 18030016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_release = { 18040016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18050016e820SDmitry Bogdanov .opcode = RELEASE, 18060016e820SDmitry Bogdanov .cdb_size = 6, 18070016e820SDmitry Bogdanov .usage_bits = {RELEASE, 0x00, 0x00, 0x00, 18080016e820SDmitry Bogdanov 0x00, SCSI_CONTROL_MASK}, 1809553b08d9SDmitry Bogdanov .enabled = tcm_is_scsi2_reservations_enabled, 18100016e820SDmitry Bogdanov }; 18110016e820SDmitry Bogdanov 18120016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_release10 = { 18130016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18140016e820SDmitry Bogdanov .opcode = RELEASE_10, 18150016e820SDmitry Bogdanov .cdb_size = 10, 18160016e820SDmitry Bogdanov .usage_bits = {RELEASE_10, 0x00, 0x00, 0x00, 18170016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 18180016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1819553b08d9SDmitry Bogdanov .enabled = tcm_is_scsi2_reservations_enabled, 18200016e820SDmitry Bogdanov }; 18210016e820SDmitry Bogdanov 18220016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_reserve = { 18230016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18240016e820SDmitry Bogdanov .opcode = RESERVE, 18250016e820SDmitry Bogdanov .cdb_size = 6, 18260016e820SDmitry Bogdanov .usage_bits = {RESERVE, 0x00, 0x00, 0x00, 18270016e820SDmitry Bogdanov 0x00, SCSI_CONTROL_MASK}, 1828553b08d9SDmitry Bogdanov .enabled = tcm_is_scsi2_reservations_enabled, 18290016e820SDmitry Bogdanov }; 18300016e820SDmitry Bogdanov 18310016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_reserve10 = { 18320016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18330016e820SDmitry Bogdanov .opcode = RESERVE_10, 18340016e820SDmitry Bogdanov .cdb_size = 10, 18350016e820SDmitry Bogdanov .usage_bits = {RESERVE_10, 0x00, 0x00, 0x00, 18360016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0xff, 18370016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 1838553b08d9SDmitry Bogdanov .enabled = tcm_is_scsi2_reservations_enabled, 18390016e820SDmitry Bogdanov }; 18400016e820SDmitry Bogdanov 18410016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_request_sense = { 18420016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18430016e820SDmitry Bogdanov .opcode = REQUEST_SENSE, 18440016e820SDmitry Bogdanov .cdb_size = 6, 18450016e820SDmitry Bogdanov .usage_bits = {REQUEST_SENSE, 0x00, 0x00, 0x00, 18460016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 18470016e820SDmitry Bogdanov }; 18480016e820SDmitry Bogdanov 18490016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_inquiry = { 18500016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18510016e820SDmitry Bogdanov .opcode = INQUIRY, 18520016e820SDmitry Bogdanov .cdb_size = 6, 18530016e820SDmitry Bogdanov .usage_bits = {INQUIRY, 0x01, 0xff, 0xff, 18540016e820SDmitry Bogdanov 0xff, SCSI_CONTROL_MASK}, 18550016e820SDmitry Bogdanov }; 18560016e820SDmitry Bogdanov 1857553b08d9SDmitry Bogdanov static bool tcm_is_3pc_enabled(struct se_cmd *cmd) 1858553b08d9SDmitry Bogdanov { 1859553b08d9SDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1860553b08d9SDmitry Bogdanov 1861553b08d9SDmitry Bogdanov return dev->dev_attrib.emulate_3pc; 1862553b08d9SDmitry Bogdanov } 1863553b08d9SDmitry Bogdanov 18640016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { 18650016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18660016e820SDmitry Bogdanov .serv_action_valid = 1, 18670016e820SDmitry Bogdanov .opcode = EXTENDED_COPY, 18680016e820SDmitry Bogdanov .cdb_size = 16, 18690016e820SDmitry Bogdanov .usage_bits = {EXTENDED_COPY, 0x00, 0x00, 0x00, 18700016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 18710016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 18720016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 1873553b08d9SDmitry Bogdanov .enabled = tcm_is_3pc_enabled, 18740016e820SDmitry Bogdanov }; 18750016e820SDmitry Bogdanov 18760016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { 18770016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18780016e820SDmitry Bogdanov .serv_action_valid = 1, 18790016e820SDmitry Bogdanov .opcode = RECEIVE_COPY_RESULTS, 18800016e820SDmitry Bogdanov .service_action = RCR_SA_OPERATING_PARAMETERS, 18810016e820SDmitry Bogdanov .cdb_size = 16, 18820016e820SDmitry Bogdanov .usage_bits = {RECEIVE_COPY_RESULTS, RCR_SA_OPERATING_PARAMETERS, 18830016e820SDmitry Bogdanov 0x00, 0x00, 18840016e820SDmitry Bogdanov 0x00, 0x00, 0x00, 0x00, 18850016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 18860016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 1887553b08d9SDmitry Bogdanov .enabled = tcm_is_3pc_enabled, 18880016e820SDmitry Bogdanov }; 18890016e820SDmitry Bogdanov 18900016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_report_luns = { 18910016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 18920016e820SDmitry Bogdanov .opcode = REPORT_LUNS, 18930016e820SDmitry Bogdanov .cdb_size = 12, 18940016e820SDmitry Bogdanov .usage_bits = {REPORT_LUNS, 0x00, 0xff, 0x00, 18950016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 18960016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 18970016e820SDmitry Bogdanov }; 18980016e820SDmitry Bogdanov 18990016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_test_unit_ready = { 19000016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 19010016e820SDmitry Bogdanov .opcode = TEST_UNIT_READY, 19020016e820SDmitry Bogdanov .cdb_size = 6, 19030016e820SDmitry Bogdanov .usage_bits = {TEST_UNIT_READY, 0x00, 0x00, 0x00, 19040016e820SDmitry Bogdanov 0x00, SCSI_CONTROL_MASK}, 19050016e820SDmitry Bogdanov }; 19060016e820SDmitry Bogdanov 19070016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_report_target_pgs = { 19080016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 19090016e820SDmitry Bogdanov .serv_action_valid = 1, 19100016e820SDmitry Bogdanov .opcode = MAINTENANCE_IN, 19110016e820SDmitry Bogdanov .service_action = MI_REPORT_TARGET_PGS, 19120016e820SDmitry Bogdanov .cdb_size = 12, 19130016e820SDmitry Bogdanov .usage_bits = {MAINTENANCE_IN, 0xE0 | MI_REPORT_TARGET_PGS, 0x00, 0x00, 19140016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 19150016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 19160016e820SDmitry Bogdanov }; 19170016e820SDmitry Bogdanov 1918bd217b8cSDmitry Bogdanov 1919bd217b8cSDmitry Bogdanov static bool spc_rsoc_enabled(struct se_cmd *cmd) 1920bd217b8cSDmitry Bogdanov { 1921bd217b8cSDmitry Bogdanov struct se_device *dev = cmd->se_dev; 1922bd217b8cSDmitry Bogdanov 1923bd217b8cSDmitry Bogdanov return dev->dev_attrib.emulate_rsoc; 1924bd217b8cSDmitry Bogdanov } 1925bd217b8cSDmitry Bogdanov 19260016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { 19270016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 19280016e820SDmitry Bogdanov .serv_action_valid = 1, 19290016e820SDmitry Bogdanov .opcode = MAINTENANCE_IN, 19300016e820SDmitry Bogdanov .service_action = MI_REPORT_SUPPORTED_OPERATION_CODES, 19310016e820SDmitry Bogdanov .cdb_size = 12, 19320016e820SDmitry Bogdanov .usage_bits = {MAINTENANCE_IN, MI_REPORT_SUPPORTED_OPERATION_CODES, 19330016e820SDmitry Bogdanov 0x87, 0xff, 19340016e820SDmitry Bogdanov 0xff, 0xff, 0xff, 0xff, 19350016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 1936bd217b8cSDmitry Bogdanov .enabled = spc_rsoc_enabled, 19370016e820SDmitry Bogdanov }; 19380016e820SDmitry Bogdanov 1939553b08d9SDmitry Bogdanov static bool tcm_is_set_tpg_enabled(struct se_cmd *cmd) 1940553b08d9SDmitry Bogdanov { 1941553b08d9SDmitry Bogdanov struct t10_alua_tg_pt_gp *l_tg_pt_gp; 1942553b08d9SDmitry Bogdanov struct se_lun *l_lun = cmd->se_lun; 1943553b08d9SDmitry Bogdanov 1944553b08d9SDmitry Bogdanov rcu_read_lock(); 1945553b08d9SDmitry Bogdanov l_tg_pt_gp = rcu_dereference(l_lun->lun_tg_pt_gp); 1946553b08d9SDmitry Bogdanov if (!l_tg_pt_gp) { 1947553b08d9SDmitry Bogdanov rcu_read_unlock(); 1948553b08d9SDmitry Bogdanov return false; 1949553b08d9SDmitry Bogdanov } 1950553b08d9SDmitry Bogdanov if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { 1951553b08d9SDmitry Bogdanov rcu_read_unlock(); 1952553b08d9SDmitry Bogdanov return false; 1953553b08d9SDmitry Bogdanov } 1954553b08d9SDmitry Bogdanov rcu_read_unlock(); 1955553b08d9SDmitry Bogdanov 1956553b08d9SDmitry Bogdanov return true; 1957553b08d9SDmitry Bogdanov } 1958553b08d9SDmitry Bogdanov 19590016e820SDmitry Bogdanov static struct target_opcode_descriptor tcm_opcode_set_tpg = { 19600016e820SDmitry Bogdanov .support = SCSI_SUPPORT_FULL, 19610016e820SDmitry Bogdanov .serv_action_valid = 1, 19620016e820SDmitry Bogdanov .opcode = MAINTENANCE_OUT, 19630016e820SDmitry Bogdanov .service_action = MO_SET_TARGET_PGS, 19640016e820SDmitry Bogdanov .cdb_size = 12, 19650016e820SDmitry Bogdanov .usage_bits = {MAINTENANCE_OUT, MO_SET_TARGET_PGS, 0x00, 0x00, 19660016e820SDmitry Bogdanov 0x00, 0x00, 0xff, 0xff, 19670016e820SDmitry Bogdanov 0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, 1968553b08d9SDmitry Bogdanov .enabled = tcm_is_set_tpg_enabled, 19690016e820SDmitry Bogdanov }; 1970b9b8782fSDmitry Bogdanov 1971b9b8782fSDmitry Bogdanov static struct target_opcode_descriptor *tcm_supported_opcodes[] = { 19720016e820SDmitry Bogdanov &tcm_opcode_read6, 19730016e820SDmitry Bogdanov &tcm_opcode_read10, 19740016e820SDmitry Bogdanov &tcm_opcode_read12, 19750016e820SDmitry Bogdanov &tcm_opcode_read16, 19760016e820SDmitry Bogdanov &tcm_opcode_write6, 19770016e820SDmitry Bogdanov &tcm_opcode_write10, 19780016e820SDmitry Bogdanov &tcm_opcode_write_verify10, 19790016e820SDmitry Bogdanov &tcm_opcode_write12, 19800016e820SDmitry Bogdanov &tcm_opcode_write16, 19810016e820SDmitry Bogdanov &tcm_opcode_write_verify16, 19820016e820SDmitry Bogdanov &tcm_opcode_write_same32, 19830016e820SDmitry Bogdanov &tcm_opcode_compare_write, 19840016e820SDmitry Bogdanov &tcm_opcode_read_capacity, 19850016e820SDmitry Bogdanov &tcm_opcode_read_capacity16, 19860016e820SDmitry Bogdanov &tcm_opcode_read_report_refferals, 19870016e820SDmitry Bogdanov &tcm_opcode_sync_cache, 19880016e820SDmitry Bogdanov &tcm_opcode_sync_cache16, 19890016e820SDmitry Bogdanov &tcm_opcode_unmap, 19900016e820SDmitry Bogdanov &tcm_opcode_write_same, 19910016e820SDmitry Bogdanov &tcm_opcode_write_same16, 19920016e820SDmitry Bogdanov &tcm_opcode_verify, 19930016e820SDmitry Bogdanov &tcm_opcode_verify16, 19940016e820SDmitry Bogdanov &tcm_opcode_start_stop, 19950016e820SDmitry Bogdanov &tcm_opcode_mode_select, 19960016e820SDmitry Bogdanov &tcm_opcode_mode_select10, 19970016e820SDmitry Bogdanov &tcm_opcode_mode_sense, 19980016e820SDmitry Bogdanov &tcm_opcode_mode_sense10, 19990016e820SDmitry Bogdanov &tcm_opcode_pri_read_keys, 20000016e820SDmitry Bogdanov &tcm_opcode_pri_read_resrv, 20010016e820SDmitry Bogdanov &tcm_opcode_pri_read_caps, 20020016e820SDmitry Bogdanov &tcm_opcode_pri_read_full_status, 20030016e820SDmitry Bogdanov &tcm_opcode_pro_register, 20040016e820SDmitry Bogdanov &tcm_opcode_pro_reserve, 20050016e820SDmitry Bogdanov &tcm_opcode_pro_release, 20060016e820SDmitry Bogdanov &tcm_opcode_pro_clear, 20070016e820SDmitry Bogdanov &tcm_opcode_pro_preempt, 20080016e820SDmitry Bogdanov &tcm_opcode_pro_preempt_abort, 20090016e820SDmitry Bogdanov &tcm_opcode_pro_reg_ign_exist, 20100016e820SDmitry Bogdanov &tcm_opcode_pro_register_move, 20110016e820SDmitry Bogdanov &tcm_opcode_release, 20120016e820SDmitry Bogdanov &tcm_opcode_release10, 20130016e820SDmitry Bogdanov &tcm_opcode_reserve, 20140016e820SDmitry Bogdanov &tcm_opcode_reserve10, 20150016e820SDmitry Bogdanov &tcm_opcode_request_sense, 20160016e820SDmitry Bogdanov &tcm_opcode_inquiry, 20170016e820SDmitry Bogdanov &tcm_opcode_extended_copy_lid1, 20180016e820SDmitry Bogdanov &tcm_opcode_rcv_copy_res_op_params, 20190016e820SDmitry Bogdanov &tcm_opcode_report_luns, 20200016e820SDmitry Bogdanov &tcm_opcode_test_unit_ready, 20210016e820SDmitry Bogdanov &tcm_opcode_report_target_pgs, 20220016e820SDmitry Bogdanov &tcm_opcode_report_supp_opcodes, 20230016e820SDmitry Bogdanov &tcm_opcode_set_tpg, 2024b9b8782fSDmitry Bogdanov }; 2025b9b8782fSDmitry Bogdanov 2026b9b8782fSDmitry Bogdanov static int 2027b9b8782fSDmitry Bogdanov spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp, 2028b9b8782fSDmitry Bogdanov struct target_opcode_descriptor *descr) 2029b9b8782fSDmitry Bogdanov { 2030b9b8782fSDmitry Bogdanov if (!ctdp) 2031b9b8782fSDmitry Bogdanov return 0; 2032b9b8782fSDmitry Bogdanov 2033b9b8782fSDmitry Bogdanov put_unaligned_be16(0xa, buf); 2034b9b8782fSDmitry Bogdanov buf[3] = descr->specific_timeout; 2035b9b8782fSDmitry Bogdanov put_unaligned_be32(descr->nominal_timeout, &buf[4]); 2036b9b8782fSDmitry Bogdanov put_unaligned_be32(descr->recommended_timeout, &buf[8]); 2037b9b8782fSDmitry Bogdanov 2038b9b8782fSDmitry Bogdanov return 12; 2039b9b8782fSDmitry Bogdanov } 2040b9b8782fSDmitry Bogdanov 2041b9b8782fSDmitry Bogdanov static int 2042b9b8782fSDmitry Bogdanov spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, 2043b9b8782fSDmitry Bogdanov struct target_opcode_descriptor *descr) 2044b9b8782fSDmitry Bogdanov { 2045b9b8782fSDmitry Bogdanov int td_size = 0; 2046b9b8782fSDmitry Bogdanov 2047b9b8782fSDmitry Bogdanov buf[0] = descr->opcode; 2048b9b8782fSDmitry Bogdanov 2049b9b8782fSDmitry Bogdanov put_unaligned_be16(descr->service_action, &buf[2]); 2050b9b8782fSDmitry Bogdanov 2051b9b8782fSDmitry Bogdanov buf[5] = (ctdp << 1) | descr->serv_action_valid; 2052b9b8782fSDmitry Bogdanov put_unaligned_be16(descr->cdb_size, &buf[6]); 2053b9b8782fSDmitry Bogdanov 2054b9b8782fSDmitry Bogdanov td_size = spc_rsoc_encode_command_timeouts_descriptor(&buf[8], ctdp, 2055b9b8782fSDmitry Bogdanov descr); 2056b9b8782fSDmitry Bogdanov 2057b9b8782fSDmitry Bogdanov return 8 + td_size; 2058b9b8782fSDmitry Bogdanov } 2059b9b8782fSDmitry Bogdanov 2060b9b8782fSDmitry Bogdanov static int 2061b9b8782fSDmitry Bogdanov spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, 2062415d82b4SDmitry Bogdanov struct target_opcode_descriptor *descr, 2063415d82b4SDmitry Bogdanov struct se_device *dev) 2064b9b8782fSDmitry Bogdanov { 2065b9b8782fSDmitry Bogdanov int td_size = 0; 2066b9b8782fSDmitry Bogdanov 2067b9b8782fSDmitry Bogdanov if (!descr) { 2068b9b8782fSDmitry Bogdanov buf[1] = (ctdp << 7) | SCSI_SUPPORT_NOT_SUPPORTED; 2069b9b8782fSDmitry Bogdanov return 2; 2070b9b8782fSDmitry Bogdanov } 2071b9b8782fSDmitry Bogdanov 2072b9b8782fSDmitry Bogdanov buf[1] = (ctdp << 7) | SCSI_SUPPORT_FULL; 2073b9b8782fSDmitry Bogdanov put_unaligned_be16(descr->cdb_size, &buf[2]); 2074b9b8782fSDmitry Bogdanov memcpy(&buf[4], descr->usage_bits, descr->cdb_size); 2075415d82b4SDmitry Bogdanov if (descr->update_usage_bits) 2076415d82b4SDmitry Bogdanov descr->update_usage_bits(&buf[4], dev); 2077b9b8782fSDmitry Bogdanov 2078b9b8782fSDmitry Bogdanov td_size = spc_rsoc_encode_command_timeouts_descriptor( 2079b9b8782fSDmitry Bogdanov &buf[4 + descr->cdb_size], ctdp, descr); 2080b9b8782fSDmitry Bogdanov 2081b9b8782fSDmitry Bogdanov return 4 + descr->cdb_size + td_size; 2082b9b8782fSDmitry Bogdanov } 2083b9b8782fSDmitry Bogdanov 2084b9b8782fSDmitry Bogdanov static sense_reason_t 2085b9b8782fSDmitry Bogdanov spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) 2086b9b8782fSDmitry Bogdanov { 2087b9b8782fSDmitry Bogdanov struct target_opcode_descriptor *descr; 2088b9b8782fSDmitry Bogdanov struct se_session *sess = cmd->se_sess; 2089b9b8782fSDmitry Bogdanov unsigned char *cdb = cmd->t_task_cdb; 2090b9b8782fSDmitry Bogdanov u8 opts = cdb[2] & 0x3; 2091b9b8782fSDmitry Bogdanov u8 requested_opcode; 2092b9b8782fSDmitry Bogdanov u16 requested_sa; 2093b9b8782fSDmitry Bogdanov int i; 2094b9b8782fSDmitry Bogdanov 2095b9b8782fSDmitry Bogdanov requested_opcode = cdb[3]; 2096b9b8782fSDmitry Bogdanov requested_sa = ((u16)cdb[4]) << 8 | cdb[5]; 2097b9b8782fSDmitry Bogdanov *opcode = NULL; 2098b9b8782fSDmitry Bogdanov 2099b9b8782fSDmitry Bogdanov if (opts > 3) { 2100b9b8782fSDmitry Bogdanov pr_debug("TARGET_CORE[%s]: Invalid REPORT SUPPORTED OPERATION CODES" 2101b9b8782fSDmitry Bogdanov " with unsupported REPORTING OPTIONS %#x for 0x%08llx from %s\n", 2102b9b8782fSDmitry Bogdanov cmd->se_tfo->fabric_name, opts, 2103b9b8782fSDmitry Bogdanov cmd->se_lun->unpacked_lun, 2104b9b8782fSDmitry Bogdanov sess->se_node_acl->initiatorname); 2105b9b8782fSDmitry Bogdanov return TCM_INVALID_CDB_FIELD; 2106b9b8782fSDmitry Bogdanov } 2107b9b8782fSDmitry Bogdanov 2108b9b8782fSDmitry Bogdanov for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) { 2109b9b8782fSDmitry Bogdanov descr = tcm_supported_opcodes[i]; 2110b9b8782fSDmitry Bogdanov if (descr->opcode != requested_opcode) 2111b9b8782fSDmitry Bogdanov continue; 2112b9b8782fSDmitry Bogdanov 2113b9b8782fSDmitry Bogdanov switch (opts) { 2114b9b8782fSDmitry Bogdanov case 0x1: 2115b9b8782fSDmitry Bogdanov /* 2116b9b8782fSDmitry Bogdanov * If the REQUESTED OPERATION CODE field specifies an 2117b9b8782fSDmitry Bogdanov * operation code for which the device server implements 2118b9b8782fSDmitry Bogdanov * service actions, then the device server shall 2119b9b8782fSDmitry Bogdanov * terminate the command with CHECK CONDITION status, 2120b9b8782fSDmitry Bogdanov * with the sense key set to ILLEGAL REQUEST, and the 2121b9b8782fSDmitry Bogdanov * additional sense code set to INVALID FIELD IN CDB 2122b9b8782fSDmitry Bogdanov */ 2123b9b8782fSDmitry Bogdanov if (descr->serv_action_valid) 2124b9b8782fSDmitry Bogdanov return TCM_INVALID_CDB_FIELD; 2125553b08d9SDmitry Bogdanov 2126553b08d9SDmitry Bogdanov if (!descr->enabled || descr->enabled(cmd)) 2127b9b8782fSDmitry Bogdanov *opcode = descr; 2128b9b8782fSDmitry Bogdanov break; 2129b9b8782fSDmitry Bogdanov case 0x2: 2130b9b8782fSDmitry Bogdanov /* 2131b9b8782fSDmitry Bogdanov * If the REQUESTED OPERATION CODE field specifies an 2132b9b8782fSDmitry Bogdanov * operation code for which the device server does not 2133b9b8782fSDmitry Bogdanov * implement service actions, then the device server 2134b9b8782fSDmitry Bogdanov * shall terminate the command with CHECK CONDITION 2135b9b8782fSDmitry Bogdanov * status, with the sense key set to ILLEGAL REQUEST, 2136b9b8782fSDmitry Bogdanov * and the additional sense code set to INVALID FIELD IN CDB. 2137b9b8782fSDmitry Bogdanov */ 2138b9b8782fSDmitry Bogdanov if (descr->serv_action_valid && 2139553b08d9SDmitry Bogdanov descr->service_action == requested_sa) { 2140553b08d9SDmitry Bogdanov if (!descr->enabled || descr->enabled(cmd)) 2141b9b8782fSDmitry Bogdanov *opcode = descr; 2142553b08d9SDmitry Bogdanov } else if (!descr->serv_action_valid) 2143b9b8782fSDmitry Bogdanov return TCM_INVALID_CDB_FIELD; 2144b9b8782fSDmitry Bogdanov break; 2145b9b8782fSDmitry Bogdanov case 0x3: 2146b9b8782fSDmitry Bogdanov /* 2147b9b8782fSDmitry Bogdanov * The command support data for the operation code and 2148b9b8782fSDmitry Bogdanov * service action a specified in the REQUESTED OPERATION 2149b9b8782fSDmitry Bogdanov * CODE field and REQUESTED SERVICE ACTION field shall 2150b9b8782fSDmitry Bogdanov * be returned in the one_command parameter data format. 2151b9b8782fSDmitry Bogdanov */ 2152b9b8782fSDmitry Bogdanov if (descr->service_action == requested_sa) 2153553b08d9SDmitry Bogdanov if (!descr->enabled || descr->enabled(cmd)) 2154b9b8782fSDmitry Bogdanov *opcode = descr; 2155b9b8782fSDmitry Bogdanov break; 2156b9b8782fSDmitry Bogdanov } 2157b9b8782fSDmitry Bogdanov } 2158553b08d9SDmitry Bogdanov 2159b9b8782fSDmitry Bogdanov return 0; 2160b9b8782fSDmitry Bogdanov } 2161b9b8782fSDmitry Bogdanov 2162b9b8782fSDmitry Bogdanov static sense_reason_t 2163b9b8782fSDmitry Bogdanov spc_emulate_report_supp_op_codes(struct se_cmd *cmd) 2164b9b8782fSDmitry Bogdanov { 2165b9b8782fSDmitry Bogdanov int descr_num = ARRAY_SIZE(tcm_supported_opcodes); 2166b9b8782fSDmitry Bogdanov struct target_opcode_descriptor *descr = NULL; 2167b9b8782fSDmitry Bogdanov unsigned char *cdb = cmd->t_task_cdb; 2168b9b8782fSDmitry Bogdanov u8 rctd = (cdb[2] >> 7) & 0x1; 2169b9b8782fSDmitry Bogdanov unsigned char *buf = NULL; 2170b9b8782fSDmitry Bogdanov int response_length = 0; 2171b9b8782fSDmitry Bogdanov u8 opts = cdb[2] & 0x3; 2172b9b8782fSDmitry Bogdanov unsigned char *rbuf; 2173b9b8782fSDmitry Bogdanov sense_reason_t ret = 0; 2174b9b8782fSDmitry Bogdanov int i; 2175b9b8782fSDmitry Bogdanov 2176bd217b8cSDmitry Bogdanov if (!cmd->se_dev->dev_attrib.emulate_rsoc) 2177bd217b8cSDmitry Bogdanov return TCM_UNSUPPORTED_SCSI_OPCODE; 2178bd217b8cSDmitry Bogdanov 2179b9b8782fSDmitry Bogdanov rbuf = transport_kmap_data_sg(cmd); 2180b9b8782fSDmitry Bogdanov if (cmd->data_length && !rbuf) { 2181b9b8782fSDmitry Bogdanov ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 2182b9b8782fSDmitry Bogdanov goto out; 2183b9b8782fSDmitry Bogdanov } 2184b9b8782fSDmitry Bogdanov 2185b9b8782fSDmitry Bogdanov if (opts == 0) 2186b9b8782fSDmitry Bogdanov response_length = 4 + (8 + rctd * 12) * descr_num; 2187b9b8782fSDmitry Bogdanov else { 2188b9b8782fSDmitry Bogdanov ret = spc_rsoc_get_descr(cmd, &descr); 2189b9b8782fSDmitry Bogdanov if (ret) 2190b9b8782fSDmitry Bogdanov goto out; 2191b9b8782fSDmitry Bogdanov 2192b9b8782fSDmitry Bogdanov if (descr) 2193b9b8782fSDmitry Bogdanov response_length = 4 + descr->cdb_size + rctd * 12; 2194b9b8782fSDmitry Bogdanov else 2195b9b8782fSDmitry Bogdanov response_length = 2; 2196b9b8782fSDmitry Bogdanov } 2197b9b8782fSDmitry Bogdanov 2198b9b8782fSDmitry Bogdanov buf = kzalloc(response_length, GFP_KERNEL); 2199b9b8782fSDmitry Bogdanov if (!buf) { 2200b9b8782fSDmitry Bogdanov ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 2201b9b8782fSDmitry Bogdanov goto out; 2202b9b8782fSDmitry Bogdanov } 2203b9b8782fSDmitry Bogdanov response_length = 0; 2204b9b8782fSDmitry Bogdanov 2205b9b8782fSDmitry Bogdanov if (opts == 0) { 2206b9b8782fSDmitry Bogdanov response_length += 4; 2207b9b8782fSDmitry Bogdanov 2208b9b8782fSDmitry Bogdanov for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) { 2209b9b8782fSDmitry Bogdanov descr = tcm_supported_opcodes[i]; 2210553b08d9SDmitry Bogdanov if (descr->enabled && !descr->enabled(cmd)) 2211553b08d9SDmitry Bogdanov continue; 2212553b08d9SDmitry Bogdanov 2213b9b8782fSDmitry Bogdanov response_length += spc_rsoc_encode_command_descriptor( 2214b9b8782fSDmitry Bogdanov &buf[response_length], rctd, descr); 2215b9b8782fSDmitry Bogdanov } 2216b9b8782fSDmitry Bogdanov put_unaligned_be32(response_length - 3, buf); 2217b9b8782fSDmitry Bogdanov } else { 2218b9b8782fSDmitry Bogdanov response_length = spc_rsoc_encode_one_command_descriptor( 2219415d82b4SDmitry Bogdanov &buf[response_length], rctd, descr, 2220415d82b4SDmitry Bogdanov cmd->se_dev); 2221b9b8782fSDmitry Bogdanov } 2222b9b8782fSDmitry Bogdanov 2223b9b8782fSDmitry Bogdanov memcpy(rbuf, buf, min_t(u32, response_length, cmd->data_length)); 2224b9b8782fSDmitry Bogdanov out: 2225b9b8782fSDmitry Bogdanov kfree(buf); 2226b9b8782fSDmitry Bogdanov transport_kunmap_data_sg(cmd); 2227b9b8782fSDmitry Bogdanov 2228b9b8782fSDmitry Bogdanov if (!ret) 2229b9b8782fSDmitry Bogdanov target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, response_length); 2230b9b8782fSDmitry Bogdanov return ret; 2231b9b8782fSDmitry Bogdanov } 2232b9b8782fSDmitry Bogdanov 2233de103c93SChristoph Hellwig sense_reason_t 2234de103c93SChristoph Hellwig spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) 223588455ec4SChristoph Hellwig { 2236eba2ca45SNicholas Bellinger struct se_device *dev = cmd->se_dev; 223788455ec4SChristoph Hellwig unsigned char *cdb = cmd->t_task_cdb; 223888455ec4SChristoph Hellwig 2239b49d6f78SDavid Disseldorp if (!dev->dev_attrib.emulate_pr && 2240b49d6f78SDavid Disseldorp ((cdb[0] == PERSISTENT_RESERVE_IN) || 2241b49d6f78SDavid Disseldorp (cdb[0] == PERSISTENT_RESERVE_OUT) || 2242b49d6f78SDavid Disseldorp (cdb[0] == RELEASE || cdb[0] == RELEASE_10) || 2243b49d6f78SDavid Disseldorp (cdb[0] == RESERVE || cdb[0] == RESERVE_10))) { 2244b49d6f78SDavid Disseldorp return TCM_UNSUPPORTED_SCSI_OPCODE; 2245b49d6f78SDavid Disseldorp } 2246b49d6f78SDavid Disseldorp 224788455ec4SChristoph Hellwig switch (cdb[0]) { 224888455ec4SChristoph Hellwig case MODE_SELECT: 224988455ec4SChristoph Hellwig *size = cdb[4]; 22503a3c5e4aSRoland Dreier cmd->execute_cmd = spc_emulate_modeselect; 225188455ec4SChristoph Hellwig break; 225288455ec4SChristoph Hellwig case MODE_SELECT_10: 2253a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 22543a3c5e4aSRoland Dreier cmd->execute_cmd = spc_emulate_modeselect; 225588455ec4SChristoph Hellwig break; 225688455ec4SChristoph Hellwig case MODE_SENSE: 225788455ec4SChristoph Hellwig *size = cdb[4]; 22581fd032eeSChristoph Hellwig cmd->execute_cmd = spc_emulate_modesense; 225988455ec4SChristoph Hellwig break; 226088455ec4SChristoph Hellwig case MODE_SENSE_10: 2261a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 22621fd032eeSChristoph Hellwig cmd->execute_cmd = spc_emulate_modesense; 226388455ec4SChristoph Hellwig break; 226488455ec4SChristoph Hellwig case LOG_SELECT: 226588455ec4SChristoph Hellwig case LOG_SENSE: 2266a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 226788455ec4SChristoph Hellwig break; 226888455ec4SChristoph Hellwig case PERSISTENT_RESERVE_IN: 2269a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 2270d977f437SChristoph Hellwig cmd->execute_cmd = target_scsi3_emulate_pr_in; 227188455ec4SChristoph Hellwig break; 227288455ec4SChristoph Hellwig case PERSISTENT_RESERVE_OUT: 2273388fe699STang Wenji *size = get_unaligned_be32(&cdb[5]); 2274d977f437SChristoph Hellwig cmd->execute_cmd = target_scsi3_emulate_pr_out; 227588455ec4SChristoph Hellwig break; 227688455ec4SChristoph Hellwig case RELEASE: 227788455ec4SChristoph Hellwig case RELEASE_10: 227888455ec4SChristoph Hellwig if (cdb[0] == RELEASE_10) 2279a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 228088455ec4SChristoph Hellwig else 228188455ec4SChristoph Hellwig *size = cmd->data_length; 228288455ec4SChristoph Hellwig 228388455ec4SChristoph Hellwig cmd->execute_cmd = target_scsi2_reservation_release; 228488455ec4SChristoph Hellwig break; 228588455ec4SChristoph Hellwig case RESERVE: 228688455ec4SChristoph Hellwig case RESERVE_10: 228788455ec4SChristoph Hellwig /* 228888455ec4SChristoph Hellwig * The SPC-2 RESERVE does not contain a size in the SCSI CDB. 228988455ec4SChristoph Hellwig * Assume the passthrough or $FABRIC_MOD will tell us about it. 229088455ec4SChristoph Hellwig */ 229188455ec4SChristoph Hellwig if (cdb[0] == RESERVE_10) 2292a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[7]); 229388455ec4SChristoph Hellwig else 229488455ec4SChristoph Hellwig *size = cmd->data_length; 229588455ec4SChristoph Hellwig 229688455ec4SChristoph Hellwig cmd->execute_cmd = target_scsi2_reservation_reserve; 229788455ec4SChristoph Hellwig break; 229888455ec4SChristoph Hellwig case REQUEST_SENSE: 229988455ec4SChristoph Hellwig *size = cdb[4]; 23001fd032eeSChristoph Hellwig cmd->execute_cmd = spc_emulate_request_sense; 230188455ec4SChristoph Hellwig break; 230288455ec4SChristoph Hellwig case INQUIRY: 2303a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[3]); 230488455ec4SChristoph Hellwig 230588455ec4SChristoph Hellwig /* 2306125d0119SHannes Reinecke * Do implicit HEAD_OF_QUEUE processing for INQUIRY. 230788455ec4SChristoph Hellwig * See spc4r17 section 5.3 230888455ec4SChristoph Hellwig */ 230968d81f40SChristoph Hellwig cmd->sam_task_attr = TCM_HEAD_TAG; 23101fd032eeSChristoph Hellwig cmd->execute_cmd = spc_emulate_inquiry; 231188455ec4SChristoph Hellwig break; 231288455ec4SChristoph Hellwig case SECURITY_PROTOCOL_IN: 231388455ec4SChristoph Hellwig case SECURITY_PROTOCOL_OUT: 2314a85d667eSBart Van Assche *size = get_unaligned_be32(&cdb[6]); 231588455ec4SChristoph Hellwig break; 231688455ec4SChristoph Hellwig case EXTENDED_COPY: 231704b1b795SNicholas Bellinger *size = get_unaligned_be32(&cdb[10]); 231804b1b795SNicholas Bellinger cmd->execute_cmd = target_do_xcopy; 231904b1b795SNicholas Bellinger break; 232088455ec4SChristoph Hellwig case RECEIVE_COPY_RESULTS: 232104b1b795SNicholas Bellinger *size = get_unaligned_be32(&cdb[10]); 232204b1b795SNicholas Bellinger cmd->execute_cmd = target_do_receive_copy_results; 232304b1b795SNicholas Bellinger break; 232404b1b795SNicholas Bellinger case READ_ATTRIBUTE: 232588455ec4SChristoph Hellwig case WRITE_ATTRIBUTE: 2326a85d667eSBart Van Assche *size = get_unaligned_be32(&cdb[10]); 232788455ec4SChristoph Hellwig break; 232888455ec4SChristoph Hellwig case RECEIVE_DIAGNOSTIC: 232988455ec4SChristoph Hellwig case SEND_DIAGNOSTIC: 2330a85d667eSBart Van Assche *size = get_unaligned_be16(&cdb[3]); 233188455ec4SChristoph Hellwig break; 233288455ec4SChristoph Hellwig case WRITE_BUFFER: 2333a85d667eSBart Van Assche *size = get_unaligned_be24(&cdb[6]); 233488455ec4SChristoph Hellwig break; 233588455ec4SChristoph Hellwig case REPORT_LUNS: 2336d1b1f805SChristoph Hellwig cmd->execute_cmd = spc_emulate_report_luns; 2337a85d667eSBart Van Assche *size = get_unaligned_be32(&cdb[6]); 233888455ec4SChristoph Hellwig /* 2339125d0119SHannes Reinecke * Do implicit HEAD_OF_QUEUE processing for REPORT_LUNS 234088455ec4SChristoph Hellwig * See spc4r17 section 5.3 234188455ec4SChristoph Hellwig */ 234268d81f40SChristoph Hellwig cmd->sam_task_attr = TCM_HEAD_TAG; 234388455ec4SChristoph Hellwig break; 234488455ec4SChristoph Hellwig case TEST_UNIT_READY: 23451fd032eeSChristoph Hellwig cmd->execute_cmd = spc_emulate_testunitready; 2346d6e0175cSChristoph Hellwig *size = 0; 234788455ec4SChristoph Hellwig break; 2348eba2ca45SNicholas Bellinger case MAINTENANCE_IN: 2349eba2ca45SNicholas Bellinger if (dev->transport->get_device_type(dev) != TYPE_ROM) { 2350eba2ca45SNicholas Bellinger /* 2351eba2ca45SNicholas Bellinger * MAINTENANCE_IN from SCC-2 2352eba2ca45SNicholas Bellinger * Check for emulated MI_REPORT_TARGET_PGS 2353eba2ca45SNicholas Bellinger */ 2354c87fbd56SChristoph Hellwig if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS) { 2355eba2ca45SNicholas Bellinger cmd->execute_cmd = 2356eba2ca45SNicholas Bellinger target_emulate_report_target_port_groups; 2357eba2ca45SNicholas Bellinger } 2358b9b8782fSDmitry Bogdanov if ((cdb[1] & 0x1f) == 2359b9b8782fSDmitry Bogdanov MI_REPORT_SUPPORTED_OPERATION_CODES) 2360b9b8782fSDmitry Bogdanov cmd->execute_cmd = 2361b9b8782fSDmitry Bogdanov spc_emulate_report_supp_op_codes; 2362eba2ca45SNicholas Bellinger *size = get_unaligned_be32(&cdb[6]); 2363eba2ca45SNicholas Bellinger } else { 2364eba2ca45SNicholas Bellinger /* 2365eba2ca45SNicholas Bellinger * GPCMD_SEND_KEY from multi media commands 2366eba2ca45SNicholas Bellinger */ 2367eba2ca45SNicholas Bellinger *size = get_unaligned_be16(&cdb[8]); 2368eba2ca45SNicholas Bellinger } 2369eba2ca45SNicholas Bellinger break; 2370eba2ca45SNicholas Bellinger case MAINTENANCE_OUT: 2371eba2ca45SNicholas Bellinger if (dev->transport->get_device_type(dev) != TYPE_ROM) { 2372eba2ca45SNicholas Bellinger /* 2373eba2ca45SNicholas Bellinger * MAINTENANCE_OUT from SCC-2 2374eba2ca45SNicholas Bellinger * Check for emulated MO_SET_TARGET_PGS. 2375eba2ca45SNicholas Bellinger */ 2376c87fbd56SChristoph Hellwig if (cdb[1] == MO_SET_TARGET_PGS) { 2377eba2ca45SNicholas Bellinger cmd->execute_cmd = 2378eba2ca45SNicholas Bellinger target_emulate_set_target_port_groups; 2379eba2ca45SNicholas Bellinger } 2380eba2ca45SNicholas Bellinger *size = get_unaligned_be32(&cdb[6]); 2381eba2ca45SNicholas Bellinger } else { 2382eba2ca45SNicholas Bellinger /* 2383eba2ca45SNicholas Bellinger * GPCMD_SEND_KEY from multi media commands 2384eba2ca45SNicholas Bellinger */ 2385eba2ca45SNicholas Bellinger *size = get_unaligned_be16(&cdb[8]); 2386eba2ca45SNicholas Bellinger } 2387eba2ca45SNicholas Bellinger break; 238888455ec4SChristoph Hellwig default: 2389de103c93SChristoph Hellwig return TCM_UNSUPPORTED_SCSI_OPCODE; 239088455ec4SChristoph Hellwig } 239188455ec4SChristoph Hellwig 239288455ec4SChristoph Hellwig return 0; 239388455ec4SChristoph Hellwig } 239488455ec4SChristoph Hellwig EXPORT_SYMBOL(spc_parse_cdb); 2395