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