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