1 /*
2 * Copyright (c) 2008-2014 Douglas Gilbert.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 /*
31 * This file contains SCSI pass-through (pt) helper functions for ddpt.
32 */
33
34 /* Was needed for posix_fadvise() */
35 /* #define _XOPEN_SOURCE 600 */
36
37 /* Need _GNU_SOURCE for O_DIRECT */
38 #ifndef _GNU_SOURCE
39 #define _GNU_SOURCE
40 #endif
41
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #define __STDC_FORMAT_MACROS 1
53 #include <inttypes.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56
57 /* N.B. config.h must precede anything that depends on HAVE_* */
58 #ifdef HAVE_CONFIG_H
59 #include "config.h"
60 #endif
61
62 #include "ddpt.h" /* includes <signal.h> */
63
64 #include "sg_lib.h"
65 #include "sg_cmds_basic.h"
66 #include "sg_cmds_extra.h"
67 #include "sg_pt.h"
68
69 #define DDPT_READ6_OC 0x8
70 #define DDPT_READ10_OC 0x28
71 #define DDPT_READ12_OC 0xa8
72 #define DDPT_READ16_OC 0x88
73 #define DDPT_WRITE6_OC 0xa
74 #define DDPT_WRITE10_OC 0x2a
75 #define DDPT_WRITE12_OC 0xaa
76 #define DDPT_WRITE16_OC 0x8a
77 #define DDPT_WRITE_ATOMIC16_OC 0x9c /* sbc4r02 */
78 #define DDPT_WRITE_VERIFY10_OC 0x2e
79 #define DDPT_WRITE_VERIFY16_OC 0x8e
80 #define DDPT_VARIABLE_LEN_OC 0x7f
81 #define DDPT_READ32_SA 0x9
82 #define DDPT_WRITE32_SA 0xb
83 #define DDPT_TPC_OUT_CMD 0x83
84 #define DDPT_TPC_OUT_CMDLEN 16
85 #define DDPT_TPC_IN_CMD 0x84
86 #define DDPT_TPC_IN_CMDLEN 16
87
88 #define ASC_GENERAL_0 0x0
89 #define ASQ_OP_IN_PROGRESS 0x16
90
91 #define ASC_3PC_GEN 0xd
92 #define ASQ_TARGET_UNDERRUN 0x4
93 #define ASQ_TARGET_OVERRUN 0x5
94
95 #define ASC_PARAM_LST_LEN_ERR 0x1a /* only asq=00 defined */
96
97 #define ASC_INVALID_TOKOP 0x23
98 #define ASQ_TOKOP_UNK 0x0
99 /* There are 11 of these ASQs, just add asq to DDPT_CAT base */
100
101 #define ASC_INVALID_PARAM 0x26
102 #define ASQ_INVALID_FLD_IN_PARAM 0x0
103 #define ASQ_TOO_MANY_SEGS_IN_PARAM 0x8
104
105 #define ASC_CMDS_CLEARED 0x2f
106 #define ASQ_CMDS_CLEARED_BY_DEV_SVR 0x2
107
108 #define ASC_INSUFF_RES 0x55
109 #define ASQ_INSUFF_RES_CREATE_ROD 0xc
110 #define ASQ_INSUFF_RES_CREATE_RODTOK 0xd
111
112 #define DEF_PT_TIMEOUT 60 /* 60 seconds */
113
114
115 void *
pt_construct_obj(void)116 pt_construct_obj(void)
117 {
118 void * vp;
119
120 if (NULL == (vp = construct_scsi_pt_obj()))
121 pr2serr("construct_scsi_pt_obj: out of memory\n");
122 return vp;
123 }
124
125 void
pt_destruct_obj(void * vp)126 pt_destruct_obj(void * vp)
127 {
128 destruct_scsi_pt_obj((struct sg_pt_base *)vp);
129 }
130
131 /* Opens given device with the pass-through interface. If successful sends
132 * a standard INQUIRY request. Returns file descriptor (>=0) if successful,
133 * -1 if open fails, -2 if standard INQUIRY fails. */
134 int
pt_open_if(struct opts_t * op,struct sg_simple_inquiry_resp * sirp)135 pt_open_if(struct opts_t * op, struct sg_simple_inquiry_resp * sirp)
136 {
137 int verb, flags, fl, fd;
138 struct sg_simple_inquiry_resp sir;
139 struct flags_t * fp = op->iflagp;
140 struct dev_info_t * dip = op->idip;
141 const char * fn = op->idip->fn;
142
143 verb = (op->verbose ? op->verbose - 1: 0);
144 flags = fp->block ? 0 : O_NONBLOCK;
145 if (fp->direct)
146 flags |= O_DIRECT;
147 if (fp->excl)
148 flags |= O_EXCL;
149 if (fp->sync)
150 flags |= O_SYNC;
151 fl = op->o_readonly ? O_RDONLY : O_RDWR;
152 if ((fd = scsi_pt_open_flags(fn, (fl | flags), op->verbose)) < 0) {
153 if (-EBUSY == fd) {
154 pr2serr("open %s for pass-through reports BUSY,\n"
155 " use iflag=block to wait until ready\n", fn);
156 return -1;
157 }
158 if (op->o_readonly) {
159 pr2serr("could not open %s ro as pass-through: %s\n", fn,
160 safe_strerror(-fd));
161 return -1;
162 } else {
163 fl = O_RDONLY;
164 if (op->verbose)
165 pr2serr("could not open %s read-write so try read-only\n",
166 fn);
167 if ((fd = scsi_pt_open_flags(fn, (fl | flags), op->verbose))
168 < 0) {
169 pr2serr("could not open %s [rw or ro] as pass-through: %s\n",
170 fn, safe_strerror(-fd));
171 return -1;
172 }
173 }
174 }
175 if (sg_simple_inquiry(fd, &sir, 0, verb)) {
176 pr2serr("INQUIRY failed on %s\n", fn);
177 return -2;
178 }
179 dip->pdt = sir.peripheral_type;
180 if (op->verbose) {
181 if (op->has_xcopy || op->has_odx)
182 pr2serr(" %s: %.8s %.16s %.4s [pdt=%d, 3pc=%d]\n",
183 fn, sir.vendor, sir.product, sir.revision, dip->pdt,
184 !! (0x8 & sir.byte_5));
185 else
186 pr2serr(" %s: %.8s %.16s %.4s [pdt=%d]\n",
187 fn, sir.vendor, sir.product, sir.revision, dip->pdt);
188 }
189 if (sirp)
190 *sirp = sir;
191 return fd;
192 }
193
194 /* Opens given device with the pass-through interface. If successful sends
195 * a standard INQUIRY request. Returns file descriptor (>=0) if successful,
196 * -1 if open fails, -2 if standard INQUIRY fails. */
197 int
pt_open_of(struct opts_t * op,struct sg_simple_inquiry_resp * sirp)198 pt_open_of(struct opts_t * op, struct sg_simple_inquiry_resp * sirp)
199 {
200 int verb, flags, fd;
201 struct sg_simple_inquiry_resp sir;
202 struct flags_t * fp = op->oflagp;
203 struct dev_info_t * dip = op->odip;
204 const char * fn = dip->fn;
205
206 verb = (op->verbose ? op->verbose - 1: 0);
207 flags = fp->block ? 0 : O_NONBLOCK;
208 flags |= O_RDWR;
209 if (fp->direct)
210 flags |= O_DIRECT;
211 if (fp->excl)
212 flags |= O_EXCL;
213 if (fp->sync)
214 flags |= O_SYNC;
215 if ((fd = scsi_pt_open_flags(fn, flags, op->verbose)) < 0) {
216 if (-EBUSY == fd) {
217 pr2serr("open %s for pass-through reports BUSY,\n"
218 " use oflag=block to wait until ready\n", fn);
219 return -1;
220 }
221 pr2serr("could not open %s for pass-through: %s\n", fn,
222 safe_strerror(-fd));
223 return -1;
224 }
225 if (sg_simple_inquiry(fd, &sir, 0, verb)) {
226 pr2serr("INQUIRY failed on %s\n", fn);
227 return -2;
228 }
229 dip->pdt = sir.peripheral_type;
230 if (op->verbose) {
231 if (op->has_xcopy || op->has_odx)
232 pr2serr(" %s: %.8s %.16s %.4s [pdt=%d, 3pc=%d]\n",
233 fn, sir.vendor, sir.product, sir.revision, dip->pdt,
234 !! (0x8 & sir.byte_5));
235 else
236 pr2serr(" %s: %.8s %.16s %.4s [pdt=%d]\n",
237 fn, sir.vendor, sir.product, sir.revision, dip->pdt);
238 }
239 if (sirp)
240 *sirp = sir;
241 return fd;
242 }
243
244 void
pt_close(int fd)245 pt_close(int fd)
246 {
247 scsi_pt_close_device(fd);
248 }
249
250 /* Fetch number of blocks and block size of a pt device.
251 * Return of 0 -> success, see sg_ll_read_capacity*() otherwise. */
252 int
pt_read_capacity(struct opts_t * op,int in0_out1,int64_t * num_blks,int * blk_sz)253 pt_read_capacity(struct opts_t * op, int in0_out1, int64_t * num_blks,
254 int * blk_sz)
255 {
256 int k, res;
257 unsigned int ui;
258 unsigned char rcBuff[RCAP16_REPLY_LEN];
259 int verb;
260 int sg_fd = (in0_out1 ? op->odip->fd : op->idip->fd);
261 int protect = (in0_out1 ? op->wrprotect : op->rdprotect);
262
263 verb = (op->verbose ? op->verbose - 1: 0);
264 memset(rcBuff, 0, sizeof(rcBuff));
265 if (! protect) {
266 res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 1,
267 verb);
268 if (0 != res)
269 return res;
270 }
271
272 if (protect || ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) &&
273 (0xff == rcBuff[2]) && (0xff == rcBuff[3]))) {
274 int64_t ls;
275 int prot_typ = 0;
276 int p_i_exp = 0;
277
278 if (verb && ! protect)
279 pr2serr(" READ CAPACITY (10) response cannot represent this "
280 "capacity\n");
281 res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 1,
282 verb);
283 if (0 != res)
284 return res;
285 for (k = 0, ls = 0; k < 8; ++k) {
286 ls <<= 8;
287 ls |= rcBuff[k];
288 }
289 *num_blks = ls + 1;
290 *blk_sz = (rcBuff[8] << 24) | (rcBuff[9] << 16) |
291 (rcBuff[10] << 8) | rcBuff[11];
292 if (rcBuff[12] & 0x1) { /* PROT_EN */
293 prot_typ = ((rcBuff[12] >> 1) & 0x7) + 1;
294 p_i_exp = ((rcBuff[13] >> 4) & 0xf);
295 }
296 if (in0_out1) {
297 op->odip->prot_type = prot_typ;
298 op->odip->p_i_exp = p_i_exp;
299 } else {
300 op->idip->prot_type = prot_typ;
301 op->idip->p_i_exp = p_i_exp;
302 }
303 } else {
304 ui = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) |
305 rcBuff[3]);
306 /* take care not to sign extend values > 0x7fffffff */
307 *num_blks = (int64_t)ui + 1;
308 *blk_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
309 (rcBuff[6] << 8) | rcBuff[7];
310 }
311 return 0;
312 }
313
314 /* Build a SCSI READ or WRITE CDB. */
315 static int
pt_build_scsi_cdb(unsigned char * cdbp,int cdb_sz,unsigned int blocks,int64_t start_block,int write_true,const struct flags_t * fp,int protect)316 pt_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks,
317 int64_t start_block, int write_true,
318 const struct flags_t * fp, int protect)
319 {
320 int rd_opcode[] = {DDPT_READ6_OC, DDPT_READ10_OC, DDPT_READ12_OC,
321 DDPT_READ16_OC, DDPT_READ32_SA};
322 int wr_opcode[] = {DDPT_WRITE6_OC, DDPT_WRITE10_OC, DDPT_WRITE12_OC,
323 DDPT_WRITE16_OC, DDPT_WRITE32_SA};
324 int opcode_sa, options_byte, rw_sa;
325 int * opc_arr;
326
327 if (cdb_sz < 6) {
328 pr2serr("cdb_sz too small\n");
329 return 1;
330 }
331 memset(cdbp, 0, cdb_sz);
332 opcode_sa = 0;
333 options_byte = 0;
334 opc_arr = NULL;
335
336 if (write_true) {
337 if (fp->atomic) {
338 if (16 == cdb_sz)
339 opcode_sa = DDPT_WRITE_ATOMIC16_OC;
340 else {
341 pr2serr("atomic flag only for WRITE_ATOMIC(16)\n");
342 return 1;
343 }
344 } else if (fp->verify) {
345 if (10 == cdb_sz)
346 opcode_sa = DDPT_WRITE_VERIFY10_OC;
347 else if (16 == cdb_sz)
348 opcode_sa = DDPT_WRITE_VERIFY16_OC;
349 else {
350 pr2serr("verify flag for WRITE AND VERIFY (10 or 16) only\n");
351 return 1;
352 }
353 } else
354 opc_arr = wr_opcode;
355 } else { /* a READ */
356 opc_arr = rd_opcode;
357 if (fp->rarc)
358 options_byte |= 0x4;
359 }
360
361 if (cdb_sz > 6) {
362 if (fp->dpo)
363 options_byte |= 0x10;
364 if (fp->verify && write_true) {
365 if (fp->bytchk)
366 options_byte |= ((fp->bytchk & 0x3) << 1);
367 } else {
368 if (fp->fua)
369 options_byte |= 0x8;
370 if (fp->fua_nv)
371 options_byte |= 0x2;
372 }
373 if (protect)
374 options_byte |= ((protect & 0x7) << 5);
375 }
376
377 switch (cdb_sz) {
378 case 6:
379 if (0 == opcode_sa)
380 opcode_sa = opc_arr[0];
381 cdbp[0] = (unsigned char)opcode_sa;
382 cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f);
383 cdbp[2] = (unsigned char)((start_block >> 8) & 0xff);
384 cdbp[3] = (unsigned char)(start_block & 0xff);
385 cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks;
386 if (blocks > 256) {
387 pr2serr("for 6 byte commands, maximum number of blocks is 256\n");
388 return 1;
389 }
390 if ((start_block + blocks - 1) & (~0x1fffff)) {
391 pr2serr("for 6 byte commands, can't address blocks beyond %d\n",
392 0x1fffff);
393 return 1;
394 }
395 if (fp->dpo || fp->fua || fp->rarc) {
396 pr2serr("for 6 byte commands, neither dpo, fua, nor rarc bits "
397 "supported\n");
398 return 1;
399 }
400 break;
401 case 10:
402 if (0 == opcode_sa)
403 opcode_sa = opc_arr[1];
404 cdbp[0] = (unsigned char)opcode_sa;
405 cdbp[1] = (unsigned char)options_byte;
406 cdbp[2] = (unsigned char)((start_block >> 24) & 0xff);
407 cdbp[3] = (unsigned char)((start_block >> 16) & 0xff);
408 cdbp[4] = (unsigned char)((start_block >> 8) & 0xff);
409 cdbp[5] = (unsigned char)(start_block & 0xff);
410 cdbp[7] = (unsigned char)((blocks >> 8) & 0xff);
411 cdbp[8] = (unsigned char)(blocks & 0xff);
412 if (blocks & (~0xffff)) {
413 pr2serr("for 10 byte commands, maximum number of blocks is %d\n",
414 0xffff);
415 return 1;
416 }
417 break;
418 case 12:
419 if (0 == opcode_sa)
420 opcode_sa = opc_arr[2];
421 cdbp[0] = (unsigned char)opcode_sa;
422 cdbp[1] = (unsigned char)options_byte;
423 cdbp[2] = (unsigned char)((start_block >> 24) & 0xff);
424 cdbp[3] = (unsigned char)((start_block >> 16) & 0xff);
425 cdbp[4] = (unsigned char)((start_block >> 8) & 0xff);
426 cdbp[5] = (unsigned char)(start_block & 0xff);
427 cdbp[6] = (unsigned char)((blocks >> 24) & 0xff);
428 cdbp[7] = (unsigned char)((blocks >> 16) & 0xff);
429 cdbp[8] = (unsigned char)((blocks >> 8) & 0xff);
430 cdbp[9] = (unsigned char)(blocks & 0xff);
431 break;
432 case 16:
433 if (0 == opcode_sa)
434 opcode_sa = opc_arr[3];
435 cdbp[0] = (unsigned char)opcode_sa;
436 cdbp[1] = (unsigned char)options_byte;
437 cdbp[2] = (unsigned char)((start_block >> 56) & 0xff);
438 cdbp[3] = (unsigned char)((start_block >> 48) & 0xff);
439 cdbp[4] = (unsigned char)((start_block >> 40) & 0xff);
440 cdbp[5] = (unsigned char)((start_block >> 32) & 0xff);
441 cdbp[6] = (unsigned char)((start_block >> 24) & 0xff);
442 cdbp[7] = (unsigned char)((start_block >> 16) & 0xff);
443 cdbp[8] = (unsigned char)((start_block >> 8) & 0xff);
444 cdbp[9] = (unsigned char)(start_block & 0xff);
445 cdbp[10] = (unsigned char)((blocks >> 24) & 0xff);
446 cdbp[11] = (unsigned char)((blocks >> 16) & 0xff);
447 cdbp[12] = (unsigned char)((blocks >> 8) & 0xff);
448 cdbp[13] = (unsigned char)(blocks & 0xff);
449 break;
450 case 32:
451 if (0 == opcode_sa)
452 opcode_sa = opc_arr[4];
453 cdbp[0] = (unsigned char)DDPT_VARIABLE_LEN_OC;
454 cdbp[7] = (unsigned char)0x18; /* additional length=>32 byte cdb */
455 rw_sa = opcode_sa;
456 cdbp[8] = (unsigned char)((rw_sa >> 8) & 0xff);
457 cdbp[9] = (unsigned char)(rw_sa & 0xff);
458 cdbp[10] = (unsigned char)options_byte;
459 cdbp[12] = (unsigned char)((start_block >> 56) & 0xff);
460 cdbp[13] = (unsigned char)((start_block >> 48) & 0xff);
461 cdbp[14] = (unsigned char)((start_block >> 40) & 0xff);
462 cdbp[15] = (unsigned char)((start_block >> 32) & 0xff);
463 cdbp[16] = (unsigned char)((start_block >> 24) & 0xff);
464 cdbp[17] = (unsigned char)((start_block >> 16) & 0xff);
465 cdbp[18] = (unsigned char)((start_block >> 8) & 0xff);
466 cdbp[19] = (unsigned char)(start_block & 0xff);
467 cdbp[28] = (unsigned char)((blocks >> 24) & 0xff);
468 cdbp[29] = (unsigned char)((blocks >> 16) & 0xff);
469 cdbp[30] = (unsigned char)((blocks >> 8) & 0xff);
470 cdbp[31] = (unsigned char)(blocks & 0xff);
471 break;
472 default:
473 pr2serr("expected cdb size of 6, 10, 12, 16 or 32 but got %d\n",
474 cdb_sz);
475 return 1;
476 }
477 return 0;
478 }
479
480 /* Read using the pass-through. No retries or remedial work here.
481 * 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb,
482 * SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> 'io_addrp' written to,
483 * SG_LIB_CAT_MEDIUM_HARD -> no info field,
484 * plus various other SG_LIB_CAT_* positive values,
485 * -2 -> ENOMEM
486 * -1 other errors */
487 static int
pt_low_read(struct opts_t * op,int in0_out1,unsigned char * buff,int blocks,int64_t from_block,int bs,uint64_t * io_addrp)488 pt_low_read(struct opts_t * op, int in0_out1, unsigned char * buff,
489 int blocks, int64_t from_block, int bs,
490 uint64_t * io_addrp)
491 {
492 unsigned char rdCmd[MAX_SCSI_CDBSZ];
493 unsigned char sense_b[SENSE_BUFF_LEN];
494 int res, k, info_valid, slen, sense_cat, ret, vt;
495 struct sg_pt_base * ptvp = (in0_out1 ? op->odip->ptvp : op->idip->ptvp);
496 const struct flags_t * fp = (in0_out1 ? op->oflagp : op->iflagp);
497 const struct dev_info_t * dip = (in0_out1 ? op->odip : op->idip);
498 int protect = (in0_out1 ? op->wrprotect : op->rdprotect);
499 struct sg_scsi_sense_hdr ssh;
500
501 if (pt_build_scsi_cdb(rdCmd, fp->cdbsz, blocks, from_block, 0,
502 fp, protect)) {
503 pr2serr("bad rd cdb build, from_block=%" PRId64 ", blocks=%d\n",
504 from_block, blocks);
505 return SG_LIB_SYNTAX_ERROR;
506 }
507 if (op->verbose > 2) {
508 pr2serr(" READ cdb: ");
509 for (k = 0; k < fp->cdbsz; ++k)
510 pr2serr("%02x ", rdCmd[k]);
511 pr2serr("\n");
512 }
513
514 if (NULL == ptvp) {
515 pr2serr("pt_low_read: ptvp NULL?\n");
516 return -1;
517 }
518 clear_scsi_pt_obj(ptvp);
519 set_scsi_pt_cdb(ptvp, rdCmd, fp->cdbsz);
520 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
521 set_scsi_pt_data_in(ptvp, buff, bs * blocks);
522 #ifdef SCSI_PT_FLAGS_FUNCTION
523 set_scsi_pt_flags(ptvp, SCSI_PT_FLAGS_QUEUE_AT_TAIL);
524 #endif
525 vt = (op->verbose ? (op->verbose - 1) : 0);
526 while (((res = do_scsi_pt(ptvp, dip->fd, DEF_RW_TIMEOUT, vt)) < 0) &&
527 (-EINTR == res))
528 ++op->interrupted_retries; /* resubmit if interrupted system call */
529
530 vt = ((op->verbose > 1) ? (op->verbose - 1) : op->verbose);
531 ret = sg_cmds_process_resp(ptvp, "READ", res, bs * blocks, sense_b,
532 0 /* noisy */, vt, &sense_cat);
533 if (-1 == ret)
534 ;
535 else if (-2 == ret) {
536 slen = get_scsi_pt_sense_len(ptvp);
537 ret = sense_cat;
538
539 switch (sense_cat) {
540 case SG_LIB_CAT_NOT_READY:
541 case SG_LIB_CAT_INVALID_OP:
542 case SG_LIB_CAT_RES_CONFLICT:
543 case SG_LIB_CAT_DATA_PROTECT:
544 case SG_LIB_CAT_ABORTED_COMMAND:
545 ++op->unrecovered_errs;
546 break;
547 case SG_LIB_CAT_UNIT_ATTENTION:
548 break;
549 case SG_LIB_CAT_PROTECTION:
550 /* no retry, might have INFO field */
551 ++op->unrecovered_errs;
552 info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp);
553 if (info_valid)
554 ret = SG_LIB_CAT_PROTECTION_WITH_INFO;
555 break;
556 case SG_LIB_CAT_RECOVERED:
557 ++op->recovered_errs;
558 info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp);
559 if (info_valid)
560 pr2serr(" lba of last recovered error in this READ=0x%"
561 PRIx64 "\n", *io_addrp);
562 else
563 pr2serr("Recovered error: [no info] reading from block=0x%"
564 PRIx64 ", num=%d\n", from_block, blocks);
565 break;
566 case SG_LIB_CAT_MEDIUM_HARD:
567 ++op->unrecovered_errs;
568 info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp);
569 /* MMC and MO devices don't necessarily set VALID bit */
570 if (info_valid || ((*io_addrp > 0) &&
571 ((5 == dip->pdt) || (7 == dip->pdt))))
572 ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; // <<<<<<<<<<<<
573 else
574 pr2serr("Medium, hardware or blank check error but no lba "
575 "of failure in sense data\n");
576 break;
577 case SG_LIB_CAT_NO_SENSE:
578 ret = 0;
579 break;
580 case SG_LIB_CAT_ILLEGAL_REQ:
581 if (5 == dip->pdt) { /* MMC READs can go down this path */
582 int ili;
583
584 if (sg_scsi_normalize_sense(sense_b, slen, &ssh) &&
585 (0x64 == ssh.asc) && (0x0 == ssh.ascq)) {
586 if (sg_get_sense_filemark_eom_ili(sense_b, slen, NULL,
587 NULL, &ili) && ili) {
588 info_valid = sg_get_sense_info_fld(sense_b, slen,
589 io_addrp);
590 if (*io_addrp > 0) {
591 ++op->unrecovered_errs;
592 ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;
593 } else
594 pr2serr("MMC READ gave 'illegal mode for this "
595 "track' and ILI but no LBA of failure\n");
596 }
597 ++op->unrecovered_errs;
598 ret = SG_LIB_CAT_MEDIUM_HARD;
599 }
600 }
601 default:
602 break;
603 }
604 } else
605 ret = 0;
606
607 /* We are going to re-read those good blocks */
608 if ((SG_LIB_CAT_MEDIUM_HARD_WITH_INFO != ret) &&
609 (SG_LIB_CAT_PROTECTION_WITH_INFO != ret))
610 op->sum_of_resids += get_scsi_pt_resid(ptvp);
611 return ret;
612 }
613
614 /* Control pass-through read retries and coe (continue on error).
615 * Fast path is a call to pt_low_read() that succeeds. If medium
616 * error then back up and re-read good blocks prior to bad block;
617 * then, if coe, use zero for bad block and continue reading at
618 * the next LBA (N.B. more medium errors could occur).
619 * 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb,
620 * SG_LIB_CAT_UNIT_ATTENTION -> try again, SG_LIB_CAT_NOT_READY,
621 * SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_ABORTED_COMMAND,
622 * -2 -> ENOMEM, -1 other errors */
623 int
pt_read(struct opts_t * op,int in0_out1,unsigned char * buff,int blocks,int * blks_readp)624 pt_read(struct opts_t * op, int in0_out1, unsigned char * buff, int blocks,
625 int * blks_readp)
626 {
627 uint64_t io_addr;
628 int64_t from_block;
629 int64_t lba;
630 int bs;
631 struct flags_t * fp;
632 int res, blks, use_io_addr, xferred, pi_len;
633 unsigned char * bp;
634 int retries_tmp;
635 int ret = 0;
636 int may_coe = 0;
637 const char * iop;
638
639 if (in0_out1) {
640 from_block = op->seek;
641 bs = op->obs_pi;
642 pi_len = op->obs_pi - op->obs;
643 fp = op->oflagp;
644 iop = "ofile";
645 } else {
646 from_block = op->skip;
647 bs = op->ibs_pi;
648 pi_len = op->ibs_pi - op->ibs;
649 fp = op->iflagp;
650 iop = "ifile";
651 }
652 retries_tmp = fp->retries;
653 for (xferred = 0, blks = blocks, lba = from_block, bp = buff;
654 blks > 0; blks = blocks - xferred) {
655 io_addr = 0;
656 use_io_addr = 0;
657 may_coe = 0;
658 res = pt_low_read(op, in0_out1, bp, blks, lba, bs, &io_addr);
659 switch (res) {
660 case 0: /* this is the fast path after good pt_low_read() */
661 if (blks_readp)
662 *blks_readp = xferred + blks;
663 if (0 == in0_out1)
664 zero_coe_limit_count(op);
665 return 0;
666 case -2: /* ENOMEM */
667 return res;
668 case SG_LIB_CAT_NOT_READY:
669 pr2serr("%s: Device not ready [%s]\n", __func__, iop);
670 return res;
671 case SG_LIB_CAT_ABORTED_COMMAND:
672 if (--op->max_aborted > 0)
673 pr2serr("%s: Aborted command, continuing [%s]\n", __func__,
674 iop);
675 else {
676 pr2serr("%s: Aborted command, too many [%s]\n", __func__,
677 iop);
678 return res;
679 }
680 break;
681 case SG_LIB_CAT_UNIT_ATTENTION:
682 if (--op->max_uas > 0)
683 pr2serr("%s: Unit attention, continuing [%s]\n", __func__,
684 iop);
685 else {
686 pr2serr("%s: Unit attention, too many [%s]\n", __func__,
687 iop);
688 return res;
689 }
690 break;
691 case SG_LIB_CAT_PROTECTION_WITH_INFO:
692 use_io_addr = 1;
693 ret = res;
694 break; /* unrecovered read error at lba=io_addr */
695 case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:
696 if (retries_tmp > 0) {
697 pr2serr(">>> retrying pt read: starting lba=%" PRId64 " [0x%"
698 PRIx64 "] blocks=%d\n", lba, (uint64_t)lba, blks);
699 --retries_tmp;
700 ++op->num_retries;
701 if (op->unrecovered_errs > 0)
702 --op->unrecovered_errs;
703 } else
704 use_io_addr = 1;
705 ret = SG_LIB_CAT_MEDIUM_HARD;
706 break; /* unrecovered read error at lba=io_addr */
707 case SG_LIB_SYNTAX_ERROR:
708 fp->coe = 0;
709 ret = res;
710 goto err_out;
711 case -1:
712 ret = res;
713 goto err_out;
714 case SG_LIB_CAT_MEDIUM_HARD:
715 may_coe = 1;
716 /* No VALID+INFO field but we know the range of lba_s */
717 if (0 == retries_tmp)
718 errblk_put_range(lba, blks, op);
719 /* fall through */
720 case SG_LIB_CAT_RES_CONFLICT:
721 case SG_LIB_CAT_DATA_PROTECT:
722 case SG_LIB_CAT_PROTECTION:
723 default:
724 if (retries_tmp > 0) {
725 pr2serr(">>> retrying pt read: starting lba=%" PRId64 " [0x%"
726 PRIx64 "] blocks=%d\n", lba, (uint64_t)lba, blks);
727 --retries_tmp;
728 ++op->num_retries;
729 if (op->unrecovered_errs > 0)
730 --op->unrecovered_errs;
731 break;
732 }
733 ret = res;
734 goto err_out;
735 }
736 if (! use_io_addr)
737 continue;
738 if ((io_addr < (uint64_t)lba) ||
739 (io_addr >= (uint64_t)(lba + blks))) {
740 pr2serr(" Unrecovered error lba 0x%" PRIx64 " not in "
741 "correct range:\n\t[0x%" PRIx64 ",0x%" PRIx64 "]\n",
742 io_addr, (uint64_t)lba, (uint64_t)(lba + blks - 1));
743 may_coe = 1;
744 goto err_out;
745 }
746 if (op->highest_unrecovered < 0) {
747 op->highest_unrecovered = io_addr;
748 op->lowest_unrecovered = io_addr;
749 } else {
750 if ((int64_t)io_addr < op->lowest_unrecovered)
751 op->lowest_unrecovered = io_addr;
752 if ((int64_t)io_addr > op->highest_unrecovered)
753 op->highest_unrecovered = io_addr;
754 }
755 errblk_put(io_addr, op);
756 if (fp->coe) {
757 ++op->in_partial;
758 --op->in_full;
759 }
760 blks = (int)(io_addr - (uint64_t)lba);
761 if (blks > 0) {
762 if (op->verbose)
763 pr2serr(" partial re-read of %d blocks prior to medium "
764 "error\n", blks);
765 res = pt_low_read(op, in0_out1, bp, blks, lba, bs, &io_addr);
766 switch (res) {
767 case 0:
768 break;
769 case -1:
770 fp->coe = 0;
771 ret = res;
772 goto err_out;
773 case -2:
774 pr2serr("%s: ENOMEM again, unexpected [%s]\n", __func__, iop);
775 return -1;
776 case SG_LIB_CAT_NOT_READY:
777 pr2serr("%s: device not ready [%s]\n", __func__, iop);
778 return res;
779 case SG_LIB_CAT_UNIT_ATTENTION:
780 pr2serr("%s: Unit attention, unexpected [%s]\n", __func__,
781 iop);
782 return res;
783 case SG_LIB_CAT_ABORTED_COMMAND:
784 pr2serr("%s: Aborted command, unexpected [%s]\n", __func__,
785 iop);
786 return res;
787 case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:
788 case SG_LIB_CAT_MEDIUM_HARD:
789 ret = SG_LIB_CAT_MEDIUM_HARD;
790 goto err_out;
791 case SG_LIB_CAT_PROTECTION_WITH_INFO:
792 case SG_LIB_CAT_PROTECTION:
793 ret = SG_LIB_CAT_PROTECTION;
794 goto err_out;
795 case SG_LIB_SYNTAX_ERROR:
796 default:
797 pr2serr(">> unexpected result=%d from pt_low_read() 2 [%s]\n",
798 res, iop);
799 ret = res;
800 goto err_out;
801 }
802 }
803 xferred += blks;
804 if (0 == fp->coe) {
805 /* give up at block before problem unless 'coe' */
806 if (blks_readp)
807 *blks_readp = xferred;
808 return ret;
809 }
810 bp += (blks * bs);
811 lba += blks;
812 pr2serr(">> unrecovered read error at blk=%" PRId64 ", substitute "
813 "zeros%s\n", lba, ((pi_len > 0) ? " (PI with 0xFFs)" : ""));
814 if (pi_len > 0) {
815 memset(bp, 0, bs - pi_len);
816 memset(bp + bs - pi_len, 0xff, pi_len);
817 } else
818 memset(bp, 0, bs);
819 ++xferred;
820 bp += bs;
821 ++lba;
822 if ((op->coe_limit > 0) && (++op->coe_count > op->coe_limit)) {
823 if (blks_readp)
824 *blks_readp = xferred + blks;
825 pr2serr(">> coe_limit on consecutive reads exceeded\n");
826 return SG_LIB_CAT_MEDIUM_HARD;
827 }
828 retries_tmp = fp->retries;
829 }
830 if (blks_readp)
831 *blks_readp = xferred;
832 return 0;
833
834 err_out:
835 if (fp->coe) {
836 memset(bp, 0, bs * blks);
837 pr2serr(">> unable to read at blk=%" PRId64 " for %d bytes, use "
838 "zeros\n", lba, bs * blks);
839 if (blks > 1)
840 pr2serr(">> try reducing bpt to limit number of zeros written "
841 "near bad block(s)\n");
842 /* fudge success */
843 if (blks_readp)
844 *blks_readp = xferred + blks;
845 if ((op->coe_limit > 0) && (++op->coe_count > op->coe_limit)) {
846 pr2serr(">> coe_limit on consecutive reads exceeded\n");
847 return ret;
848 }
849 return may_coe ? 0 : ret;
850 } else
851 return ret ? ret : -1;
852 }
853
854
855 /* Write block(s) via the pass-through.
856 * 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb,
857 * SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_MEDIUM_HARD,
858 * SG_LIB_CAT_ABORTED_COMMAND, -2 -> recoverable (ENOMEM),
859 * -1 -> unrecoverable error + others */
860 static int
pt_low_write(struct opts_t * op,const unsigned char * buff,int blocks,int64_t to_block,int bs)861 pt_low_write(struct opts_t * op, const unsigned char * buff, int blocks,
862 int64_t to_block, int bs)
863 {
864 unsigned char wrCmd[MAX_SCSI_CDBSZ];
865 unsigned char sense_b[SENSE_BUFF_LEN];
866 int res, k, info_valid, ret, sense_cat, slen, vt;
867 int sg_fd = op->odip->fd;
868 uint64_t io_addr = 0;
869 struct sg_pt_base * ptvp = op->odip->ptvp;
870 const struct flags_t * fp = op->oflagp;
871 const char * desc;
872
873 if (pt_build_scsi_cdb(wrCmd, fp->cdbsz, blocks, to_block, 1, fp,
874 op->wrprotect)) {
875 pr2serr("bad wr cdb build, to_block=%" PRId64 ", blocks=%d\n",
876 to_block, blocks);
877 return SG_LIB_SYNTAX_ERROR;
878 }
879 if (DDPT_WRITE_ATOMIC16_OC == wrCmd[0])
880 desc = "WRITE ATOMIC(16)";
881 else if (0xe == (0xf & wrCmd[0]))
882 desc = "WRITE AND VERIFY";
883 else
884 desc = "WRITE";
885 if (op->verbose > 2) {
886 pr2serr(" %s cdb: ", desc);
887 for (k = 0; k < fp->cdbsz; ++k)
888 pr2serr("%02x ", wrCmd[k]);
889 pr2serr("\n");
890 }
891
892 if (NULL == ptvp) {
893 pr2serr("pt_low_write: of_ptvp NULL?\n");
894 return -1;
895 }
896 clear_scsi_pt_obj(ptvp);
897 set_scsi_pt_cdb(ptvp, wrCmd, fp->cdbsz);
898 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
899 set_scsi_pt_data_out(ptvp, buff, bs * blocks);
900 #ifdef SCSI_PT_FLAGS_FUNCTION
901 set_scsi_pt_flags(ptvp, SCSI_PT_FLAGS_QUEUE_AT_TAIL);
902 #endif
903 vt = (op->verbose ? (op->verbose - 1) : 0);
904 while (((res = do_scsi_pt(ptvp, sg_fd, DEF_RW_TIMEOUT, vt)) < 0) &&
905 (-EINTR == res))
906 ++op->interrupted_retries; /* resubmit if interrupted system call */
907
908 vt = ((op->verbose > 1) ? (op->verbose - 1) : op->verbose);
909 ret = sg_cmds_process_resp(ptvp, desc, res, bs * blocks, sense_b,
910 0 /* noisy */, vt, &sense_cat);
911 if (-1 == ret)
912 ;
913 else if (-2 == ret) {
914 slen = get_scsi_pt_sense_len(ptvp);
915 ret = sense_cat;
916
917 switch (sense_cat) {
918 case SG_LIB_CAT_RECOVERED:
919 ++op->wr_recovered_errs;
920 info_valid = sg_get_sense_info_fld(sense_b, slen, &io_addr);
921 if (info_valid)
922 pr2serr(" lba of last recovered error in this WRITE=0x%"
923 PRIx64 "\n", io_addr);
924 else
925 pr2serr("Recovered error: [no info] writing to block=0x%"
926 PRIx64 ", num=%d\n", to_block, blocks);
927 break;
928 case SG_LIB_CAT_ABORTED_COMMAND:
929 case SG_LIB_CAT_UNIT_ATTENTION:
930 break;
931 case SG_LIB_CAT_NOT_READY:
932 case SG_LIB_CAT_ILLEGAL_REQ:
933 case SG_LIB_CAT_INVALID_OP:
934 case SG_LIB_CAT_SENSE:
935 case SG_LIB_CAT_RES_CONFLICT:
936 case SG_LIB_CAT_DATA_PROTECT:
937 case SG_LIB_CAT_PROTECTION:
938 ++op->wr_unrecovered_errs;
939 break;
940 case SG_LIB_CAT_MEDIUM_HARD:
941 default:
942 ++op->wr_unrecovered_errs;
943 if (fp->coe) {
944 pr2serr(">> ignored errors for out blk=%" PRId64 " for %d "
945 "bytes\n", to_block, bs * blocks);
946 ret = 0; /* fudge success */
947 }
948 break;
949 }
950 } else
951 ret = 0;
952 return ret;
953 }
954
955
956 /* Control pass-through write retries.
957 * 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb,
958 * SG_LIB_CAT_UNIT_ATTENTION -> try again, SG_LIB_CAT_NOT_READY,
959 * SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_ABORTED_COMMAND,
960 * -2 -> ENOMEM, -1 other errors */
961 int
pt_write(struct opts_t * op,const unsigned char * buff,int blocks,int64_t to_block)962 pt_write(struct opts_t * op, const unsigned char * buff, int blocks,
963 int64_t to_block)
964 {
965 int retries_tmp;
966 int first = 1;
967 int ret = 0;
968 int bs = op->obs_pi;
969
970 retries_tmp = op->oflagp->retries;
971 while (1) {
972 ret = pt_low_write(op, buff, blocks, to_block, bs);
973 if (0 == ret)
974 break;
975 if ((SG_LIB_CAT_NOT_READY == ret) ||
976 (SG_LIB_SYNTAX_ERROR == ret))
977 break;
978 else if ((SG_LIB_CAT_UNIT_ATTENTION == ret) && first) {
979 if (--op->max_uas > 0)
980 pr2serr("Unit attention, continuing (w)\n");
981 else {
982 pr2serr("Unit attention, too many (w)\n");
983 break;
984 }
985 } else if ((SG_LIB_CAT_ABORTED_COMMAND == ret) && first) {
986 if (--op->max_aborted > 0)
987 pr2serr("Aborted command, continuing (w)\n");
988 else {
989 pr2serr("Aborted command, too many (w)\n");
990 break;
991 }
992 } else if (ret < 0)
993 break;
994 else if (retries_tmp > 0) {
995 pr2serr(">>> retrying pt write: starting lba=%" PRId64 " [0x%"
996 PRIx64 "] blocks=%d\n", to_block, (uint64_t)to_block,
997 blocks);
998 --retries_tmp;
999 ++op->num_retries;
1000 if (op->wr_unrecovered_errs > 0)
1001 --op->wr_unrecovered_errs;
1002 } else
1003 break;
1004 first = 0;
1005 }
1006 return ret;
1007 }
1008
1009 /* This function performs a "trim" on a pt device. In the SCSI command set
1010 * this is either done with the UNMAP command or WRITE SAME command. This
1011 * function uses WRITE SAME(16) with the unmap bit set. In Linux libata
1012 * translates this to the ATA DATA SET MANAGEMENT command with the trim
1013 * field set. Returns 0 on success. */
1014 int
pt_write_same16(struct opts_t * op,const unsigned char * buff,int bs,int blocks,int64_t start_block)1015 pt_write_same16(struct opts_t * op, const unsigned char * buff, int bs,
1016 int blocks, int64_t start_block)
1017 {
1018 int k, ret, res, sense_cat, vt;
1019 uint64_t llba;
1020 uint32_t unum;
1021 unsigned char wsCmdBlk[16];
1022 unsigned char sense_b[SENSE_BUFF_LEN];
1023 struct sg_pt_base * ptvp = op->odip->ptvp;
1024 int sg_fd = op->odip->fd;
1025
1026 memset(wsCmdBlk, 0, sizeof(wsCmdBlk));
1027 wsCmdBlk[0] = 0x93; /* WRITE SAME(16) opcode */
1028 /* set UNMAP; clear wrprotect, anchor, pbdata, lbdata */
1029 wsCmdBlk[1] = 0x8;
1030 llba = start_block;
1031 for (k = 7; k >= 0; --k) {
1032 wsCmdBlk[2 + k] = (llba & 0xff);
1033 llba >>= 8;
1034 }
1035 unum = blocks;
1036 for (k = 3; k >= 0; --k) {
1037 wsCmdBlk[10 + k] = (unum & 0xff);
1038 unum >>= 8;
1039 }
1040 if (op->verbose > 2) {
1041 pr2serr(" WRITE SAME(16) cdb: ");
1042 for (k = 0; k < (int)sizeof(wsCmdBlk); ++k)
1043 pr2serr("%02x ", wsCmdBlk[k]);
1044 pr2serr("\n");
1045 if (op->verbose > 4)
1046 pr2serr(" Data-out buffer length=%d\n", bs);
1047 }
1048
1049 if (NULL == ptvp) {
1050 pr2serr("pt_write_same16: ptvp NULL?\n");
1051 return -1;
1052 }
1053 clear_scsi_pt_obj(ptvp);
1054 set_scsi_pt_cdb(ptvp, wsCmdBlk, sizeof(wsCmdBlk));
1055 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1056 set_scsi_pt_data_out(ptvp, buff, bs);
1057 vt = ((op->verbose > 1) ? (op->verbose - 1) : 0);
1058 while (((res = do_scsi_pt(ptvp, sg_fd, WRITE_SAME16_TIMEOUT, vt)) < 0) &&
1059 (-EINTR == res))
1060 ++op->interrupted_retries; /* resubmit if interrupted system call */
1061 ret = sg_cmds_process_resp(ptvp, "Write same(16)", res, 0, sense_b,
1062 1 /*noisy */, vt, &sense_cat);
1063 if (-1 == ret)
1064 ;
1065 else if (-2 == ret) {
1066 switch (sense_cat) {
1067 case SG_LIB_CAT_RECOVERED:
1068 case SG_LIB_CAT_NO_SENSE:
1069 ret = 0;
1070 break;
1071 case SG_LIB_CAT_MEDIUM_HARD:
1072 {
1073 int valid, slen;
1074 uint64_t ull = 0;
1075
1076 slen = get_scsi_pt_sense_len(ptvp);
1077 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1078 if (valid)
1079 pr2serr("Medium or hardware error starting at lba=%"
1080 PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
1081 }
1082 ret = sense_cat;
1083 break;
1084 default:
1085 ret = sense_cat;
1086 break;
1087 }
1088 } else
1089 ret = 0;
1090
1091 return ret;
1092 }
1093
1094 void
pt_sync_cache(int fd)1095 pt_sync_cache(int fd)
1096 {
1097 int res;
1098
1099 res = sg_ll_sync_cache_10(fd, 0, 0, 0, 0, 0, 1, 0);
1100 if (SG_LIB_CAT_UNIT_ATTENTION == res) {
1101 pr2serr("Unit attention (out, sync cache), continuing\n");
1102 res = sg_ll_sync_cache_10(fd, 0, 0, 0, 0, 0, 1, 0);
1103 }
1104 if (0 != res)
1105 pr2serr("Unable to do SCSI synchronize cache\n");
1106 }
1107
1108 static int
pt_tpc_process_res(int cp_ret,int sense_cat,const unsigned char * sense_b,int sense_len)1109 pt_tpc_process_res(int cp_ret, int sense_cat, const unsigned char * sense_b,
1110 int sense_len)
1111 {
1112 int ret, sb_ok;
1113
1114 if (-1 == cp_ret)
1115 ret = -1;
1116 else if (-2 == cp_ret) {
1117 struct sg_scsi_sense_hdr ssh;
1118
1119 sb_ok = sg_scsi_normalize_sense(sense_b, sense_len, &ssh);
1120 switch (sense_cat) {
1121 case SG_LIB_CAT_ILLEGAL_REQ:
1122 if (sb_ok) {
1123 if ((ASC_GENERAL_0 == ssh.asc) &&
1124 (ASQ_OP_IN_PROGRESS == ssh.ascq))
1125 ret = DDPT_CAT_OP_IN_PROGRESS;
1126 else if (ASC_3PC_GEN == ssh.asc) {
1127 if (ASQ_TARGET_UNDERRUN == ssh.ascq)
1128 ret = DDPT_CAT_TARGET_UNDERRUN;
1129 else if (ASQ_TARGET_OVERRUN == ssh.ascq)
1130 ret = DDPT_CAT_TARGET_OVERRUN;
1131 else
1132 ret = sense_cat;
1133 } else if (ASC_PARAM_LST_LEN_ERR == ssh.asc)
1134 ret = DDPT_CAT_PARAM_LST_LEN_ERR;
1135 else if (ASC_INVALID_PARAM == ssh.asc) {
1136 if (ASQ_INVALID_FLD_IN_PARAM == ssh.ascq)
1137 ret = DDPT_CAT_INVALID_FLD_IN_PARAM;
1138 else if (ASQ_TOO_MANY_SEGS_IN_PARAM == ssh.ascq)
1139 ret = DDPT_CAT_TOO_MANY_SEGS_IN_PARAM;
1140 else
1141 ret = sense_cat;
1142 } else if (ASC_INSUFF_RES == ssh.asc) {
1143 if (ASQ_INSUFF_RES_CREATE_ROD == ssh.ascq)
1144 ret = DDPT_CAT_INSUFF_RES_CREATE_ROD;
1145 else if (ASQ_INSUFF_RES_CREATE_RODTOK == ssh.ascq)
1146 ret = DDPT_CAT_INSUFF_RES_CREATE_RODTOK;
1147 else
1148 ret = sense_cat;
1149 } else if (ASC_INVALID_TOKOP == ssh.asc)
1150 ret = DDPT_CAT_TOKOP_BASE + ssh.ascq;
1151 else
1152 ret = sense_cat;
1153 } else
1154 ret = sense_cat;
1155 break;
1156 case SG_LIB_CAT_RECOVERED:
1157 case SG_LIB_CAT_NO_SENSE:
1158 ret = 0;
1159 break;
1160 default:
1161 ret = sense_cat;
1162 break;
1163 }
1164 } else
1165 ret = 0;
1166 return ret;
1167 }
1168
1169 /* Handles various service actions associated with opcode 0x83 which is
1170 * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID1 and
1171 * LID4), POPULATE TOKEN and WRITE USING TOKEN commands.
1172 * Return of 0 -> success,
1173 * SG_LIB_CAT_INVALID_OP -> opcode 0x83 not supported,
1174 * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
1175 * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
1176 * -1 -> other failure */
1177 int
pt_3party_copy_out(int sg_fd,int sa,uint32_t list_id,int group_num,int timeout_secs,void * paramp,int param_len,int noisy,int vb,int err_vb)1178 pt_3party_copy_out(int sg_fd, int sa, uint32_t list_id, int group_num,
1179 int timeout_secs, void * paramp, int param_len,
1180 int noisy, int vb, int err_vb)
1181 {
1182 int k, res, ret, has_lid, sense_cat, tmout;
1183 unsigned char xcopyCmdBlk[DDPT_TPC_OUT_CMDLEN] =
1184 {DDPT_TPC_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1185 unsigned char sense_b[SENSE_BUFF_LEN];
1186 struct sg_pt_base * ptvp;
1187 char cname[80];
1188
1189 if (vb < 0)
1190 vb = 0;
1191 if (err_vb < 0)
1192 err_vb = 0;
1193 sg_get_opcode_sa_name(DDPT_TPC_OUT_CMD, sa, 0, sizeof(cname),
1194 cname);
1195 xcopyCmdBlk[1] = (unsigned char)(sa & 0x1f);
1196 switch (sa) {
1197 case 0x0: /* XCOPY(LID1) */
1198 case 0x1: /* XCOPY(LID4) */
1199 xcopyCmdBlk[10] = (unsigned char)((param_len >> 24) & 0xff);
1200 xcopyCmdBlk[11] = (unsigned char)((param_len >> 16) & 0xff);
1201 xcopyCmdBlk[12] = (unsigned char)((param_len >> 8) & 0xff);
1202 xcopyCmdBlk[13] = (unsigned char)(param_len & 0xff);
1203 has_lid = 0;
1204 break;
1205 case 0x10: /* POPULATE TOKEN (SBC-3) */
1206 case 0x11: /* WRITE USING TOKEN (SBC-3) */
1207 xcopyCmdBlk[6] = (unsigned char)((list_id >> 24) & 0xff);
1208 xcopyCmdBlk[7] = (unsigned char)((list_id >> 16) & 0xff);
1209 xcopyCmdBlk[8] = (unsigned char)((list_id >> 8) & 0xff);
1210 xcopyCmdBlk[9] = (unsigned char)(list_id & 0xff);
1211 has_lid = 1;
1212 xcopyCmdBlk[10] = (unsigned char)((param_len >> 24) & 0xff);
1213 xcopyCmdBlk[11] = (unsigned char)((param_len >> 16) & 0xff);
1214 xcopyCmdBlk[12] = (unsigned char)((param_len >> 8) & 0xff);
1215 xcopyCmdBlk[13] = (unsigned char)(param_len & 0xff);
1216 xcopyCmdBlk[14] = (unsigned char)(group_num & 0x1f);
1217 break;
1218 case 0x1c: /* COPY OPERATION ABORT */
1219 xcopyCmdBlk[2] = (unsigned char)((list_id >> 24) & 0xff);
1220 xcopyCmdBlk[3] = (unsigned char)((list_id >> 16) & 0xff);
1221 xcopyCmdBlk[4] = (unsigned char)((list_id >> 8) & 0xff);
1222 xcopyCmdBlk[5] = (unsigned char)(list_id & 0xff);
1223 has_lid = 1;
1224 break;
1225 default:
1226 pr2serr("pt_3party_copy_out: unknown service action 0x%x\n", sa);
1227 return -1;
1228 }
1229 tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
1230
1231 if (vb) {
1232 if ((vb > 1) || (param_len <= 0)) {
1233 pr2serr(" %s cmd : ", cname);
1234 for (k = 0; k < DDPT_TPC_OUT_CMDLEN; ++k)
1235 pr2serr("%02x ", xcopyCmdBlk[k]);
1236 pr2serr("\n");
1237 } else if (has_lid)
1238 pr2serr(" %s for list_id=%" PRIu32 "\n", cname, list_id);
1239 if (paramp && param_len) {
1240 if (vb > 1) {
1241 if (param_len <= 16) {
1242 pr2serr(" %s parameter list:\n", cname);
1243 dStrHexErr((const char *)paramp, param_len, -1);
1244 } else {
1245 pr2serr(" %s, first 16 of %d byte parameter list:\n",
1246 cname, param_len);
1247 dStrHexErr((const char *)paramp, 16, -1);
1248 }
1249 }
1250 }
1251 }
1252
1253 ptvp = construct_scsi_pt_obj();
1254 if (NULL == ptvp) {
1255 pr2serr("%s: out of memory\n", cname);
1256 return -1;
1257 }
1258 set_scsi_pt_cdb(ptvp, xcopyCmdBlk, sizeof(xcopyCmdBlk));
1259 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1260 set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
1261 res = do_scsi_pt(ptvp, sg_fd, tmout, vb);
1262 ret = sg_cmds_process_resp(ptvp, cname, res, 0, sense_b, noisy,
1263 ((err_vb > 0) ? err_vb : 0), &sense_cat);
1264 if ((-1 == ret) &&
1265 (SCSI_PT_RESULT_STATUS == get_scsi_pt_result_category(ptvp)) &&
1266 (SAM_STAT_RESERVATION_CONFLICT == get_scsi_pt_status_response(ptvp)))
1267 ret = SG_LIB_CAT_RES_CONFLICT;
1268 else
1269 ret = pt_tpc_process_res(ret, sense_cat, sense_b,
1270 get_scsi_pt_sense_len(ptvp));
1271 destruct_scsi_pt_obj(ptvp);
1272 return ret;
1273 }
1274
1275 int
pt_3party_copy_in(int sg_fd,int sa,uint32_t list_id,int timeout_secs,void * resp,int mx_resp_len,int noisy,int vb,int err_vb)1276 pt_3party_copy_in(int sg_fd, int sa, uint32_t list_id, int timeout_secs,
1277 void * resp, int mx_resp_len, int noisy, int vb, int err_vb)
1278 {
1279 int k, res, ret, sense_cat, tmout;
1280 unsigned char rcvcopyresCmdBlk[DDPT_TPC_IN_CMDLEN] =
1281 {DDPT_TPC_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1282 unsigned char sense_b[SENSE_BUFF_LEN];
1283 struct sg_pt_base * ptvp;
1284 char cname[64];
1285
1286 if (vb < 0)
1287 vb = 0;
1288 if (err_vb < 0)
1289 err_vb = 0;
1290 sg_get_opcode_sa_name(DDPT_TPC_IN_CMD, sa, 0, (int)sizeof(cname), cname);
1291 rcvcopyresCmdBlk[1] = (unsigned char)(sa & 0x1f);
1292 if (sa <= 4) /* LID1 variants */
1293 rcvcopyresCmdBlk[2] = (unsigned char)(list_id);
1294 else if ((sa >= 5) && (sa <= 7)) { /* LID4 variants */
1295 rcvcopyresCmdBlk[2] = (unsigned char)((list_id >> 24) & 0xff);
1296 rcvcopyresCmdBlk[3] = (unsigned char)((list_id >> 16) & 0xff);
1297 rcvcopyresCmdBlk[4] = (unsigned char)((list_id >> 8) & 0xff);
1298 rcvcopyresCmdBlk[5] = (unsigned char)(list_id & 0xff);
1299 }
1300 rcvcopyresCmdBlk[10] = (unsigned char)((mx_resp_len >> 24) & 0xff);
1301 rcvcopyresCmdBlk[11] = (unsigned char)((mx_resp_len >> 16) & 0xff);
1302 rcvcopyresCmdBlk[12] = (unsigned char)((mx_resp_len >> 8) & 0xff);
1303 rcvcopyresCmdBlk[13] = (unsigned char)(mx_resp_len & 0xff);
1304 tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
1305
1306 if (vb > 1) {
1307 pr2serr(" %s cmd: ", cname);
1308 for (k = 0; k < DDPT_TPC_IN_CMDLEN; ++k)
1309 pr2serr("%02x ", rcvcopyresCmdBlk[k]);
1310 pr2serr("\n");
1311 }
1312
1313 ptvp = construct_scsi_pt_obj();
1314 if (NULL == ptvp) {
1315 pr2serr("%s: out of memory\n", cname);
1316 return -1;
1317 }
1318 set_scsi_pt_cdb(ptvp, rcvcopyresCmdBlk, sizeof(rcvcopyresCmdBlk));
1319 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1320 set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
1321 res = do_scsi_pt(ptvp, sg_fd, tmout, vb);
1322 ret = sg_cmds_process_resp(ptvp, cname, res, mx_resp_len, sense_b, noisy,
1323 ((err_vb > 0) ? err_vb : 0), &sense_cat);
1324 if ((-1 == ret) &&
1325 (SCSI_PT_RESULT_STATUS == get_scsi_pt_result_category(ptvp)) &&
1326 (SAM_STAT_RESERVATION_CONFLICT == get_scsi_pt_status_response(ptvp)))
1327 ret = SG_LIB_CAT_RES_CONFLICT;
1328 else
1329 ret = pt_tpc_process_res(ret, sense_cat, sense_b,
1330 get_scsi_pt_sense_len(ptvp));
1331 destruct_scsi_pt_obj(ptvp);
1332 return ret;
1333 }
1334