xref: /aosp_15_r20/external/sg3_utils/lib/sg_cmds_mmc.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2008-2021 Douglas Gilbert.
3*44704f69SBart Van Assche  * All rights reserved.
4*44704f69SBart Van Assche  * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche  * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche  *
7*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche  */
9*44704f69SBart Van Assche 
10*44704f69SBart Van Assche #include <stdio.h>
11*44704f69SBart Van Assche #include <stdlib.h>
12*44704f69SBart Van Assche #include <stdarg.h>
13*44704f69SBart Van Assche #include <string.h>
14*44704f69SBart Van Assche #include <unistd.h>
15*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
16*44704f69SBart Van Assche #include <inttypes.h>
17*44704f69SBart Van Assche 
18*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
19*44704f69SBart Van Assche #include "config.h"
20*44704f69SBart Van Assche #endif
21*44704f69SBart Van Assche 
22*44704f69SBart Van Assche #include "sg_lib.h"
23*44704f69SBart Van Assche #include "sg_cmds_basic.h"
24*44704f69SBart Van Assche #include "sg_cmds_mmc.h"
25*44704f69SBart Van Assche #include "sg_pt.h"
26*44704f69SBart Van Assche #include "sg_unaligned.h"
27*44704f69SBart Van Assche #include "sg_pr2serr.h"
28*44704f69SBart Van Assche 
29*44704f69SBart Van Assche 
30*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
31*44704f69SBart Van Assche 
32*44704f69SBart Van Assche #define DEF_PT_TIMEOUT 60       /* 60 seconds */
33*44704f69SBart Van Assche 
34*44704f69SBart Van Assche #define GET_CONFIG_CMD 0x46
35*44704f69SBart Van Assche #define GET_CONFIG_CMD_LEN 10
36*44704f69SBart Van Assche #define GET_PERFORMANCE_CMD 0xac
37*44704f69SBart Van Assche #define GET_PERFORMANCE_CMD_LEN 12
38*44704f69SBart Van Assche #define SET_CD_SPEED_CMD 0xbb
39*44704f69SBart Van Assche #define SET_CD_SPEED_CMDLEN 12
40*44704f69SBart Van Assche #define SET_STREAMING_CMD 0xb6
41*44704f69SBart Van Assche #define SET_STREAMING_CMDLEN 12
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche 
44*44704f69SBart Van Assche static struct sg_pt_base *
create_pt_obj(const char * cname)45*44704f69SBart Van Assche create_pt_obj(const char * cname)
46*44704f69SBart Van Assche {
47*44704f69SBart Van Assche     struct sg_pt_base * ptvp = construct_scsi_pt_obj();
48*44704f69SBart Van Assche     if (NULL == ptvp)
49*44704f69SBart Van Assche         pr2ws("%s: out of memory\n", cname);
50*44704f69SBart Van Assche     return ptvp;
51*44704f69SBart Van Assche }
52*44704f69SBart Van Assche 
53*44704f69SBart Van Assche /* Invokes a SCSI SET CD SPEED command (MMC).
54*44704f69SBart Van Assche  * Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> command not supported,
55*44704f69SBart Van Assche  * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
56*44704f69SBart Van Assche  * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
57*44704f69SBart Van Assche  * -1 -> other failure */
58*44704f69SBart Van Assche int
sg_ll_set_cd_speed(int sg_fd,int rot_control,int drv_read_speed,int drv_write_speed,bool noisy,int verbose)59*44704f69SBart Van Assche sg_ll_set_cd_speed(int sg_fd, int rot_control, int drv_read_speed,
60*44704f69SBart Van Assche                    int drv_write_speed, bool noisy, int verbose)
61*44704f69SBart Van Assche {
62*44704f69SBart Van Assche     static const char * const cdb_s = "set cd speed";
63*44704f69SBart Van Assche     int res, ret, sense_cat;
64*44704f69SBart Van Assche     uint8_t scsCmdBlk[SET_CD_SPEED_CMDLEN] = {SET_CD_SPEED_CMD, 0,
65*44704f69SBart Van Assche                                          0, 0, 0, 0, 0, 0, 0, 0, 0 ,0};
66*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN];
67*44704f69SBart Van Assche     struct sg_pt_base * ptvp;
68*44704f69SBart Van Assche 
69*44704f69SBart Van Assche     scsCmdBlk[1] |= (rot_control & 0x3);
70*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)drv_read_speed, scsCmdBlk + 2);
71*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)drv_write_speed, scsCmdBlk + 4);
72*44704f69SBart Van Assche 
73*44704f69SBart Van Assche     if (verbose) {
74*44704f69SBart Van Assche         int k;
75*44704f69SBart Van Assche 
76*44704f69SBart Van Assche         pr2ws("    %s cdb: ", cdb_s);
77*44704f69SBart Van Assche         for (k = 0; k < SET_CD_SPEED_CMDLEN; ++k)
78*44704f69SBart Van Assche             pr2ws("%02x ", scsCmdBlk[k]);
79*44704f69SBart Van Assche         pr2ws("\n");
80*44704f69SBart Van Assche     }
81*44704f69SBart Van Assche     if (NULL == ((ptvp = create_pt_obj(cdb_s))))
82*44704f69SBart Van Assche         return -1;
83*44704f69SBart Van Assche     set_scsi_pt_cdb(ptvp, scsCmdBlk, sizeof(scsCmdBlk));
84*44704f69SBart Van Assche     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
85*44704f69SBart Van Assche     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
86*44704f69SBart Van Assche     ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
87*44704f69SBart Van Assche     if (-1 == ret) {
88*44704f69SBart Van Assche         if (get_scsi_pt_transport_err(ptvp))
89*44704f69SBart Van Assche             ret = SG_LIB_TRANSPORT_ERROR;
90*44704f69SBart Van Assche         else
91*44704f69SBart Van Assche             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
92*44704f69SBart Van Assche     } else if (-2 == ret) {
93*44704f69SBart Van Assche         switch (sense_cat) {
94*44704f69SBart Van Assche         case SG_LIB_CAT_NOT_READY:
95*44704f69SBart Van Assche         case SG_LIB_CAT_UNIT_ATTENTION:
96*44704f69SBart Van Assche         case SG_LIB_CAT_INVALID_OP:
97*44704f69SBart Van Assche         case SG_LIB_CAT_ILLEGAL_REQ:
98*44704f69SBart Van Assche         case SG_LIB_CAT_ABORTED_COMMAND:
99*44704f69SBart Van Assche             ret = sense_cat;
100*44704f69SBart Van Assche             break;
101*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
102*44704f69SBart Van Assche         case SG_LIB_CAT_NO_SENSE:
103*44704f69SBart Van Assche             ret = 0;
104*44704f69SBart Van Assche             break;
105*44704f69SBart Van Assche         default:
106*44704f69SBart Van Assche             ret = -1;
107*44704f69SBart Van Assche             break;
108*44704f69SBart Van Assche         }
109*44704f69SBart Van Assche     } else
110*44704f69SBart Van Assche         ret = 0;
111*44704f69SBart Van Assche 
112*44704f69SBart Van Assche     destruct_scsi_pt_obj(ptvp);
113*44704f69SBart Van Assche     return ret;
114*44704f69SBart Van Assche }
115*44704f69SBart Van Assche 
116*44704f69SBart Van Assche /* Invokes a SCSI GET CONFIGURATION command (MMC-3,4,5).
117*44704f69SBart Van Assche  * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
118*44704f69SBart Van Assche  * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
119*44704f69SBart Van Assche  * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
120*44704f69SBart Van Assche int
sg_ll_get_config(int sg_fd,int rt,int starting,void * resp,int mx_resp_len,bool noisy,int verbose)121*44704f69SBart Van Assche sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
122*44704f69SBart Van Assche                  int mx_resp_len, bool noisy, int verbose)
123*44704f69SBart Van Assche {
124*44704f69SBart Van Assche     static const char * const cdb_s = "get configuration";
125*44704f69SBart Van Assche     int res, ret, sense_cat;
126*44704f69SBart Van Assche     uint8_t gcCmdBlk[GET_CONFIG_CMD_LEN] = {GET_CONFIG_CMD, 0, 0, 0,
127*44704f69SBart Van Assche                                                   0, 0, 0, 0, 0, 0};
128*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN];
129*44704f69SBart Van Assche     struct sg_pt_base * ptvp;
130*44704f69SBart Van Assche 
131*44704f69SBart Van Assche     if ((rt < 0) || (rt > 3)) {
132*44704f69SBart Van Assche         pr2ws("Bad rt value: %d\n", rt);
133*44704f69SBart Van Assche         return -1;
134*44704f69SBart Van Assche     }
135*44704f69SBart Van Assche     gcCmdBlk[1] = (rt & 0x3);
136*44704f69SBart Van Assche     if ((starting < 0) || (starting > 0xffff)) {
137*44704f69SBart Van Assche         pr2ws("Bad starting field number: 0x%x\n", starting);
138*44704f69SBart Van Assche         return -1;
139*44704f69SBart Van Assche     }
140*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)starting, gcCmdBlk + 2);
141*44704f69SBart Van Assche     if ((mx_resp_len < 0) || (mx_resp_len > 0xffff)) {
142*44704f69SBart Van Assche         pr2ws("Bad mx_resp_len: 0x%x\n", starting);
143*44704f69SBart Van Assche         return -1;
144*44704f69SBart Van Assche     }
145*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)mx_resp_len, gcCmdBlk + 7);
146*44704f69SBart Van Assche 
147*44704f69SBart Van Assche     if (verbose) {
148*44704f69SBart Van Assche         int k;
149*44704f69SBart Van Assche 
150*44704f69SBart Van Assche         pr2ws("    %s cdb: ", cdb_s);
151*44704f69SBart Van Assche         for (k = 0; k < GET_CONFIG_CMD_LEN; ++k)
152*44704f69SBart Van Assche             pr2ws("%02x ", gcCmdBlk[k]);
153*44704f69SBart Van Assche         pr2ws("\n");
154*44704f69SBart Van Assche     }
155*44704f69SBart Van Assche 
156*44704f69SBart Van Assche     if (NULL == ((ptvp = create_pt_obj(cdb_s))))
157*44704f69SBart Van Assche         return -1;
158*44704f69SBart Van Assche     set_scsi_pt_cdb(ptvp, gcCmdBlk, sizeof(gcCmdBlk));
159*44704f69SBart Van Assche     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
160*44704f69SBart Van Assche     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
161*44704f69SBart Van Assche     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
162*44704f69SBart Van Assche     ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
163*44704f69SBart Van Assche     if (-1 == ret) {
164*44704f69SBart Van Assche         if (get_scsi_pt_transport_err(ptvp))
165*44704f69SBart Van Assche             ret = SG_LIB_TRANSPORT_ERROR;
166*44704f69SBart Van Assche         else
167*44704f69SBart Van Assche             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
168*44704f69SBart Van Assche     } else if (-2 == ret) {
169*44704f69SBart Van Assche         switch (sense_cat) {
170*44704f69SBart Van Assche         case SG_LIB_CAT_INVALID_OP:
171*44704f69SBart Van Assche         case SG_LIB_CAT_ILLEGAL_REQ:
172*44704f69SBart Van Assche         case SG_LIB_CAT_UNIT_ATTENTION:
173*44704f69SBart Van Assche         case SG_LIB_CAT_ABORTED_COMMAND:
174*44704f69SBart Van Assche             ret = sense_cat;
175*44704f69SBart Van Assche             break;
176*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
177*44704f69SBart Van Assche         case SG_LIB_CAT_NO_SENSE:
178*44704f69SBart Van Assche             ret = 0;
179*44704f69SBart Van Assche             break;
180*44704f69SBart Van Assche         default:
181*44704f69SBart Van Assche             ret = -1;
182*44704f69SBart Van Assche             break;
183*44704f69SBart Van Assche         }
184*44704f69SBart Van Assche     } else {
185*44704f69SBart Van Assche         if ((verbose > 2) && (ret > 3)) {
186*44704f69SBart Van Assche             uint8_t * bp;
187*44704f69SBart Van Assche             int len;
188*44704f69SBart Van Assche 
189*44704f69SBart Van Assche             bp = (uint8_t *)resp;
190*44704f69SBart Van Assche             len = sg_get_unaligned_be32(bp + 0);
191*44704f69SBart Van Assche             if (len < 0)
192*44704f69SBart Van Assche                 len = 0;
193*44704f69SBart Van Assche             len = (ret < len) ? ret : len;
194*44704f69SBart Van Assche             pr2ws("    %s: response:\n", cdb_s);
195*44704f69SBart Van Assche             if (3 == verbose) {
196*44704f69SBart Van Assche                 pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : ""));
197*44704f69SBart Van Assche                 hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len),
198*44704f69SBart Van Assche                            -1);
199*44704f69SBart Van Assche             } else {
200*44704f69SBart Van Assche                 pr2ws(":\n");
201*44704f69SBart Van Assche                 hex2stderr((const uint8_t *)resp, len, 0);
202*44704f69SBart Van Assche             }
203*44704f69SBart Van Assche         }
204*44704f69SBart Van Assche         ret = 0;
205*44704f69SBart Van Assche     }
206*44704f69SBart Van Assche     destruct_scsi_pt_obj(ptvp);
207*44704f69SBart Van Assche     return ret;
208*44704f69SBart Van Assche }
209*44704f69SBart Van Assche 
210*44704f69SBart Van Assche /* Invokes a SCSI GET PERFORMANCE command (MMC-3...6).
211*44704f69SBart Van Assche  * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
212*44704f69SBart Van Assche  * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
213*44704f69SBart Van Assche  * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
214*44704f69SBart Van Assche int
sg_ll_get_performance(int sg_fd,int data_type,unsigned int starting_lba,int max_num_desc,int ttype,void * resp,int mx_resp_len,bool noisy,int verbose)215*44704f69SBart Van Assche sg_ll_get_performance(int sg_fd, int data_type, unsigned int starting_lba,
216*44704f69SBart Van Assche                       int max_num_desc, int ttype, void * resp,
217*44704f69SBart Van Assche                       int mx_resp_len, bool noisy, int verbose)
218*44704f69SBart Van Assche {
219*44704f69SBart Van Assche     static const char * const cdb_s = "get performance";
220*44704f69SBart Van Assche     int res, ret, sense_cat;
221*44704f69SBart Van Assche     uint8_t gpCmdBlk[GET_PERFORMANCE_CMD_LEN] = {GET_PERFORMANCE_CMD, 0,
222*44704f69SBart Van Assche                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
223*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN];
224*44704f69SBart Van Assche     struct sg_pt_base * ptvp;
225*44704f69SBart Van Assche 
226*44704f69SBart Van Assche     if ((data_type < 0) || (data_type > 0x1f)) {
227*44704f69SBart Van Assche         pr2ws("Bad data_type value: %d\n", data_type);
228*44704f69SBart Van Assche         return -1;
229*44704f69SBart Van Assche     }
230*44704f69SBart Van Assche     gpCmdBlk[1] = (data_type & 0x1f);
231*44704f69SBart Van Assche     sg_put_unaligned_be32((uint32_t)starting_lba, gpCmdBlk + 2);
232*44704f69SBart Van Assche     if ((max_num_desc < 0) || (max_num_desc > 0xffff)) {
233*44704f69SBart Van Assche         pr2ws("Bad max_num_desc: 0x%x\n", max_num_desc);
234*44704f69SBart Van Assche         return -1;
235*44704f69SBart Van Assche     }
236*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)max_num_desc, gpCmdBlk + 8);
237*44704f69SBart Van Assche     if ((ttype < 0) || (ttype > 0xff)) {
238*44704f69SBart Van Assche         pr2ws("Bad type: 0x%x\n", ttype);
239*44704f69SBart Van Assche         return -1;
240*44704f69SBart Van Assche     }
241*44704f69SBart Van Assche     gpCmdBlk[10] = (uint8_t)ttype;
242*44704f69SBart Van Assche 
243*44704f69SBart Van Assche     if (verbose) {
244*44704f69SBart Van Assche         int k;
245*44704f69SBart Van Assche 
246*44704f69SBart Van Assche         pr2ws("    %s cdb: ", cdb_s);
247*44704f69SBart Van Assche         for (k = 0; k < GET_PERFORMANCE_CMD_LEN; ++k)
248*44704f69SBart Van Assche             pr2ws("%02x ", gpCmdBlk[k]);
249*44704f69SBart Van Assche         pr2ws("\n");
250*44704f69SBart Van Assche     }
251*44704f69SBart Van Assche 
252*44704f69SBart Van Assche     if (NULL == ((ptvp = create_pt_obj(cdb_s))))
253*44704f69SBart Van Assche         return -1;
254*44704f69SBart Van Assche     set_scsi_pt_cdb(ptvp, gpCmdBlk, sizeof(gpCmdBlk));
255*44704f69SBart Van Assche     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
256*44704f69SBart Van Assche     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
257*44704f69SBart Van Assche     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
258*44704f69SBart Van Assche     ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
259*44704f69SBart Van Assche     if (-1 == ret) {
260*44704f69SBart Van Assche         if (get_scsi_pt_transport_err(ptvp))
261*44704f69SBart Van Assche             ret = SG_LIB_TRANSPORT_ERROR;
262*44704f69SBart Van Assche         else
263*44704f69SBart Van Assche             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
264*44704f69SBart Van Assche     } else if (-2 == ret) {
265*44704f69SBart Van Assche         switch (sense_cat) {
266*44704f69SBart Van Assche         case SG_LIB_CAT_INVALID_OP:
267*44704f69SBart Van Assche         case SG_LIB_CAT_ILLEGAL_REQ:
268*44704f69SBart Van Assche         case SG_LIB_CAT_UNIT_ATTENTION:
269*44704f69SBart Van Assche         case SG_LIB_CAT_ABORTED_COMMAND:
270*44704f69SBart Van Assche             ret = sense_cat;
271*44704f69SBart Van Assche             break;
272*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
273*44704f69SBart Van Assche         case SG_LIB_CAT_NO_SENSE:
274*44704f69SBart Van Assche             ret = 0;
275*44704f69SBart Van Assche             break;
276*44704f69SBart Van Assche         default:
277*44704f69SBart Van Assche             ret = -1;
278*44704f69SBart Van Assche             break;
279*44704f69SBart Van Assche         }
280*44704f69SBart Van Assche     } else {
281*44704f69SBart Van Assche         if ((verbose > 2) && (ret > 3)) {
282*44704f69SBart Van Assche             uint8_t * bp;
283*44704f69SBart Van Assche             int len;
284*44704f69SBart Van Assche 
285*44704f69SBart Van Assche             bp = (uint8_t *)resp;
286*44704f69SBart Van Assche             len = sg_get_unaligned_be32(bp + 0);
287*44704f69SBart Van Assche             if (len < 0)
288*44704f69SBart Van Assche                 len = 0;
289*44704f69SBart Van Assche             len = (ret < len) ? ret : len;
290*44704f69SBart Van Assche             pr2ws("    %s: response", cdb_s);
291*44704f69SBart Van Assche             if (3 == verbose) {
292*44704f69SBart Van Assche                 pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : ""));
293*44704f69SBart Van Assche                 hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len),
294*44704f69SBart Van Assche                            -1);
295*44704f69SBart Van Assche             } else {
296*44704f69SBart Van Assche                 pr2ws(":\n");
297*44704f69SBart Van Assche                 hex2stderr((const uint8_t *)resp, len, 0);
298*44704f69SBart Van Assche             }
299*44704f69SBart Van Assche         }
300*44704f69SBart Van Assche         ret = 0;
301*44704f69SBart Van Assche     }
302*44704f69SBart Van Assche     destruct_scsi_pt_obj(ptvp);
303*44704f69SBart Van Assche     return ret;
304*44704f69SBart Van Assche }
305*44704f69SBart Van Assche 
306*44704f69SBart Van Assche /* Invokes a SCSI SET STREAMING command (MMC). Return of 0 -> success,
307*44704f69SBart Van Assche  * SG_LIB_CAT_INVALID_OP -> Set Streaming not supported,
308*44704f69SBart Van Assche  * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
309*44704f69SBart Van Assche  * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_NOT_READY -> device not ready,
310*44704f69SBart Van Assche  * -1 -> other failure */
311*44704f69SBart Van Assche int
sg_ll_set_streaming(int sg_fd,int type,void * paramp,int param_len,bool noisy,int verbose)312*44704f69SBart Van Assche sg_ll_set_streaming(int sg_fd, int type, void * paramp, int param_len,
313*44704f69SBart Van Assche                     bool noisy, int verbose)
314*44704f69SBart Van Assche {
315*44704f69SBart Van Assche     static const char * const cdb_s = "set streaming";
316*44704f69SBart Van Assche     int res, ret, sense_cat;
317*44704f69SBart Van Assche     uint8_t ssCmdBlk[SET_STREAMING_CMDLEN] =
318*44704f69SBart Van Assche                  {SET_STREAMING_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
319*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN];
320*44704f69SBart Van Assche     struct sg_pt_base * ptvp;
321*44704f69SBart Van Assche 
322*44704f69SBart Van Assche     ssCmdBlk[8] = type;
323*44704f69SBart Van Assche     sg_put_unaligned_be16((uint16_t)param_len, ssCmdBlk + 9);
324*44704f69SBart Van Assche     if (verbose) {
325*44704f69SBart Van Assche         int k;
326*44704f69SBart Van Assche 
327*44704f69SBart Van Assche         pr2ws("    %s cdb: ", cdb_s);
328*44704f69SBart Van Assche         for (k = 0; k < SET_STREAMING_CMDLEN; ++k)
329*44704f69SBart Van Assche             pr2ws("%02x ", ssCmdBlk[k]);
330*44704f69SBart Van Assche         pr2ws("\n");
331*44704f69SBart Van Assche         if ((verbose > 1) && paramp && param_len) {
332*44704f69SBart Van Assche             pr2ws("    %s parameter list:\n", cdb_s);
333*44704f69SBart Van Assche             hex2stderr((const uint8_t *)paramp, param_len, -1);
334*44704f69SBart Van Assche         }
335*44704f69SBart Van Assche     }
336*44704f69SBart Van Assche 
337*44704f69SBart Van Assche     if (NULL == ((ptvp = create_pt_obj(cdb_s))))
338*44704f69SBart Van Assche         return -1;
339*44704f69SBart Van Assche     set_scsi_pt_cdb(ptvp, ssCmdBlk, sizeof(ssCmdBlk));
340*44704f69SBart Van Assche     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
341*44704f69SBart Van Assche     set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len);
342*44704f69SBart Van Assche     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
343*44704f69SBart Van Assche     ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
344*44704f69SBart Van Assche     if (-1 == ret) {
345*44704f69SBart Van Assche         if (get_scsi_pt_transport_err(ptvp))
346*44704f69SBart Van Assche             ret = SG_LIB_TRANSPORT_ERROR;
347*44704f69SBart Van Assche         else
348*44704f69SBart Van Assche             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
349*44704f69SBart Van Assche     } else if (-2 == ret) {
350*44704f69SBart Van Assche         switch (sense_cat) {
351*44704f69SBart Van Assche         case SG_LIB_CAT_NOT_READY:
352*44704f69SBart Van Assche         case SG_LIB_CAT_INVALID_OP:
353*44704f69SBart Van Assche         case SG_LIB_CAT_ILLEGAL_REQ:
354*44704f69SBart Van Assche         case SG_LIB_CAT_UNIT_ATTENTION:
355*44704f69SBart Van Assche         case SG_LIB_CAT_ABORTED_COMMAND:
356*44704f69SBart Van Assche             ret = sense_cat;
357*44704f69SBart Van Assche             break;
358*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
359*44704f69SBart Van Assche         case SG_LIB_CAT_NO_SENSE:
360*44704f69SBart Van Assche             ret = 0;
361*44704f69SBart Van Assche             break;
362*44704f69SBart Van Assche         default:
363*44704f69SBart Van Assche             ret = -1;
364*44704f69SBart Van Assche             break;
365*44704f69SBart Van Assche         }
366*44704f69SBart Van Assche     } else
367*44704f69SBart Van Assche         ret = 0;
368*44704f69SBart Van Assche     destruct_scsi_pt_obj(ptvp);
369*44704f69SBart Van Assche     return ret;
370*44704f69SBart Van Assche }
371