diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-05-20 11:59:15 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-16 20:27:45 -0400 |
commit | 1fd032ee10d2816c947f5d5b9abda95e728f0a8f (patch) | |
tree | 2a76ad6b466160127dd41ba1d2f6fdb54f412bf2 /drivers/target/target_core_spc.c | |
parent | d6e0175cf3f9737a760482d185bb73566bcc9331 (diff) |
target: move code for CDB emulation
Move the existing code in target_core_cdb.c into the files for the command
sets that the emulations implement.
(roland + nab: Squash patch: Fix range calculation in WRITE SAME emulation
when num blocks == 0s)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_spc.c')
-rw-r--r-- | drivers/target/target_core_spc.c | 916 |
1 files changed, 905 insertions, 11 deletions
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 156291fbf6d8..96dcb57089f7 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
@@ -39,7 +39,906 @@ | |||
39 | #include "target_core_ua.h" | 39 | #include "target_core_ua.h" |
40 | 40 | ||
41 | 41 | ||
42 | int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) | 42 | static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) |
43 | { | ||
44 | struct t10_alua_tg_pt_gp *tg_pt_gp; | ||
45 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; | ||
46 | |||
47 | /* | ||
48 | * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. | ||
49 | */ | ||
50 | buf[5] = 0x80; | ||
51 | |||
52 | /* | ||
53 | * Set TPGS field for explict and/or implict ALUA access type | ||
54 | * and opteration. | ||
55 | * | ||
56 | * See spc4r17 section 6.4.2 Table 135 | ||
57 | */ | ||
58 | if (!port) | ||
59 | return; | ||
60 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; | ||
61 | if (!tg_pt_gp_mem) | ||
62 | return; | ||
63 | |||
64 | spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | ||
65 | tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; | ||
66 | if (tg_pt_gp) | ||
67 | buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; | ||
68 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | ||
69 | } | ||
70 | |||
71 | static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) | ||
72 | { | ||
73 | struct se_lun *lun = cmd->se_lun; | ||
74 | struct se_device *dev = cmd->se_dev; | ||
75 | |||
76 | /* Set RMB (removable media) for tape devices */ | ||
77 | if (dev->transport->get_device_type(dev) == TYPE_TAPE) | ||
78 | buf[1] = 0x80; | ||
79 | |||
80 | buf[2] = dev->transport->get_device_rev(dev); | ||
81 | |||
82 | /* | ||
83 | * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 | ||
84 | * | ||
85 | * SPC4 says: | ||
86 | * A RESPONSE DATA FORMAT field set to 2h indicates that the | ||
87 | * standard INQUIRY data is in the format defined in this | ||
88 | * standard. Response data format values less than 2h are | ||
89 | * obsolete. Response data format values greater than 2h are | ||
90 | * reserved. | ||
91 | */ | ||
92 | buf[3] = 2; | ||
93 | |||
94 | /* | ||
95 | * Enable SCCS and TPGS fields for Emulated ALUA | ||
96 | */ | ||
97 | if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) | ||
98 | spc_fill_alua_data(lun->lun_sep, buf); | ||
99 | |||
100 | buf[7] = 0x2; /* CmdQue=1 */ | ||
101 | |||
102 | snprintf(&buf[8], 8, "LIO-ORG"); | ||
103 | snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); | ||
104 | snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); | ||
105 | buf[4] = 31; /* Set additional length to 31 */ | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* unit serial number */ | ||
111 | static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | ||
112 | { | ||
113 | struct se_device *dev = cmd->se_dev; | ||
114 | u16 len = 0; | ||
115 | |||
116 | if (dev->se_sub_dev->su_dev_flags & | ||
117 | SDF_EMULATED_VPD_UNIT_SERIAL) { | ||
118 | u32 unit_serial_len; | ||
119 | |||
120 | unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); | ||
121 | unit_serial_len++; /* For NULL Terminator */ | ||
122 | |||
123 | len += sprintf(&buf[4], "%s", | ||
124 | dev->se_sub_dev->t10_wwn.unit_serial); | ||
125 | len++; /* Extra Byte for NULL Terminator */ | ||
126 | buf[3] = len; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, | ||
132 | unsigned char *buf) | ||
133 | { | ||
134 | unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; | ||
135 | int cnt; | ||
136 | bool next = true; | ||
137 | |||
138 | /* | ||
139 | * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on | ||
140 | * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field | ||
141 | * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION | ||
142 | * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL | ||
143 | * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure | ||
144 | * per device uniqeness. | ||
145 | */ | ||
146 | for (cnt = 0; *p && cnt < 13; p++) { | ||
147 | int val = hex_to_bin(*p); | ||
148 | |||
149 | if (val < 0) | ||
150 | continue; | ||
151 | |||
152 | if (next) { | ||
153 | next = false; | ||
154 | buf[cnt++] |= val; | ||
155 | } else { | ||
156 | next = true; | ||
157 | buf[cnt] = val << 4; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * Device identification VPD, for a complete list of | ||
164 | * DESIGNATOR TYPEs see spc4r17 Table 459. | ||
165 | */ | ||
166 | static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) | ||
167 | { | ||
168 | struct se_device *dev = cmd->se_dev; | ||
169 | struct se_lun *lun = cmd->se_lun; | ||
170 | struct se_port *port = NULL; | ||
171 | struct se_portal_group *tpg = NULL; | ||
172 | struct t10_alua_lu_gp_member *lu_gp_mem; | ||
173 | struct t10_alua_tg_pt_gp *tg_pt_gp; | ||
174 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; | ||
175 | unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0]; | ||
176 | u32 prod_len; | ||
177 | u32 unit_serial_len, off = 0; | ||
178 | u16 len = 0, id_len; | ||
179 | |||
180 | off = 4; | ||
181 | |||
182 | /* | ||
183 | * NAA IEEE Registered Extended Assigned designator format, see | ||
184 | * spc4r17 section 7.7.3.6.5 | ||
185 | * | ||
186 | * We depend upon a target_core_mod/ConfigFS provided | ||
187 | * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial | ||
188 | * value in order to return the NAA id. | ||
189 | */ | ||
190 | if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) | ||
191 | goto check_t10_vend_desc; | ||
192 | |||
193 | /* CODE SET == Binary */ | ||
194 | buf[off++] = 0x1; | ||
195 | |||
196 | /* Set ASSOCIATION == addressed logical unit: 0)b */ | ||
197 | buf[off] = 0x00; | ||
198 | |||
199 | /* Identifier/Designator type == NAA identifier */ | ||
200 | buf[off++] |= 0x3; | ||
201 | off++; | ||
202 | |||
203 | /* Identifier/Designator length */ | ||
204 | buf[off++] = 0x10; | ||
205 | |||
206 | /* | ||
207 | * Start NAA IEEE Registered Extended Identifier/Designator | ||
208 | */ | ||
209 | buf[off++] = (0x6 << 4); | ||
210 | |||
211 | /* | ||
212 | * Use OpenFabrics IEEE Company ID: 00 14 05 | ||
213 | */ | ||
214 | buf[off++] = 0x01; | ||
215 | buf[off++] = 0x40; | ||
216 | buf[off] = (0x5 << 4); | ||
217 | |||
218 | /* | ||
219 | * Return ConfigFS Unit Serial Number information for | ||
220 | * VENDOR_SPECIFIC_IDENTIFIER and | ||
221 | * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION | ||
222 | */ | ||
223 | spc_parse_naa_6h_vendor_specific(dev, &buf[off]); | ||
224 | |||
225 | len = 20; | ||
226 | off = (len + 4); | ||
227 | |||
228 | check_t10_vend_desc: | ||
229 | /* | ||
230 | * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4 | ||
231 | */ | ||
232 | id_len = 8; /* For Vendor field */ | ||
233 | prod_len = 4; /* For VPD Header */ | ||
234 | prod_len += 8; /* For Vendor field */ | ||
235 | prod_len += strlen(prod); | ||
236 | prod_len++; /* For : */ | ||
237 | |||
238 | if (dev->se_sub_dev->su_dev_flags & | ||
239 | SDF_EMULATED_VPD_UNIT_SERIAL) { | ||
240 | unit_serial_len = | ||
241 | strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); | ||
242 | unit_serial_len++; /* For NULL Terminator */ | ||
243 | |||
244 | id_len += sprintf(&buf[off+12], "%s:%s", prod, | ||
245 | &dev->se_sub_dev->t10_wwn.unit_serial[0]); | ||
246 | } | ||
247 | buf[off] = 0x2; /* ASCII */ | ||
248 | buf[off+1] = 0x1; /* T10 Vendor ID */ | ||
249 | buf[off+2] = 0x0; | ||
250 | memcpy(&buf[off+4], "LIO-ORG", 8); | ||
251 | /* Extra Byte for NULL Terminator */ | ||
252 | id_len++; | ||
253 | /* Identifier Length */ | ||
254 | buf[off+3] = id_len; | ||
255 | /* Header size for Designation descriptor */ | ||
256 | len += (id_len + 4); | ||
257 | off += (id_len + 4); | ||
258 | /* | ||
259 | * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD | ||
260 | */ | ||
261 | port = lun->lun_sep; | ||
262 | if (port) { | ||
263 | struct t10_alua_lu_gp *lu_gp; | ||
264 | u32 padding, scsi_name_len; | ||
265 | u16 lu_gp_id = 0; | ||
266 | u16 tg_pt_gp_id = 0; | ||
267 | u16 tpgt; | ||
268 | |||
269 | tpg = port->sep_tpg; | ||
270 | /* | ||
271 | * Relative target port identifer, see spc4r17 | ||
272 | * section 7.7.3.7 | ||
273 | * | ||
274 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 | ||
275 | * section 7.5.1 Table 362 | ||
276 | */ | ||
277 | buf[off] = | ||
278 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); | ||
279 | buf[off++] |= 0x1; /* CODE SET == Binary */ | ||
280 | buf[off] = 0x80; /* Set PIV=1 */ | ||
281 | /* Set ASSOCIATION == target port: 01b */ | ||
282 | buf[off] |= 0x10; | ||
283 | /* DESIGNATOR TYPE == Relative target port identifer */ | ||
284 | buf[off++] |= 0x4; | ||
285 | off++; /* Skip over Reserved */ | ||
286 | buf[off++] = 4; /* DESIGNATOR LENGTH */ | ||
287 | /* Skip over Obsolete field in RTPI payload | ||
288 | * in Table 472 */ | ||
289 | off += 2; | ||
290 | buf[off++] = ((port->sep_rtpi >> 8) & 0xff); | ||
291 | buf[off++] = (port->sep_rtpi & 0xff); | ||
292 | len += 8; /* Header size + Designation descriptor */ | ||
293 | /* | ||
294 | * Target port group identifier, see spc4r17 | ||
295 | * section 7.7.3.8 | ||
296 | * | ||
297 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 | ||
298 | * section 7.5.1 Table 362 | ||
299 | */ | ||
300 | if (dev->se_sub_dev->t10_alua.alua_type != | ||
301 | SPC3_ALUA_EMULATED) | ||
302 | goto check_scsi_name; | ||
303 | |||
304 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; | ||
305 | if (!tg_pt_gp_mem) | ||
306 | goto check_lu_gp; | ||
307 | |||
308 | spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | ||
309 | tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; | ||
310 | if (!tg_pt_gp) { | ||
311 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | ||
312 | goto check_lu_gp; | ||
313 | } | ||
314 | tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; | ||
315 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | ||
316 | |||
317 | buf[off] = | ||
318 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); | ||
319 | buf[off++] |= 0x1; /* CODE SET == Binary */ | ||
320 | buf[off] = 0x80; /* Set PIV=1 */ | ||
321 | /* Set ASSOCIATION == target port: 01b */ | ||
322 | buf[off] |= 0x10; | ||
323 | /* DESIGNATOR TYPE == Target port group identifier */ | ||
324 | buf[off++] |= 0x5; | ||
325 | off++; /* Skip over Reserved */ | ||
326 | buf[off++] = 4; /* DESIGNATOR LENGTH */ | ||
327 | off += 2; /* Skip over Reserved Field */ | ||
328 | buf[off++] = ((tg_pt_gp_id >> 8) & 0xff); | ||
329 | buf[off++] = (tg_pt_gp_id & 0xff); | ||
330 | len += 8; /* Header size + Designation descriptor */ | ||
331 | /* | ||
332 | * Logical Unit Group identifier, see spc4r17 | ||
333 | * section 7.7.3.8 | ||
334 | */ | ||
335 | check_lu_gp: | ||
336 | lu_gp_mem = dev->dev_alua_lu_gp_mem; | ||
337 | if (!lu_gp_mem) | ||
338 | goto check_scsi_name; | ||
339 | |||
340 | spin_lock(&lu_gp_mem->lu_gp_mem_lock); | ||
341 | lu_gp = lu_gp_mem->lu_gp; | ||
342 | if (!lu_gp) { | ||
343 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); | ||
344 | goto check_scsi_name; | ||
345 | } | ||
346 | lu_gp_id = lu_gp->lu_gp_id; | ||
347 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); | ||
348 | |||
349 | buf[off++] |= 0x1; /* CODE SET == Binary */ | ||
350 | /* DESIGNATOR TYPE == Logical Unit Group identifier */ | ||
351 | buf[off++] |= 0x6; | ||
352 | off++; /* Skip over Reserved */ | ||
353 | buf[off++] = 4; /* DESIGNATOR LENGTH */ | ||
354 | off += 2; /* Skip over Reserved Field */ | ||
355 | buf[off++] = ((lu_gp_id >> 8) & 0xff); | ||
356 | buf[off++] = (lu_gp_id & 0xff); | ||
357 | len += 8; /* Header size + Designation descriptor */ | ||
358 | /* | ||
359 | * SCSI name string designator, see spc4r17 | ||
360 | * section 7.7.3.11 | ||
361 | * | ||
362 | * Get the PROTOCOL IDENTIFIER as defined by spc4r17 | ||
363 | * section 7.5.1 Table 362 | ||
364 | */ | ||
365 | check_scsi_name: | ||
366 | scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg)); | ||
367 | /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */ | ||
368 | scsi_name_len += 10; | ||
369 | /* Check for 4-byte padding */ | ||
370 | padding = ((-scsi_name_len) & 3); | ||
371 | if (padding != 0) | ||
372 | scsi_name_len += padding; | ||
373 | /* Header size + Designation descriptor */ | ||
374 | scsi_name_len += 4; | ||
375 | |||
376 | buf[off] = | ||
377 | (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); | ||
378 | buf[off++] |= 0x3; /* CODE SET == UTF-8 */ | ||
379 | buf[off] = 0x80; /* Set PIV=1 */ | ||
380 | /* Set ASSOCIATION == target port: 01b */ | ||
381 | buf[off] |= 0x10; | ||
382 | /* DESIGNATOR TYPE == SCSI name string */ | ||
383 | buf[off++] |= 0x8; | ||
384 | off += 2; /* Skip over Reserved and length */ | ||
385 | /* | ||
386 | * SCSI name string identifer containing, $FABRIC_MOD | ||
387 | * dependent information. For LIO-Target and iSCSI | ||
388 | * Target Port, this means "<iSCSI name>,t,0x<TPGT> in | ||
389 | * UTF-8 encoding. | ||
390 | */ | ||
391 | tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); | ||
392 | scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x", | ||
393 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt); | ||
394 | scsi_name_len += 1 /* Include NULL terminator */; | ||
395 | /* | ||
396 | * The null-terminated, null-padded (see 4.4.2) SCSI | ||
397 | * NAME STRING field contains a UTF-8 format string. | ||
398 | * The number of bytes in the SCSI NAME STRING field | ||
399 | * (i.e., the value in the DESIGNATOR LENGTH field) | ||
400 | * shall be no larger than 256 and shall be a multiple | ||
401 | * of four. | ||
402 | */ | ||
403 | if (padding) | ||
404 | scsi_name_len += padding; | ||
405 | |||
406 | buf[off-1] = scsi_name_len; | ||
407 | off += scsi_name_len; | ||
408 | /* Header size + Designation descriptor */ | ||
409 | len += (scsi_name_len + 4); | ||
410 | } | ||
411 | buf[2] = ((len >> 8) & 0xff); | ||
412 | buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | /* Extended INQUIRY Data VPD Page */ | ||
417 | static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) | ||
418 | { | ||
419 | buf[3] = 0x3c; | ||
420 | /* Set HEADSUP, ORDSUP, SIMPSUP */ | ||
421 | buf[5] = 0x07; | ||
422 | |||
423 | /* If WriteCache emulation is enabled, set V_SUP */ | ||
424 | if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) | ||
425 | buf[6] = 0x01; | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | /* Block Limits VPD page */ | ||
430 | static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) | ||
431 | { | ||
432 | struct se_device *dev = cmd->se_dev; | ||
433 | u32 max_sectors; | ||
434 | int have_tp = 0; | ||
435 | |||
436 | /* | ||
437 | * Following spc3r22 section 6.5.3 Block Limits VPD page, when | ||
438 | * emulate_tpu=1 or emulate_tpws=1 we will be expect a | ||
439 | * different page length for Thin Provisioning. | ||
440 | */ | ||
441 | if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) | ||
442 | have_tp = 1; | ||
443 | |||
444 | buf[0] = dev->transport->get_device_type(dev); | ||
445 | buf[3] = have_tp ? 0x3c : 0x10; | ||
446 | |||
447 | /* Set WSNZ to 1 */ | ||
448 | buf[4] = 0x01; | ||
449 | |||
450 | /* | ||
451 | * Set OPTIMAL TRANSFER LENGTH GRANULARITY | ||
452 | */ | ||
453 | put_unaligned_be16(1, &buf[6]); | ||
454 | |||
455 | /* | ||
456 | * Set MAXIMUM TRANSFER LENGTH | ||
457 | */ | ||
458 | max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, | ||
459 | dev->se_sub_dev->se_dev_attrib.hw_max_sectors); | ||
460 | put_unaligned_be32(max_sectors, &buf[8]); | ||
461 | |||
462 | /* | ||
463 | * Set OPTIMAL TRANSFER LENGTH | ||
464 | */ | ||
465 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); | ||
466 | |||
467 | /* | ||
468 | * Exit now if we don't support TP. | ||
469 | */ | ||
470 | if (!have_tp) | ||
471 | return 0; | ||
472 | |||
473 | /* | ||
474 | * Set MAXIMUM UNMAP LBA COUNT | ||
475 | */ | ||
476 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]); | ||
477 | |||
478 | /* | ||
479 | * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT | ||
480 | */ | ||
481 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count, | ||
482 | &buf[24]); | ||
483 | |||
484 | /* | ||
485 | * Set OPTIMAL UNMAP GRANULARITY | ||
486 | */ | ||
487 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]); | ||
488 | |||
489 | /* | ||
490 | * UNMAP GRANULARITY ALIGNMENT | ||
491 | */ | ||
492 | put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment, | ||
493 | &buf[32]); | ||
494 | if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0) | ||
495 | buf[32] |= 0x80; /* Set the UGAVALID bit */ | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | /* Block Device Characteristics VPD page */ | ||
501 | static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) | ||
502 | { | ||
503 | struct se_device *dev = cmd->se_dev; | ||
504 | |||
505 | buf[0] = dev->transport->get_device_type(dev); | ||
506 | buf[3] = 0x3c; | ||
507 | buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0; | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | /* Thin Provisioning VPD */ | ||
513 | static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) | ||
514 | { | ||
515 | struct se_device *dev = cmd->se_dev; | ||
516 | |||
517 | /* | ||
518 | * From spc3r22 section 6.5.4 Thin Provisioning VPD page: | ||
519 | * | ||
520 | * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to | ||
521 | * zero, then the page length shall be set to 0004h. If the DP bit | ||
522 | * is set to one, then the page length shall be set to the value | ||
523 | * defined in table 162. | ||
524 | */ | ||
525 | buf[0] = dev->transport->get_device_type(dev); | ||
526 | |||
527 | /* | ||
528 | * Set Hardcoded length mentioned above for DP=0 | ||
529 | */ | ||
530 | put_unaligned_be16(0x0004, &buf[2]); | ||
531 | |||
532 | /* | ||
533 | * The THRESHOLD EXPONENT field indicates the threshold set size in | ||
534 | * LBAs as a power of 2 (i.e., the threshold set size is equal to | ||
535 | * 2(threshold exponent)). | ||
536 | * | ||
537 | * Note that this is currently set to 0x00 as mkp says it will be | ||
538 | * changing again. We can enable this once it has settled in T10 | ||
539 | * and is actually used by Linux/SCSI ML code. | ||
540 | */ | ||
541 | buf[4] = 0x00; | ||
542 | |||
543 | /* | ||
544 | * A TPU bit set to one indicates that the device server supports | ||
545 | * the UNMAP command (see 5.25). A TPU bit set to zero indicates | ||
546 | * that the device server does not support the UNMAP command. | ||
547 | */ | ||
548 | if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0) | ||
549 | buf[5] = 0x80; | ||
550 | |||
551 | /* | ||
552 | * A TPWS bit set to one indicates that the device server supports | ||
553 | * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs. | ||
554 | * A TPWS bit set to zero indicates that the device server does not | ||
555 | * support the use of the WRITE SAME (16) command to unmap LBAs. | ||
556 | */ | ||
557 | if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0) | ||
558 | buf[5] |= 0x40; | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); | ||
564 | |||
565 | static struct { | ||
566 | uint8_t page; | ||
567 | int (*emulate)(struct se_cmd *, unsigned char *); | ||
568 | } evpd_handlers[] = { | ||
569 | { .page = 0x00, .emulate = spc_emulate_evpd_00 }, | ||
570 | { .page = 0x80, .emulate = spc_emulate_evpd_80 }, | ||
571 | { .page = 0x83, .emulate = spc_emulate_evpd_83 }, | ||
572 | { .page = 0x86, .emulate = spc_emulate_evpd_86 }, | ||
573 | { .page = 0xb0, .emulate = spc_emulate_evpd_b0 }, | ||
574 | { .page = 0xb1, .emulate = spc_emulate_evpd_b1 }, | ||
575 | { .page = 0xb2, .emulate = spc_emulate_evpd_b2 }, | ||
576 | }; | ||
577 | |||
578 | /* supported vital product data pages */ | ||
579 | static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) | ||
580 | { | ||
581 | int p; | ||
582 | |||
583 | /* | ||
584 | * Only report the INQUIRY EVPD=1 pages after a valid NAA | ||
585 | * Registered Extended LUN WWN has been set via ConfigFS | ||
586 | * during device creation/restart. | ||
587 | */ | ||
588 | if (cmd->se_dev->se_sub_dev->su_dev_flags & | ||
589 | SDF_EMULATED_VPD_UNIT_SERIAL) { | ||
590 | buf[3] = ARRAY_SIZE(evpd_handlers); | ||
591 | for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) | ||
592 | buf[p + 4] = evpd_handlers[p].page; | ||
593 | } | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int spc_emulate_inquiry(struct se_cmd *cmd) | ||
599 | { | ||
600 | struct se_device *dev = cmd->se_dev; | ||
601 | struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; | ||
602 | unsigned char *buf, *map_buf; | ||
603 | unsigned char *cdb = cmd->t_task_cdb; | ||
604 | int p, ret; | ||
605 | |||
606 | map_buf = transport_kmap_data_sg(cmd); | ||
607 | /* | ||
608 | * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we | ||
609 | * know we actually allocated a full page. Otherwise, if the | ||
610 | * data buffer is too small, allocate a temporary buffer so we | ||
611 | * don't have to worry about overruns in all our INQUIRY | ||
612 | * emulation handling. | ||
613 | */ | ||
614 | if (cmd->data_length < SE_INQUIRY_BUF && | ||
615 | (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { | ||
616 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); | ||
617 | if (!buf) { | ||
618 | transport_kunmap_data_sg(cmd); | ||
619 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
620 | return -ENOMEM; | ||
621 | } | ||
622 | } else { | ||
623 | buf = map_buf; | ||
624 | } | ||
625 | |||
626 | if (dev == tpg->tpg_virt_lun0.lun_se_dev) | ||
627 | buf[0] = 0x3f; /* Not connected */ | ||
628 | else | ||
629 | buf[0] = dev->transport->get_device_type(dev); | ||
630 | |||
631 | if (!(cdb[1] & 0x1)) { | ||
632 | if (cdb[2]) { | ||
633 | pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", | ||
634 | cdb[2]); | ||
635 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
636 | ret = -EINVAL; | ||
637 | goto out; | ||
638 | } | ||
639 | |||
640 | ret = spc_emulate_inquiry_std(cmd, buf); | ||
641 | goto out; | ||
642 | } | ||
643 | |||
644 | for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { | ||
645 | if (cdb[2] == evpd_handlers[p].page) { | ||
646 | buf[1] = cdb[2]; | ||
647 | ret = evpd_handlers[p].emulate(cmd, buf); | ||
648 | goto out; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); | ||
653 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
654 | ret = -EINVAL; | ||
655 | |||
656 | out: | ||
657 | if (buf != map_buf) { | ||
658 | memcpy(map_buf, buf, cmd->data_length); | ||
659 | kfree(buf); | ||
660 | } | ||
661 | transport_kunmap_data_sg(cmd); | ||
662 | |||
663 | if (!ret) | ||
664 | target_complete_cmd(cmd, GOOD); | ||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | static int spc_modesense_rwrecovery(unsigned char *p) | ||
669 | { | ||
670 | p[0] = 0x01; | ||
671 | p[1] = 0x0a; | ||
672 | |||
673 | return 12; | ||
674 | } | ||
675 | |||
676 | static int spc_modesense_control(struct se_device *dev, unsigned char *p) | ||
677 | { | ||
678 | p[0] = 0x0a; | ||
679 | p[1] = 0x0a; | ||
680 | p[2] = 2; | ||
681 | /* | ||
682 | * From spc4r23, 7.4.7 Control mode page | ||
683 | * | ||
684 | * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies | ||
685 | * restrictions on the algorithm used for reordering commands | ||
686 | * having the SIMPLE task attribute (see SAM-4). | ||
687 | * | ||
688 | * Table 368 -- QUEUE ALGORITHM MODIFIER field | ||
689 | * Code Description | ||
690 | * 0h Restricted reordering | ||
691 | * 1h Unrestricted reordering allowed | ||
692 | * 2h to 7h Reserved | ||
693 | * 8h to Fh Vendor specific | ||
694 | * | ||
695 | * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that | ||
696 | * the device server shall order the processing sequence of commands | ||
697 | * having the SIMPLE task attribute such that data integrity is maintained | ||
698 | * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol | ||
699 | * requests is halted at any time, the final value of all data observable | ||
700 | * on the medium shall be the same as if all the commands had been processed | ||
701 | * with the ORDERED task attribute). | ||
702 | * | ||
703 | * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the | ||
704 | * device server may reorder the processing sequence of commands having the | ||
705 | * SIMPLE task attribute in any manner. Any data integrity exposures related to | ||
706 | * command sequence order shall be explicitly handled by the application client | ||
707 | * through the selection of appropriate ommands and task attributes. | ||
708 | */ | ||
709 | p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; | ||
710 | /* | ||
711 | * From spc4r17, section 7.4.6 Control mode Page | ||
712 | * | ||
713 | * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b | ||
714 | * | ||
715 | * 00b: The logical unit shall clear any unit attention condition | ||
716 | * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION | ||
717 | * status and shall not establish a unit attention condition when a com- | ||
718 | * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT | ||
719 | * status. | ||
720 | * | ||
721 | * 10b: The logical unit shall not clear any unit attention condition | ||
722 | * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION | ||
723 | * status and shall not establish a unit attention condition when | ||
724 | * a command is completed with BUSY, TASK SET FULL, or RESERVATION | ||
725 | * CONFLICT status. | ||
726 | * | ||
727 | * 11b a The logical unit shall not clear any unit attention condition | ||
728 | * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION | ||
729 | * status and shall establish a unit attention condition for the | ||
730 | * initiator port associated with the I_T nexus on which the BUSY, | ||
731 | * TASK SET FULL, or RESERVATION CONFLICT status is being returned. | ||
732 | * Depending on the status, the additional sense code shall be set to | ||
733 | * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS | ||
734 | * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE | ||
735 | * command, a unit attention condition shall be established only once | ||
736 | * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless | ||
737 | * to the number of commands completed with one of those status codes. | ||
738 | */ | ||
739 | p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : | ||
740 | (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; | ||
741 | /* | ||
742 | * From spc4r17, section 7.4.6 Control mode Page | ||
743 | * | ||
744 | * Task Aborted Status (TAS) bit set to zero. | ||
745 | * | ||
746 | * A task aborted status (TAS) bit set to zero specifies that aborted | ||
747 | * tasks shall be terminated by the device server without any response | ||
748 | * to the application client. A TAS bit set to one specifies that tasks | ||
749 | * aborted by the actions of an I_T nexus other than the I_T nexus on | ||
750 | * which the command was received shall be completed with TASK ABORTED | ||
751 | * status (see SAM-4). | ||
752 | */ | ||
753 | p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00; | ||
754 | p[8] = 0xff; | ||
755 | p[9] = 0xff; | ||
756 | p[11] = 30; | ||
757 | |||
758 | return 12; | ||
759 | } | ||
760 | |||
761 | static int spc_modesense_caching(struct se_device *dev, unsigned char *p) | ||
762 | { | ||
763 | p[0] = 0x08; | ||
764 | p[1] = 0x12; | ||
765 | if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) | ||
766 | p[2] = 0x04; /* Write Cache Enable */ | ||
767 | p[12] = 0x20; /* Disabled Read Ahead */ | ||
768 | |||
769 | return 20; | ||
770 | } | ||
771 | |||
772 | static void spc_modesense_write_protect(unsigned char *buf, int type) | ||
773 | { | ||
774 | /* | ||
775 | * I believe that the WP bit (bit 7) in the mode header is the same for | ||
776 | * all device types.. | ||
777 | */ | ||
778 | switch (type) { | ||
779 | case TYPE_DISK: | ||
780 | case TYPE_TAPE: | ||
781 | default: | ||
782 | buf[0] |= 0x80; /* WP bit */ | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | static void spc_modesense_dpofua(unsigned char *buf, int type) | ||
788 | { | ||
789 | switch (type) { | ||
790 | case TYPE_DISK: | ||
791 | buf[0] |= 0x10; /* DPOFUA bit */ | ||
792 | break; | ||
793 | default: | ||
794 | break; | ||
795 | } | ||
796 | } | ||
797 | |||
798 | static int spc_emulate_modesense(struct se_cmd *cmd) | ||
799 | { | ||
800 | struct se_device *dev = cmd->se_dev; | ||
801 | char *cdb = cmd->t_task_cdb; | ||
802 | unsigned char *rbuf; | ||
803 | int type = dev->transport->get_device_type(dev); | ||
804 | int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); | ||
805 | int offset = ten ? 8 : 4; | ||
806 | int length = 0; | ||
807 | unsigned char buf[SE_MODE_PAGE_BUF]; | ||
808 | |||
809 | memset(buf, 0, SE_MODE_PAGE_BUF); | ||
810 | |||
811 | switch (cdb[2] & 0x3f) { | ||
812 | case 0x01: | ||
813 | length = spc_modesense_rwrecovery(&buf[offset]); | ||
814 | break; | ||
815 | case 0x08: | ||
816 | length = spc_modesense_caching(dev, &buf[offset]); | ||
817 | break; | ||
818 | case 0x0a: | ||
819 | length = spc_modesense_control(dev, &buf[offset]); | ||
820 | break; | ||
821 | case 0x3f: | ||
822 | length = spc_modesense_rwrecovery(&buf[offset]); | ||
823 | length += spc_modesense_caching(dev, &buf[offset+length]); | ||
824 | length += spc_modesense_control(dev, &buf[offset+length]); | ||
825 | break; | ||
826 | default: | ||
827 | pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", | ||
828 | cdb[2] & 0x3f, cdb[3]); | ||
829 | cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | offset += length; | ||
833 | |||
834 | if (ten) { | ||
835 | offset -= 2; | ||
836 | buf[0] = (offset >> 8) & 0xff; | ||
837 | buf[1] = offset & 0xff; | ||
838 | |||
839 | if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || | ||
840 | (cmd->se_deve && | ||
841 | (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) | ||
842 | spc_modesense_write_protect(&buf[3], type); | ||
843 | |||
844 | if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && | ||
845 | (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) | ||
846 | spc_modesense_dpofua(&buf[3], type); | ||
847 | |||
848 | if ((offset + 2) > cmd->data_length) | ||
849 | offset = cmd->data_length; | ||
850 | |||
851 | } else { | ||
852 | offset -= 1; | ||
853 | buf[0] = offset & 0xff; | ||
854 | |||
855 | if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || | ||
856 | (cmd->se_deve && | ||
857 | (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) | ||
858 | spc_modesense_write_protect(&buf[2], type); | ||
859 | |||
860 | if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && | ||
861 | (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) | ||
862 | spc_modesense_dpofua(&buf[2], type); | ||
863 | |||
864 | if ((offset + 1) > cmd->data_length) | ||
865 | offset = cmd->data_length; | ||
866 | } | ||
867 | |||
868 | rbuf = transport_kmap_data_sg(cmd); | ||
869 | memcpy(rbuf, buf, offset); | ||
870 | transport_kunmap_data_sg(cmd); | ||
871 | |||
872 | target_complete_cmd(cmd, GOOD); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int spc_emulate_request_sense(struct se_cmd *cmd) | ||
877 | { | ||
878 | unsigned char *cdb = cmd->t_task_cdb; | ||
879 | unsigned char *buf; | ||
880 | u8 ua_asc = 0, ua_ascq = 0; | ||
881 | int err = 0; | ||
882 | |||
883 | if (cdb[1] & 0x01) { | ||
884 | pr_err("REQUEST_SENSE description emulation not" | ||
885 | " supported\n"); | ||
886 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
887 | return -ENOSYS; | ||
888 | } | ||
889 | |||
890 | buf = transport_kmap_data_sg(cmd); | ||
891 | |||
892 | if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { | ||
893 | /* | ||
894 | * CURRENT ERROR, UNIT ATTENTION | ||
895 | */ | ||
896 | buf[0] = 0x70; | ||
897 | buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; | ||
898 | |||
899 | if (cmd->data_length < 18) { | ||
900 | buf[7] = 0x00; | ||
901 | err = -EINVAL; | ||
902 | goto end; | ||
903 | } | ||
904 | /* | ||
905 | * The Additional Sense Code (ASC) from the UNIT ATTENTION | ||
906 | */ | ||
907 | buf[SPC_ASC_KEY_OFFSET] = ua_asc; | ||
908 | buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; | ||
909 | buf[7] = 0x0A; | ||
910 | } else { | ||
911 | /* | ||
912 | * CURRENT ERROR, NO SENSE | ||
913 | */ | ||
914 | buf[0] = 0x70; | ||
915 | buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; | ||
916 | |||
917 | if (cmd->data_length < 18) { | ||
918 | buf[7] = 0x00; | ||
919 | err = -EINVAL; | ||
920 | goto end; | ||
921 | } | ||
922 | /* | ||
923 | * NO ADDITIONAL SENSE INFORMATION | ||
924 | */ | ||
925 | buf[SPC_ASC_KEY_OFFSET] = 0x00; | ||
926 | buf[7] = 0x0A; | ||
927 | } | ||
928 | |||
929 | end: | ||
930 | transport_kunmap_data_sg(cmd); | ||
931 | target_complete_cmd(cmd, GOOD); | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int spc_emulate_testunitready(struct se_cmd *cmd) | ||
936 | { | ||
937 | target_complete_cmd(cmd, GOOD); | ||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) | ||
43 | { | 942 | { |
44 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; | 943 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; |
45 | unsigned char *cdb = cmd->t_task_cdb; | 944 | unsigned char *cdb = cmd->t_task_cdb; |
@@ -53,13 +952,11 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) | |||
53 | break; | 952 | break; |
54 | case MODE_SENSE: | 953 | case MODE_SENSE: |
55 | *size = cdb[4]; | 954 | *size = cdb[4]; |
56 | if (!passthrough) | 955 | cmd->execute_cmd = spc_emulate_modesense; |
57 | cmd->execute_cmd = target_emulate_modesense; | ||
58 | break; | 956 | break; |
59 | case MODE_SENSE_10: | 957 | case MODE_SENSE_10: |
60 | *size = (cdb[7] << 8) + cdb[8]; | 958 | *size = (cdb[7] << 8) + cdb[8]; |
61 | if (!passthrough) | 959 | cmd->execute_cmd = spc_emulate_modesense; |
62 | cmd->execute_cmd = target_emulate_modesense; | ||
63 | break; | 960 | break; |
64 | case LOG_SELECT: | 961 | case LOG_SELECT: |
65 | case LOG_SENSE: | 962 | case LOG_SENSE: |
@@ -108,8 +1005,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) | |||
108 | break; | 1005 | break; |
109 | case REQUEST_SENSE: | 1006 | case REQUEST_SENSE: |
110 | *size = cdb[4]; | 1007 | *size = cdb[4]; |
111 | if (!passthrough) | 1008 | cmd->execute_cmd = spc_emulate_request_sense; |
112 | cmd->execute_cmd = target_emulate_request_sense; | ||
113 | break; | 1009 | break; |
114 | case INQUIRY: | 1010 | case INQUIRY: |
115 | *size = (cdb[3] << 8) + cdb[4]; | 1011 | *size = (cdb[3] << 8) + cdb[4]; |
@@ -120,8 +1016,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) | |||
120 | */ | 1016 | */ |
121 | if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) | 1017 | if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) |
122 | cmd->sam_task_attr = MSG_HEAD_TAG; | 1018 | cmd->sam_task_attr = MSG_HEAD_TAG; |
123 | if (!passthrough) | 1019 | cmd->execute_cmd = spc_emulate_inquiry; |
124 | cmd->execute_cmd = target_emulate_inquiry; | ||
125 | break; | 1020 | break; |
126 | case SECURITY_PROTOCOL_IN: | 1021 | case SECURITY_PROTOCOL_IN: |
127 | case SECURITY_PROTOCOL_OUT: | 1022 | case SECURITY_PROTOCOL_OUT: |
@@ -152,9 +1047,8 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) | |||
152 | cmd->sam_task_attr = MSG_HEAD_TAG; | 1047 | cmd->sam_task_attr = MSG_HEAD_TAG; |
153 | break; | 1048 | break; |
154 | case TEST_UNIT_READY: | 1049 | case TEST_UNIT_READY: |
1050 | cmd->execute_cmd = spc_emulate_testunitready; | ||
155 | *size = 0; | 1051 | *size = 0; |
156 | if (!passthrough) | ||
157 | cmd->execute_cmd = target_emulate_noop; | ||
158 | break; | 1052 | break; |
159 | default: | 1053 | default: |
160 | pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" | 1054 | pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" |