]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - scsicmds.cpp
import smartmontools 7.0
[mirror_smartmontools-debian.git] / scsicmds.cpp
CommitLineData
832b75ed 1/*
4d59bff9 2 * scsicmds.cpp
832b75ed 3 *
a86ec89e 4 * Home page of code is: http://www.smartmontools.org
832b75ed 5 *
a86ec89e 6 * Copyright (C) 2002-8 Bruce Allen
832b75ed 7 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
ff28b140 8 * Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
832b75ed 9 *
ff28b140 10 * SPDX-License-Identifier: GPL-2.0-or-later
832b75ed
GG
11 *
12 *
13 * In the SCSI world "SMART" is a dead or withdrawn standard. In recent
14 * SCSI standards (since SCSI-3) it goes under the awkward name of
15 * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")].
16 * The relevant information is spread around several SCSI draft
17 * standards available at http://www.t10.org . Reference is made in the
18 * code to the following acronyms:
19 * - SAM [SCSI Architectural model, versions 2 or 3]
20 * - SPC [SCSI Primary commands, versions 2 or 3]
21 * - SBC [SCSI Block commands, versions 2]
22 *
23 * Some SCSI disk vendors have snippets of "SMART" information in their
24 * product manuals.
25 */
26
27#include <stdio.h>
28#include <string.h>
cfbba5b9 29#include <errno.h>
3d17a85c 30#include <ctype.h>
832b75ed
GG
31
32#include "config.h"
ff28b140 33
832b75ed 34#include "scsicmds.h"
2127e193
GI
35#include "atacmds.h" // FIXME: for smart_command_set only
36#include "dev_interface.h"
832b75ed 37#include "utility.h"
ff28b140 38#include "sg_unaligned.h"
832b75ed 39
ff28b140 40const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 4842 2018-12-02 16:07:26Z chrfranke $"
cfbba5b9 41 SCSICMDS_H_CVSID;
832b75ed 42
ff28b140
TL
43static const char * logSenStr = "Log Sense";
44
cfbba5b9
GI
45// Print SCSI debug messages?
46unsigned char scsi_debugmode = 0;
832b75ed 47
ee38a438
GI
48supported_vpd_pages * supported_vpd_pages_p = NULL;
49
50
51supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0)
52{
d2e702cf 53 unsigned char b[0xfc]; /* pre SPC-3 INQUIRY max response size */
ee38a438
GI
54 memset(b, 0, sizeof(b));
55 if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES,
56 b, sizeof(b)))) {
ff28b140 57 num_valid = sg_get_unaligned_be16(b + 2);
a86ec89e 58 int n = sizeof(pages);
ee38a438
GI
59 if (num_valid > n)
60 num_valid = n;
61 memcpy(pages, b + 4, num_valid);
62 }
63}
64
65bool
66supported_vpd_pages::is_supported(int vpd_page_num) const
67{
68 /* Supported VPD pages numbers start at offset 4 and should be in
69 * ascending order but don't assume that. */
70 for (int k = 0; k < num_valid; ++k) {
71 if (vpd_page_num == pages[k])
72 return true;
73 }
74 return false;
75}
76
ff28b140 77/* output binary in ASCII hex and optionally ASCII. Uses pout() for output. */
ee38a438 78void
ff28b140 79dStrHex(const uint8_t * up, int len, int no_ascii)
832b75ed 80{
ff28b140 81 const uint8_t * p = up;
832b75ed
GG
82 char buff[82];
83 int a = 0;
84 const int bpstart = 5;
85 const int cpstart = 60;
86 int cpos = cpstart;
87 int bpos = bpstart;
88 int i, k;
ee38a438 89
832b75ed
GG
90 if (len <= 0) return;
91 memset(buff,' ',80);
92 buff[80]='\0';
ee38a438 93 k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
832b75ed
GG
94 buff[k + 1] = ' ';
95 if (bpos >= ((bpstart + (9 * 3))))
96 bpos++;
97
98 for(i = 0; i < len; i++)
99 {
ff28b140 100 uint8_t c = *p++;
832b75ed
GG
101 bpos += 3;
102 if (bpos == (bpstart + (9 * 3)))
103 bpos++;
ff28b140 104 snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (unsigned int)c);
832b75ed
GG
105 buff[bpos + 2] = ' ';
106 if (no_ascii)
107 buff[cpos++] = ' ';
108 else {
109 if ((c < ' ') || (c >= 0x7f))
110 c='.';
111 buff[cpos++] = c;
112 }
113 if (cpos > (cpstart+15))
114 {
a86ec89e
GI
115 while (cpos > 0 && buff[cpos-1] == ' ')
116 cpos--;
117 buff[cpos] = 0;
832b75ed
GG
118 pout("%s\n", buff);
119 bpos = bpstart;
120 cpos = cpstart;
121 a += 16;
122 memset(buff,' ',80);
ee38a438 123 k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
832b75ed
GG
124 buff[k + 1] = ' ';
125 }
126 }
127 if (cpos > cpstart)
128 {
a86ec89e
GI
129 while (cpos > 0 && buff[cpos-1] == ' ')
130 cpos--;
131 buff[cpos] = 0;
832b75ed
GG
132 pout("%s\n", buff);
133 }
134}
135
ff28b140
TL
136/* This is a heuristic that takes into account the command bytes and length
137 * to decide whether the presented unstructured sequence of bytes could be
138 * a SCSI command. If so it returns true otherwise false. Vendor specific
139 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
140 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
141 * only SCSI commands considered above 16 bytes of length are the Variable
142 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
143 * Both have an inbuilt length field which can be cross checked with clen.
144 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
145 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
146 * structures that are sent across the wire. The FIS register structure is
147 * used to move a command from a SATA host to device, but the ATA 'command'
148 * is not the first byte. So it is harder to say what will happen if a
149 * FIS structure is presented as a SCSI command, hopefully there is a low
150 * probability this function will yield true in that case. */
151bool
152is_scsi_cdb(const uint8_t * cdbp, int clen)
153{
154 int ilen, sa;
155 uint8_t opcode;
156 uint8_t top3bits;
157
158 if (clen < 6)
159 return false;
160 opcode = cdbp[0];
161 top3bits = opcode >> 5;
162 if (0x3 == top3bits) { /* Opcodes 0x60 to 0x7f */
163 if ((clen < 12) || (clen % 4))
164 return false; /* must be modulo 4 and 12 or more bytes */
165 switch (opcode) {
166 case 0x7e: /* Extended cdb (XCDB) */
167 ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
168 return (ilen == clen);
169 case 0x7f: /* Variable Length cdb */
170 ilen = 8 + cdbp[7];
171 sa = sg_get_unaligned_be16(cdbp + 8);
172 /* service action (sa) 0x0 is reserved */
173 return ((ilen == clen) && sa);
174 default:
175 return false;
176 }
177 } else if (clen <= 16) {
178 switch (clen) {
179 case 6:
180 if (top3bits > 0x5) /* vendor */
181 return true;
182 return (0x0 == top3bits); /* 6 byte cdb */
183 case 10:
184 if (top3bits > 0x5) /* vendor */
185 return true;
186 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
187 case 16:
188 if (top3bits > 0x5) /* vendor */
189 return true;
190 return (0x4 == top3bits); /* 16 byte cdb */
191 case 12:
192 if (top3bits > 0x5) /* vendor */
193 return true;
194 return (0x5 == top3bits); /* 12 byte cdb */
195 default:
196 return false;
197 }
198 }
199 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
200 * opcode > 0x7f). */
201 return false;
202}
203
832b75ed 204struct scsi_opcode_name {
ff28b140 205 uint8_t opcode;
832b75ed
GG
206 const char * name;
207};
208
209static struct scsi_opcode_name opcode_name_arr[] = {
210 /* in ascending opcode order */
211 {TEST_UNIT_READY, "test unit ready"}, /* 0x00 */
212 {REQUEST_SENSE, "request sense"}, /* 0x03 */
213 {INQUIRY, "inquiry"}, /* 0x12 */
a37e7145
GG
214 {MODE_SELECT, "mode select(6)"}, /* 0x15 */
215 {MODE_SENSE, "mode sense(6)"}, /* 0x1a */
cfbba5b9 216 {START_STOP_UNIT, "start stop unit"}, /* 0x1b */
832b75ed
GG
217 {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */
218 {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */
cfbba5b9 219 {READ_CAPACITY_10, "read capacity(10)"}, /* 0x25 */
832b75ed 220 {READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */
2127e193 221 {LOG_SELECT, "log select"}, /* 0x4c */
832b75ed
GG
222 {LOG_SENSE, "log sense"}, /* 0x4d */
223 {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */
224 {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */
4d59bff9 225 {SAT_ATA_PASSTHROUGH_16, "ata pass-through(16)"}, /* 0x85 */
cfbba5b9
GI
226 {READ_CAPACITY_16, "read capacity(16)"}, /* 0x9e,0x10 */
227 {REPORT_LUNS, "report luns"}, /* 0xa0 */
4d59bff9 228 {SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */
ee38a438 229 {READ_DEFECT_12, "read defect list(12)"}, /* 0xb7 */
832b75ed
GG
230};
231
cfbba5b9
GI
232static const char * vendor_specific = "<vendor specific>";
233
234/* Need to expand to take service action into account. For commands
235 * of interest the service action is in the 2nd command byte */
ee38a438 236const char *
ff28b140 237scsi_get_opcode_name(uint8_t opcode)
832b75ed 238{
832b75ed 239 int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);
832b75ed 240
cfbba5b9 241 if (opcode >= 0xc0)
a7e8ffec 242 return vendor_specific;
a86ec89e
GI
243 for (int k = 0; k < len; ++k) {
244 struct scsi_opcode_name * onp = &opcode_name_arr[k];
832b75ed
GG
245 if (opcode == onp->opcode)
246 return onp->name;
247 else if (opcode < onp->opcode)
248 return NULL;
249 }
250 return NULL;
251}
252
ee38a438
GI
253void
254scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
255 struct scsi_sense_disect * out)
832b75ed
GG
256{
257 memset(out, 0, sizeof(struct scsi_sense_disect));
4d59bff9 258 if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) {
a86ec89e 259 int resp_code = (io_buf->sensep[0] & 0x7f);
ee38a438 260 out->resp_code = resp_code;
4d59bff9
GG
261 if (resp_code >= 0x72) {
262 out->sense_key = (io_buf->sensep[1] & 0xf);
263 out->asc = io_buf->sensep[2];
264 out->ascq = io_buf->sensep[3];
265 } else if (resp_code >= 0x70) {
266 out->sense_key = (io_buf->sensep[2] & 0xf);
267 if (io_buf->resp_sense_len > 13) {
268 out->asc = io_buf->sensep[12];
269 out->ascq = io_buf->sensep[13];
270 }
832b75ed
GG
271 }
272 }
273}
274
ee38a438
GI
275int
276scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo)
832b75ed
GG
277{
278 switch (sinfo->sense_key) {
a37e7145
GG
279 case SCSI_SK_NO_SENSE:
280 case SCSI_SK_RECOVERED_ERR:
281 return SIMPLE_NO_ERROR;
832b75ed 282 case SCSI_SK_NOT_READY:
ee38a438 283 if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
832b75ed
GG
284 return SIMPLE_ERR_NO_MEDIUM;
285 else if (SCSI_ASC_NOT_READY == sinfo->asc) {
286 if (0x1 == sinfo->ascq)
287 return SIMPLE_ERR_BECOMING_READY;
288 else
289 return SIMPLE_ERR_NOT_READY;
290 } else
291 return SIMPLE_ERR_NOT_READY;
292 case SCSI_SK_MEDIUM_ERROR:
293 case SCSI_SK_HARDWARE_ERROR:
294 return SIMPLE_ERR_MEDIUM_HARDWARE;
295 case SCSI_SK_ILLEGAL_REQUEST:
296 if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)
297 return SIMPLE_ERR_BAD_OPCODE;
ee38a438 298 else if (SCSI_ASC_INVALID_FIELD == sinfo->asc)
832b75ed
GG
299 return SIMPLE_ERR_BAD_FIELD;
300 else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)
301 return SIMPLE_ERR_BAD_PARAM;
302 else
303 return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */
304 case SCSI_SK_UNIT_ATTENTION:
305 return SIMPLE_ERR_TRY_AGAIN;
a37e7145
GG
306 case SCSI_SK_ABORTED_COMMAND:
307 return SIMPLE_ERR_ABORTED_COMMAND;
832b75ed 308 default:
a37e7145 309 return SIMPLE_ERR_UNKNOWN;
832b75ed
GG
310 }
311}
312
ee38a438
GI
313const char *
314scsiErrString(int scsiErr)
832b75ed
GG
315{
316 if (scsiErr < 0)
317 return strerror(-scsiErr);
318 switch (scsiErr) {
ee38a438 319 case SIMPLE_NO_ERROR:
832b75ed 320 return "no error";
ee38a438 321 case SIMPLE_ERR_NOT_READY:
832b75ed 322 return "device not ready";
ee38a438 323 case SIMPLE_ERR_BAD_OPCODE:
832b75ed 324 return "unsupported scsi opcode";
ee38a438 325 case SIMPLE_ERR_BAD_FIELD:
832b75ed 326 return "unsupported field in scsi command";
ee38a438 327 case SIMPLE_ERR_BAD_PARAM:
832b75ed 328 return "badly formed scsi parameters";
ee38a438 329 case SIMPLE_ERR_BAD_RESP:
832b75ed 330 return "scsi response fails sanity test";
ee38a438 331 case SIMPLE_ERR_NO_MEDIUM:
832b75ed 332 return "no medium present";
ee38a438 333 case SIMPLE_ERR_BECOMING_READY:
832b75ed 334 return "device will be ready soon";
ee38a438 335 case SIMPLE_ERR_TRY_AGAIN:
832b75ed 336 return "unit attention reported, try again";
ee38a438 337 case SIMPLE_ERR_MEDIUM_HARDWARE:
832b75ed 338 return "medium or hardware error (serious)";
ee38a438 339 case SIMPLE_ERR_UNKNOWN:
a37e7145 340 return "unknown error (unexpected sense key)";
ee38a438 341 case SIMPLE_ERR_ABORTED_COMMAND:
1953ff6d 342 return "aborted command";
832b75ed
GG
343 default:
344 return "unknown error";
345 }
346}
347
a7e8ffec
GI
348/* Iterates to next designation descriptor in the device identification
349 * VPD page. The 'initial_desig_desc' should point to start of first
350 * descriptor with 'page_len' being the number of valid bytes in that
351 * and following descriptors. To start, 'off' should point to a negative
352 * value, thereafter it should point to the value yielded by the previous
353 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
354 * descriptor; returns -1 if normal end condition and -2 for an abnormal
355 * termination. Matches association, designator_type and/or code_set when
356 * any of those values are greater than or equal to zero. */
ee38a438
GI
357int
358scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
359 int * off, int m_assoc, int m_desig_type, int m_code_set)
a7e8ffec
GI
360{
361 const unsigned char * ucp;
a86ec89e 362 int k;
a7e8ffec
GI
363
364 for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) {
365 k = (k < 0) ? 0 : (k + ucp[k + 3] + 4);
366 if ((k + 4) > page_len)
367 break;
a86ec89e 368 int c_set = (ucp[k] & 0xf);
a7e8ffec
GI
369 if ((m_code_set >= 0) && (m_code_set != c_set))
370 continue;
a86ec89e 371 int assoc = ((ucp[k + 1] >> 4) & 0x3);
a7e8ffec
GI
372 if ((m_assoc >= 0) && (m_assoc != assoc))
373 continue;
a86ec89e 374 int desig_type = (ucp[k + 1] & 0xf);
a7e8ffec
GI
375 if ((m_desig_type >= 0) && (m_desig_type != desig_type))
376 continue;
377 *off = k;
378 return 0;
379 }
380 return (k == page_len) ? -1 : -2;
381}
382
383/* Decode VPD page 0x83 logical unit designator into a string. If both
384 * numeric address and SCSI name string present, prefer the former.
385 * Returns 0 on success, -1 on error with error string in s. */
ee38a438
GI
386int
387scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
388 int * transport)
a7e8ffec 389{
a7e8ffec 390 if (transport)
ee38a438 391 *transport = -1;
a7e8ffec 392 if (slen < 32) {
ee38a438
GI
393 if (slen > 0)
394 s[0] = '\0';
395 return -1;
a7e8ffec 396 }
a86ec89e 397
a7e8ffec 398 s[0] = '\0';
a86ec89e
GI
399 int si = 0;
400 int have_scsi_ns = 0;
401 int off = -1;
402 int u;
a7e8ffec 403 while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) {
a86ec89e
GI
404 const unsigned char * ucp = b + off;
405 int i_len = ucp[3];
a7e8ffec 406 if ((off + i_len + 4) > blen) {
ee38a438
GI
407 snprintf(s+si, slen-si, "error: designator length");
408 return -1;
a7e8ffec 409 }
a86ec89e 410 int assoc = ((ucp[1] >> 4) & 0x3);
ee38a438
GI
411 if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
412 *transport = (ucp[0] >> 4) & 0xf;
413 if (0 != assoc)
414 continue;
a86ec89e
GI
415 const unsigned char * ip = ucp + 4;
416 int c_set = (ucp[0] & 0xf);
417 int desig_type = (ucp[1] & 0xf);
a7e8ffec 418
a86ec89e 419 int naa;
a7e8ffec
GI
420 switch (desig_type) {
421 case 0: /* vendor specific */
422 case 1: /* T10 vendor identification */
423 break;
424 case 2: /* EUI-64 based */
425 if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
ee38a438
GI
426 snprintf(s+si, slen-si, "error: EUI-64 length");
427 return -1;
428 }
429 if (have_scsi_ns)
430 si = 0;
431 si += snprintf(s+si, slen-si, "0x");
a86ec89e 432 for (int m = 0; m < i_len; ++m)
ee38a438 433 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
a7e8ffec
GI
434 break;
435 case 3: /* NAA */
436 if (1 != c_set) {
ee38a438
GI
437 snprintf(s+si, slen-si, "error: NAA bad code_set");
438 return -1;
439 }
a7e8ffec
GI
440 naa = (ip[0] >> 4) & 0xff;
441 if ((naa < 2) || (naa > 6) || (4 == naa)) {
ee38a438
GI
442 snprintf(s+si, slen-si, "error: unexpected NAA");
443 return -1;
a7e8ffec 444 }
ee38a438
GI
445 if (have_scsi_ns)
446 si = 0;
a7e8ffec
GI
447 if (2 == naa) { /* NAA IEEE Extended */
448 if (8 != i_len) {
ee38a438
GI
449 snprintf(s+si, slen-si, "error: NAA 2 length");
450 return -1;
a7e8ffec 451 }
ee38a438 452 si += snprintf(s+si, slen-si, "0x");
a86ec89e 453 for (int m = 0; m < 8; ++m)
ee38a438 454 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
a7e8ffec
GI
455 } else if ((3 == naa ) || (5 == naa)) {
456 /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
457 if (8 != i_len) {
ee38a438
GI
458 snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
459 return -1;
a7e8ffec 460 }
ee38a438 461 si += snprintf(s+si, slen-si, "0x");
a86ec89e 462 for (int m = 0; m < 8; ++m)
ee38a438 463 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
a7e8ffec
GI
464 } else if (6 == naa) { /* NAA IEEE Registered extended */
465 if (16 != i_len) {
ee38a438
GI
466 snprintf(s+si, slen-si, "error: NAA 6 length");
467 return -1;
a7e8ffec 468 }
ee38a438 469 si += snprintf(s+si, slen-si, "0x");
a86ec89e 470 for (int m = 0; m < 16; ++m)
ee38a438 471 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
a7e8ffec
GI
472 }
473 break;
474 case 4: /* Relative target port */
475 case 5: /* (primary) Target port group */
476 case 6: /* Logical unit group */
477 case 7: /* MD5 logical unit identifier */
478 break;
479 case 8: /* SCSI name string */
480 if (3 != c_set) {
ee38a438
GI
481 snprintf(s+si, slen-si, "error: SCSI name string");
482 return -1;
a7e8ffec
GI
483 }
484 /* does %s print out UTF-8 ok?? */
ee38a438
GI
485 if (si == 0) {
486 si += snprintf(s+si, slen-si, "%s", (const char *)ip);
487 ++have_scsi_ns;
488 }
a7e8ffec
GI
489 break;
490 default: /* reserved */
491 break;
492 }
493 }
494 if (-2 == u) {
ee38a438
GI
495 snprintf(s+si, slen-si, "error: bad structure");
496 return -1;
a7e8ffec
GI
497 }
498 return 0;
499}
500
832b75ed 501/* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if
ff28b140
TL
502 * command not supported, 3 if field (within command) not supported or
503 * returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a).
504 * N.B. Sets PC==1 to fetch "current cumulative" log pages.
505 * If known_resp_len > 0 then a single fetch is done for this response
506 * length. If known_resp_len == 0 then twin fetches are performed, the
507 * first to deduce the response length, then send the same command again
508 * requesting the deduced response length. This protects certain fragile
509 * HBAs. The twin fetch technique should not be used with the TapeAlert
510 * log page since it clears its state flags after each fetch. If
511 * known_resp_len < 0 then does single fetch for BufLen bytes. */
ee38a438 512int
ff28b140 513scsiLogSense(scsi_device * device, int pagenum, int subpagenum, uint8_t *pBuf,
ee38a438 514 int bufLen, int known_resp_len)
832b75ed 515{
ff28b140 516 int pageLen;
832b75ed
GG
517 struct scsi_cmnd_io io_hdr;
518 struct scsi_sense_disect sinfo;
ff28b140
TL
519 uint8_t cdb[10];
520 uint8_t sense[32];
832b75ed
GG
521
522 if (known_resp_len > bufLen)
523 return -EIO;
524 if (known_resp_len > 0)
525 pageLen = known_resp_len;
ff28b140
TL
526 else if (known_resp_len < 0)
527 pageLen = bufLen;
528 else { /* 0 == known_resp_len */
832b75ed
GG
529 /* Starting twin fetch strategy: first fetch to find respone length */
530 pageLen = 4;
531 if (pageLen > bufLen)
532 return -EIO;
533 else
534 memset(pBuf, 0, pageLen);
535
536 memset(&io_hdr, 0, sizeof(io_hdr));
537 memset(cdb, 0, sizeof(cdb));
538 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
539 io_hdr.dxfer_len = pageLen;
540 io_hdr.dxferp = pBuf;
541 cdb[0] = LOG_SENSE;
ff28b140
TL
542 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
543 cdb[3] = subpagenum; /* 0 for no sub-page */
544 sg_put_unaligned_be16(pageLen, cdb + 7);
832b75ed
GG
545 io_hdr.cmnd = cdb;
546 io_hdr.cmnd_len = sizeof(cdb);
547 io_hdr.sensep = sense;
548 io_hdr.max_sense_len = sizeof(sense);
549 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
2127e193
GI
550
551 if (!device->scsi_pass_through(&io_hdr))
552 return -device->get_errno();
832b75ed 553 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e 554 int res;
832b75ed
GG
555 if ((res = scsiSimpleSenseFilter(&sinfo)))
556 return res;
557 /* sanity check on response */
cfbba5b9 558 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
832b75ed 559 return SIMPLE_ERR_BAD_RESP;
ff28b140
TL
560 uint16_t u = sg_get_unaligned_be16(pBuf + 2);
561 if (0 == u)
832b75ed 562 return SIMPLE_ERR_BAD_RESP;
ff28b140 563 pageLen = u + 4;
a37e7145
GG
564 if (4 == pageLen) /* why define a lpage with no payload? */
565 pageLen = 252; /* some IBM tape drives don't like double fetch */
832b75ed
GG
566 /* some SCSI HBA don't like "odd" length transfers */
567 if (pageLen % 2)
ee38a438 568 pageLen += 1;
832b75ed
GG
569 if (pageLen > bufLen)
570 pageLen = bufLen;
571 }
572 memset(pBuf, 0, 4);
573 memset(&io_hdr, 0, sizeof(io_hdr));
574 memset(cdb, 0, sizeof(cdb));
575 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
576 io_hdr.dxfer_len = pageLen;
577 io_hdr.dxferp = pBuf;
578 cdb[0] = LOG_SENSE;
579 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
ff28b140
TL
580 cdb[3] = subpagenum;
581 sg_put_unaligned_be16(pageLen, cdb + 7);
832b75ed
GG
582 io_hdr.cmnd = cdb;
583 io_hdr.cmnd_len = sizeof(cdb);
584 io_hdr.sensep = sense;
585 io_hdr.max_sense_len = sizeof(sense);
586 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
587
2127e193
GI
588 if (!device->scsi_pass_through(&io_hdr))
589 return -device->get_errno();
832b75ed 590 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e 591 int status = scsiSimpleSenseFilter(&sinfo);
832b75ed
GG
592 if (0 != status)
593 return status;
594 /* sanity check on response */
cfbba5b9 595 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
832b75ed 596 return SIMPLE_ERR_BAD_RESP;
ff28b140 597 if (0 == sg_get_unaligned_be16(pBuf + 2))
832b75ed
GG
598 return SIMPLE_ERR_BAD_RESP;
599 return 0;
600}
601
2127e193
GI
602/* Sends a LOG SELECT command. Can be used to set log page values
603 * or reset one log page (or all of them) to its defaults (typically zero).
604 * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if
605 * field in command not supported, * 4 if bad parameter to command or
606 * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */
ee38a438
GI
607int
608scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
ff28b140 609 int subpagenum, uint8_t *pBuf, int bufLen)
2127e193
GI
610{
611 struct scsi_cmnd_io io_hdr;
612 struct scsi_sense_disect sinfo;
ff28b140
TL
613 uint8_t cdb[10];
614 uint8_t sense[32];
2127e193
GI
615
616 memset(&io_hdr, 0, sizeof(io_hdr));
617 memset(cdb, 0, sizeof(cdb));
618 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
619 io_hdr.dxfer_len = bufLen;
620 io_hdr.dxferp = pBuf;
621 cdb[0] = LOG_SELECT;
622 cdb[1] = (pcr ? 2 : 0) | (sp ? 1 : 0);
623 cdb[2] = ((pc << 6) & 0xc0) | (pagenum & 0x3f);
624 cdb[3] = (subpagenum & 0xff);
ff28b140 625 sg_put_unaligned_be16(bufLen, cdb + 7);
2127e193
GI
626 io_hdr.cmnd = cdb;
627 io_hdr.cmnd_len = sizeof(cdb);
628 io_hdr.sensep = sense;
629 io_hdr.max_sense_len = sizeof(sense);
630 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
631
632 if (!device->scsi_pass_through(&io_hdr))
633 return -device->get_errno();
634 scsi_do_sense_disect(&io_hdr, &sinfo);
635 return scsiSimpleSenseFilter(&sinfo);
636}
637
832b75ed
GG
638/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
639 * 2 if command not supported (then MODE SENSE(10) should be supported),
ee38a438 640 * 3 if field in command not supported or returns negated errno.
832b75ed 641 * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
ee38a438
GI
642int
643scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
ff28b140 644 uint8_t *pBuf, int bufLen)
832b75ed
GG
645{
646 struct scsi_cmnd_io io_hdr;
647 struct scsi_sense_disect sinfo;
ff28b140
TL
648 uint8_t cdb[6];
649 uint8_t sense[32];
832b75ed
GG
650
651 if ((bufLen < 0) || (bufLen > 255))
652 return -EINVAL;
653 memset(&io_hdr, 0, sizeof(io_hdr));
654 memset(cdb, 0, sizeof(cdb));
655 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
656 io_hdr.dxfer_len = bufLen;
657 io_hdr.dxferp = pBuf;
658 cdb[0] = MODE_SENSE;
659 cdb[2] = (pc << 6) | (pagenum & 0x3f);
4d59bff9 660 cdb[3] = subpagenum;
832b75ed
GG
661 cdb[4] = bufLen;
662 io_hdr.cmnd = cdb;
663 io_hdr.cmnd_len = sizeof(cdb);
664 io_hdr.sensep = sense;
665 io_hdr.max_sense_len = sizeof(sense);
666 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
667
2127e193
GI
668 if (!device->scsi_pass_through(&io_hdr))
669 return -device->get_errno();
832b75ed 670 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e 671 int status = scsiSimpleSenseFilter(&sinfo);
832b75ed 672 if (SIMPLE_ERR_TRY_AGAIN == status) {
2127e193
GI
673 if (!device->scsi_pass_through(&io_hdr))
674 return -device->get_errno();
832b75ed
GG
675 scsi_do_sense_disect(&io_hdr, &sinfo);
676 status = scsiSimpleSenseFilter(&sinfo);
677 }
678 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
679 int offset;
680
681 offset = scsiModePageOffset(pBuf, bufLen, 0);
682 if (offset < 0)
683 return SIMPLE_ERR_BAD_RESP;
684 else if (pagenum != (pBuf[offset] & 0x3f))
685 return SIMPLE_ERR_BAD_RESP;
686 }
687 return status;
688}
689
690/* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response
691 * from a corresponding 6 byte MODE SENSE command. Such a response should
692 * have a 4 byte header followed by 0 or more 8 byte block descriptors
693 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY,
ee38a438 694 * 2 if command not supported (then MODE SELECT(10) may be supported),
832b75ed
GG
695 * 3 if field in command not supported, 4 if bad parameter to command
696 * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
ee38a438 697int
ff28b140 698scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
832b75ed
GG
699{
700 struct scsi_cmnd_io io_hdr;
701 struct scsi_sense_disect sinfo;
ff28b140
TL
702 uint8_t cdb[6];
703 uint8_t sense[32];
2127e193 704 int pg_offset, pg_len, hdr_plus_1_pg;
832b75ed
GG
705
706 pg_offset = 4 + pBuf[3];
707 if (pg_offset + 2 >= bufLen)
708 return -EINVAL;
709 pg_len = pBuf[pg_offset + 1] + 2;
710 hdr_plus_1_pg = pg_offset + pg_len;
711 if (hdr_plus_1_pg > bufLen)
712 return -EINVAL;
ff28b140 713 pBuf[0] = 0; /* Length of returned mode sense data reserved for SELECT */
832b75ed
GG
714 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
715 memset(&io_hdr, 0, sizeof(io_hdr));
716 memset(cdb, 0, sizeof(cdb));
717 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
718 io_hdr.dxfer_len = hdr_plus_1_pg;
719 io_hdr.dxferp = pBuf;
720 cdb[0] = MODE_SELECT;
721 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
722 cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */
723 io_hdr.cmnd = cdb;
724 io_hdr.cmnd_len = sizeof(cdb);
725 io_hdr.sensep = sense;
726 io_hdr.max_sense_len = sizeof(sense);
727 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
728
2127e193
GI
729 if (!device->scsi_pass_through(&io_hdr))
730 return -device->get_errno();
832b75ed
GG
731 scsi_do_sense_disect(&io_hdr, &sinfo);
732 return scsiSimpleSenseFilter(&sinfo);
733}
734
ee38a438 735/* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
832b75ed 736 * not supported (then MODE SENSE(6) might be supported), 3 if field in
ee38a438 737 * command not supported or returns negated errno.
832b75ed 738 * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
ee38a438
GI
739int
740scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
ff28b140 741 uint8_t *pBuf, int bufLen)
832b75ed
GG
742{
743 struct scsi_cmnd_io io_hdr;
744 struct scsi_sense_disect sinfo;
ff28b140
TL
745 uint8_t cdb[10];
746 uint8_t sense[32];
832b75ed
GG
747
748 memset(&io_hdr, 0, sizeof(io_hdr));
749 memset(cdb, 0, sizeof(cdb));
750 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
751 io_hdr.dxfer_len = bufLen;
752 io_hdr.dxferp = pBuf;
753 cdb[0] = MODE_SENSE_10;
754 cdb[2] = (pc << 6) | (pagenum & 0x3f);
4d59bff9 755 cdb[3] = subpagenum;
ff28b140 756 sg_put_unaligned_be16(bufLen, cdb + 7);
832b75ed
GG
757 io_hdr.cmnd = cdb;
758 io_hdr.cmnd_len = sizeof(cdb);
759 io_hdr.sensep = sense;
760 io_hdr.max_sense_len = sizeof(sense);
761 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
762
2127e193
GI
763 if (!device->scsi_pass_through(&io_hdr))
764 return -device->get_errno();
832b75ed 765 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e 766 int status = scsiSimpleSenseFilter(&sinfo);
832b75ed 767 if (SIMPLE_ERR_TRY_AGAIN == status) {
2127e193
GI
768 if (!device->scsi_pass_through(&io_hdr))
769 return -device->get_errno();
832b75ed
GG
770 scsi_do_sense_disect(&io_hdr, &sinfo);
771 status = scsiSimpleSenseFilter(&sinfo);
772 }
773 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
774 int offset;
775
776 offset = scsiModePageOffset(pBuf, bufLen, 1);
777 if (offset < 0)
778 return SIMPLE_ERR_BAD_RESP;
779 else if (pagenum != (pBuf[offset] & 0x3f))
780 return SIMPLE_ERR_BAD_RESP;
781 }
782 return status;
783}
784
785/* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response
786 * from a corresponding 10 byte MODE SENSE command. Such a response should
787 * have a 8 byte header followed by 0 or more 8 byte block descriptors
ee38a438 788 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
832b75ed
GG
789 * command not supported (then MODE SELECT(6) may be supported), 3 if field
790 * in command not supported, 4 if bad parameter to command or returns
791 * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
ee38a438 792int
ff28b140 793scsiModeSelect10(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
832b75ed
GG
794{
795 struct scsi_cmnd_io io_hdr;
796 struct scsi_sense_disect sinfo;
ff28b140
TL
797 uint8_t cdb[10];
798 uint8_t sense[32];
2127e193 799 int pg_offset, pg_len, hdr_plus_1_pg;
832b75ed 800
ff28b140 801 pg_offset = 8 + sg_get_unaligned_be16(pBuf + 6);
832b75ed
GG
802 if (pg_offset + 2 >= bufLen)
803 return -EINVAL;
804 pg_len = pBuf[pg_offset + 1] + 2;
805 hdr_plus_1_pg = pg_offset + pg_len;
806 if (hdr_plus_1_pg > bufLen)
807 return -EINVAL;
ee38a438 808 pBuf[0] = 0;
832b75ed
GG
809 pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */
810 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
811 memset(&io_hdr, 0, sizeof(io_hdr));
812 memset(cdb, 0, sizeof(cdb));
813 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
814 io_hdr.dxfer_len = hdr_plus_1_pg;
815 io_hdr.dxferp = pBuf;
816 cdb[0] = MODE_SELECT_10;
817 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
ff28b140
TL
818 /* make sure only one page sent */
819 sg_put_unaligned_be16(hdr_plus_1_pg, cdb + 7);
832b75ed
GG
820 io_hdr.cmnd = cdb;
821 io_hdr.cmnd_len = sizeof(cdb);
822 io_hdr.sensep = sense;
823 io_hdr.max_sense_len = sizeof(sense);
824 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
825
2127e193
GI
826 if (!device->scsi_pass_through(&io_hdr))
827 return -device->get_errno();
832b75ed
GG
828 scsi_do_sense_disect(&io_hdr, &sinfo);
829 return scsiSimpleSenseFilter(&sinfo);
830}
831
832/* Standard INQUIRY returns 0 for ok, anything else is a major problem.
833 * bufLen should be 36 for unsafe devices (like USB mass storage stuff)
834 * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
ee38a438 835int
ff28b140 836scsiStdInquiry(scsi_device * device, uint8_t *pBuf, int bufLen)
832b75ed
GG
837{
838 struct scsi_sense_disect sinfo;
839 struct scsi_cmnd_io io_hdr;
ff28b140
TL
840 uint8_t cdb[6];
841 uint8_t sense[32];
832b75ed 842
ee38a438 843 if ((bufLen < 0) || (bufLen > 1023))
832b75ed
GG
844 return -EINVAL;
845 memset(&io_hdr, 0, sizeof(io_hdr));
846 memset(cdb, 0, sizeof(cdb));
847 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
848 io_hdr.dxfer_len = bufLen;
849 io_hdr.dxferp = pBuf;
850 cdb[0] = INQUIRY;
ff28b140 851 sg_put_unaligned_be16(bufLen, cdb + 3);
832b75ed
GG
852 io_hdr.cmnd = cdb;
853 io_hdr.cmnd_len = sizeof(cdb);
854 io_hdr.sensep = sense;
855 io_hdr.max_sense_len = sizeof(sense);
856 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
857
2127e193
GI
858 if (!device->scsi_pass_through(&io_hdr))
859 return -device->get_errno();
832b75ed
GG
860 scsi_do_sense_disect(&io_hdr, &sinfo);
861 return scsiSimpleSenseFilter(&sinfo);
862}
863
864/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
ee38a438 865 * (unlikely), 2 if command not supported, 3 if field in command not
832b75ed
GG
866 * supported, 5 if response indicates that EVPD bit ignored or returns
867 * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
ee38a438 868int
ff28b140 869scsiInquiryVpd(scsi_device * device, int vpd_page, uint8_t *pBuf, int bufLen)
832b75ed
GG
870{
871 struct scsi_cmnd_io io_hdr;
872 struct scsi_sense_disect sinfo;
ff28b140
TL
873 uint8_t cdb[6];
874 uint8_t sense[32];
2127e193 875 int res;
832b75ed 876
ee38a438
GI
877 /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */
878 if ((SCSI_VPD_SUPPORTED_VPD_PAGES != vpd_page) &&
879 supported_vpd_pages_p &&
880 (! supported_vpd_pages_p->is_supported(vpd_page)))
881 return 3;
882
883 if ((bufLen < 0) || (bufLen > 1023))
832b75ed 884 return -EINVAL;
ee38a438 885try_again:
832b75ed
GG
886 memset(&io_hdr, 0, sizeof(io_hdr));
887 memset(cdb, 0, sizeof(cdb));
888 if (bufLen > 1)
889 pBuf[1] = 0x0;
890 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
891 io_hdr.dxfer_len = bufLen;
892 io_hdr.dxferp = pBuf;
893 cdb[0] = INQUIRY;
894 cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
895 cdb[2] = vpd_page;
ff28b140 896 sg_put_unaligned_be16(bufLen, cdb + 3);
832b75ed
GG
897 io_hdr.cmnd = cdb;
898 io_hdr.cmnd_len = sizeof(cdb);
899 io_hdr.sensep = sense;
900 io_hdr.max_sense_len = sizeof(sense);
901 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
902
2127e193
GI
903 if (!device->scsi_pass_through(&io_hdr))
904 return -device->get_errno();
832b75ed 905 scsi_do_sense_disect(&io_hdr, &sinfo);
ee38a438
GI
906 if ((SCSI_STATUS_CHECK_CONDITION == io_hdr.scsi_status) &&
907 (SCSI_SK_ILLEGAL_REQUEST == sinfo.sense_key) &&
908 (SCSI_ASC_INVALID_FIELD == sinfo.asc) &&
909 (cdb[3] > 0)) {
910 bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */
911 goto try_again;
912 }
913
832b75ed
GG
914 if ((res = scsiSimpleSenseFilter(&sinfo)))
915 return res;
916 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
917 if (bufLen > 1) {
918 if (vpd_page == pBuf[1]) {
919 if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2]))
920 return SIMPLE_ERR_BAD_RESP;
921 } else
922 return SIMPLE_ERR_BAD_RESP;
923 }
924 return 0;
925}
926
927/* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
928 * SPC-3 section 6.27 (rev 22a) */
ee38a438
GI
929int
930scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
832b75ed
GG
931{
932 struct scsi_cmnd_io io_hdr;
ff28b140
TL
933 uint8_t cdb[6];
934 uint8_t sense[32];
935 uint8_t buff[18];
936 int sz_buff = sizeof(buff);
832b75ed
GG
937
938 memset(&io_hdr, 0, sizeof(io_hdr));
939 memset(cdb, 0, sizeof(cdb));
940 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
ff28b140 941 io_hdr.dxfer_len = sz_buff;
832b75ed
GG
942 io_hdr.dxferp = buff;
943 cdb[0] = REQUEST_SENSE;
ff28b140 944 cdb[4] = sz_buff;
832b75ed
GG
945 io_hdr.cmnd = cdb;
946 io_hdr.cmnd_len = sizeof(cdb);
947 io_hdr.sensep = sense;
948 io_hdr.max_sense_len = sizeof(sense);
949 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
950
2127e193
GI
951 if (!device->scsi_pass_through(&io_hdr))
952 return -device->get_errno();
953 if (sense_info) {
ff28b140 954 uint8_t resp_code = buff[0] & 0x7f;
ee38a438 955 sense_info->resp_code = resp_code;
832b75ed
GG
956 sense_info->sense_key = buff[2] & 0xf;
957 sense_info->asc = 0;
958 sense_info->ascq = 0;
ee38a438 959 if ((0x70 == resp_code) || (0x71 == resp_code)) {
a86ec89e 960 int len = buff[7] + 8;
832b75ed
GG
961 if (len > 13) {
962 sense_info->asc = buff[12];
963 sense_info->ascq = buff[13];
964 }
965 }
ff28b140 966 // fill progress indicator, if available
ee38a438
GI
967 sense_info->progress = -1;
968 switch (resp_code) {
969 const unsigned char * ucp;
970 int sk, sk_pr;
971 case 0x70:
972 case 0x71:
973 sk = (buff[2] & 0xf);
ff28b140 974 if (! ((SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk))) {
ee38a438
GI
975 break;
976 }
977 if (buff[15] & 0x80) { /* SKSV bit set */
ff28b140 978 sense_info->progress = sg_get_unaligned_be16(buff + 16);
ee38a438
GI
979 break;
980 } else {
981 break;
982 }
983 case 0x72:
984 case 0x73:
985 /* sense key specific progress (0x2) or progress descriptor (0xa) */
986 sk = (buff[1] & 0xf);
987 sk_pr = (SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk);
ff28b140 988 if (sk_pr && ((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 2))) &&
ee38a438 989 (0x6 == ucp[1]) && (0x80 & ucp[4])) {
ff28b140 990 sense_info->progress = sg_get_unaligned_be16(ucp + 5);
ee38a438 991 break;
ff28b140 992 } else if (((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 0xa))) &&
ee38a438 993 ((0x6 == ucp[1]))) {
ff28b140 994 sense_info->progress = sg_get_unaligned_be16(ucp + 6);
ee38a438
GI
995 break;
996 } else
997 break;
998 default:
999 return 0;
1000 }
832b75ed 1001 }
2127e193 1002 return 0;
832b75ed
GG
1003}
1004
1005/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
1006 * not supported, 3 if field in command not supported or returns negated
1007 * errno. SPC-3 section 6.28 (rev 22a) */
ee38a438 1008int
ff28b140 1009scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf,
ee38a438 1010 int bufLen)
832b75ed
GG
1011{
1012 struct scsi_cmnd_io io_hdr;
1013 struct scsi_sense_disect sinfo;
ff28b140
TL
1014 uint8_t cdb[6];
1015 uint8_t sense[32];
832b75ed
GG
1016
1017 memset(&io_hdr, 0, sizeof(io_hdr));
1018 memset(cdb, 0, sizeof(cdb));
1019 io_hdr.dxfer_dir = bufLen ? DXFER_TO_DEVICE: DXFER_NONE;
1020 io_hdr.dxfer_len = bufLen;
1021 io_hdr.dxferp = pBuf;
1022 cdb[0] = SEND_DIAGNOSTIC;
1023 if (SCSI_DIAG_DEF_SELF_TEST == functioncode)
1024 cdb[1] = 0x4; /* SelfTest bit */
1025 else if (SCSI_DIAG_NO_SELF_TEST != functioncode)
1026 cdb[1] = (functioncode & 0x7) << 5; /* SelfTest _code_ */
1027 else /* SCSI_DIAG_NO_SELF_TEST == functioncode */
1028 cdb[1] = 0x10; /* PF bit */
ff28b140 1029 sg_put_unaligned_be16(bufLen, cdb + 3);
832b75ed
GG
1030 io_hdr.cmnd = cdb;
1031 io_hdr.cmnd_len = sizeof(cdb);
1032 io_hdr.sensep = sense;
1033 io_hdr.max_sense_len = sizeof(sense);
1034 /* worst case is an extended foreground self test on a big disk */
1035 io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST;
ee38a438 1036
2127e193
GI
1037 if (!device->scsi_pass_through(&io_hdr))
1038 return -device->get_errno();
832b75ed
GG
1039 scsi_do_sense_disect(&io_hdr, &sinfo);
1040 return scsiSimpleSenseFilter(&sinfo);
1041}
1042
832b75ed 1043/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
ee38a438
GI
1044static int
1045_testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
832b75ed
GG
1046{
1047 struct scsi_cmnd_io io_hdr;
ff28b140
TL
1048 uint8_t cdb[6];
1049 uint8_t sense[32];
832b75ed
GG
1050
1051 memset(&io_hdr, 0, sizeof(io_hdr));
1052 memset(cdb, 0, sizeof(cdb));
1053 io_hdr.dxfer_dir = DXFER_NONE;
1054 io_hdr.dxfer_len = 0;
1055 io_hdr.dxferp = NULL;
1056 cdb[0] = TEST_UNIT_READY;
1057 io_hdr.cmnd = cdb;
1058 io_hdr.cmnd_len = sizeof(cdb);
1059 io_hdr.sensep = sense;
1060 io_hdr.max_sense_len = sizeof(sense);
1061 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1062
2127e193
GI
1063 if (!device->scsi_pass_through(&io_hdr))
1064 return -device->get_errno();
832b75ed
GG
1065 scsi_do_sense_disect(&io_hdr, sinfo);
1066 return 0;
1067}
1068
1069/* Returns 0 for device responds and media ready, 1 for device responds and
1070 media not ready, or returns a negated errno value */
ee38a438
GI
1071int
1072scsiTestUnitReady(scsi_device * device)
832b75ed
GG
1073{
1074 struct scsi_sense_disect sinfo;
1075 int status;
1076
1077 status = _testunitready(device, &sinfo);
1078 if (0 != status)
1079 return status;
1080 status = scsiSimpleSenseFilter(&sinfo);
1081 if (SIMPLE_ERR_TRY_AGAIN == status) {
1082 /* power on reset, media changed, ok ... try again */
ee38a438 1083 status = _testunitready(device, &sinfo);
832b75ed
GG
1084 if (0 != status)
1085 return status;
1086 status = scsiSimpleSenseFilter(&sinfo);
1087 }
1088 return status;
1089}
1090
1091/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
a86ec89e
GI
1092 * command not supported, 3 if field in command not supported, 101 if
1093 * defect list not found (e.g. SSD may not have defect list) or returns
832b75ed 1094 * negated errno. SBC-2 section 5.12 (rev 16) */
ee38a438
GI
1095int
1096scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
ff28b140 1097 int dl_format, uint8_t *pBuf, int bufLen)
832b75ed
GG
1098{
1099 struct scsi_cmnd_io io_hdr;
1100 struct scsi_sense_disect sinfo;
ff28b140
TL
1101 uint8_t cdb[10];
1102 uint8_t sense[32];
832b75ed
GG
1103
1104 memset(&io_hdr, 0, sizeof(io_hdr));
1105 memset(cdb, 0, sizeof(cdb));
1106 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
1107 io_hdr.dxfer_len = bufLen;
1108 io_hdr.dxferp = pBuf;
1109 cdb[0] = READ_DEFECT_10;
1110 cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) |
1111 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
ff28b140 1112 sg_put_unaligned_be16(bufLen, cdb + 7);
832b75ed
GG
1113 io_hdr.cmnd = cdb;
1114 io_hdr.cmnd_len = sizeof(cdb);
1115 io_hdr.sensep = sense;
1116 io_hdr.max_sense_len = sizeof(sense);
1117 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1118
2127e193
GI
1119 if (!device->scsi_pass_through(&io_hdr))
1120 return -device->get_errno();
832b75ed 1121 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e
GI
1122 /* Look for "(Primary|Grown) defect list not found" */
1123 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1124 return 101;
832b75ed
GG
1125 return scsiSimpleSenseFilter(&sinfo);
1126}
1127
ee38a438 1128/* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if
a86ec89e
GI
1129 * command not supported, 3 if field in command not supported, 101 if
1130 * defect list not found (e.g. SSD may not have defect list) or returns
ee38a438
GI
1131 * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */
1132int
1133scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
ff28b140 1134 int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
ee38a438
GI
1135{
1136 struct scsi_cmnd_io io_hdr;
1137 struct scsi_sense_disect sinfo;
ff28b140
TL
1138 uint8_t cdb[12];
1139 uint8_t sense[32];
ee38a438
GI
1140
1141 memset(&io_hdr, 0, sizeof(io_hdr));
1142 memset(cdb, 0, sizeof(cdb));
1143 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
1144 io_hdr.dxfer_len = bufLen;
1145 io_hdr.dxferp = pBuf;
1146 cdb[0] = READ_DEFECT_12;
1147 cdb[1] = (unsigned char)(((req_plist << 4) & 0x10) |
1148 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
ff28b140
TL
1149 sg_put_unaligned_be32(addrDescIndex, cdb + 2);
1150 sg_put_unaligned_be32(bufLen, cdb + 6);
ee38a438
GI
1151 io_hdr.cmnd = cdb;
1152 io_hdr.cmnd_len = sizeof(cdb);
1153 io_hdr.sensep = sense;
1154 io_hdr.max_sense_len = sizeof(sense);
1155 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1156
1157 if (!device->scsi_pass_through(&io_hdr))
1158 return -device->get_errno();
1159 scsi_do_sense_disect(&io_hdr, &sinfo);
a86ec89e
GI
1160 /* Look for "(Primary|Grown) defect list not found" */
1161 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1162 return 101;
ee38a438
GI
1163 return scsiSimpleSenseFilter(&sinfo);
1164}
1165
a7e8ffec
GI
1166/* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1167 * command not supported, 3 if field in command not supported or returns
1168 * negated errno. SBC-3 section 5.15 (rev 26) */
ee38a438
GI
1169int
1170scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
1171 unsigned int * lb_sizep)
a7e8ffec
GI
1172{
1173 int res;
1174 struct scsi_cmnd_io io_hdr;
1175 struct scsi_sense_disect sinfo;
ff28b140
TL
1176 uint8_t cdb[10];
1177 uint8_t sense[32];
1178 uint8_t resp[8];
a7e8ffec
GI
1179
1180 memset(&io_hdr, 0, sizeof(io_hdr));
1181 memset(cdb, 0, sizeof(cdb));
1182 memset(resp, 0, sizeof(resp));
1183 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
1184 io_hdr.dxfer_len = sizeof(resp);
1185 io_hdr.dxferp = resp;
1186 cdb[0] = READ_CAPACITY_10;
1187 io_hdr.cmnd = cdb;
1188 io_hdr.cmnd_len = sizeof(cdb);
1189 io_hdr.sensep = sense;
1190 io_hdr.max_sense_len = sizeof(sense);
1191 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1192
1193 if (!device->scsi_pass_through(&io_hdr))
1194 return -device->get_errno();
1195 scsi_do_sense_disect(&io_hdr, &sinfo);
1196 res = scsiSimpleSenseFilter(&sinfo);
1197 if (res)
1198 return res;
1199 if (last_lbap)
ff28b140 1200 *last_lbap = sg_get_unaligned_be32(resp + 0);
a7e8ffec 1201 if (lb_sizep)
ff28b140 1202 *lb_sizep = sg_get_unaligned_be32(resp + 4);
a7e8ffec
GI
1203 return 0;
1204}
1205
1206/* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0
1207 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command
1208 * not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */
ee38a438 1209int
ff28b140 1210scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen)
a7e8ffec
GI
1211{
1212 struct scsi_cmnd_io io_hdr;
1213 struct scsi_sense_disect sinfo;
ff28b140
TL
1214 uint8_t cdb[16];
1215 uint8_t sense[32];
a7e8ffec
GI
1216
1217 memset(&io_hdr, 0, sizeof(io_hdr));
1218 memset(cdb, 0, sizeof(cdb));
1219 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
1220 io_hdr.dxfer_len = bufLen;
1221 io_hdr.dxferp = pBuf;
1222 cdb[0] = READ_CAPACITY_16;
1223 cdb[1] = SAI_READ_CAPACITY_16;
ff28b140 1224 sg_put_unaligned_be32(bufLen, cdb + 10);
a7e8ffec
GI
1225 io_hdr.cmnd = cdb;
1226 io_hdr.cmnd_len = sizeof(cdb);
1227 io_hdr.sensep = sense;
1228 io_hdr.max_sense_len = sizeof(sense);
1229 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1230
1231 if (!device->scsi_pass_through(&io_hdr))
1232 return -device->get_errno();
1233 scsi_do_sense_disect(&io_hdr, &sinfo);
1234 return scsiSimpleSenseFilter(&sinfo);
1235}
1236
1237/* Return number of bytes of storage in 'device' or 0 if error. If
ff28b140
TL
1238 * successful and lb_sizep is not NULL then the logical block size in bytes
1239 * is written to the location pointed to by lb_sizep. If the 'Logical Blocks
1240 * per Physical Block Exponent' pointer (lb_per_pb_expp,) is non-null then
1241 * the value is written. If 'Protection information Intervals Exponent'*/
ee38a438 1242uint64_t
ff28b140
TL
1243scsiGetSize(scsi_device * device, bool avoid_rcap16,
1244 struct scsi_readcap_resp * srrp)
a7e8ffec 1245{
ff28b140
TL
1246 bool try_16 = false;
1247 bool try_12 = false;
ee38a438 1248 unsigned int last_lba = 0, lb_size = 0;
a86ec89e 1249 int res;
a7e8ffec 1250 uint64_t ret_val = 0;
ff28b140 1251 uint8_t rc16resp[32];
a7e8ffec 1252
ff28b140
TL
1253 if (avoid_rcap16) {
1254 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1255 if (res) {
1256 if (scsi_debugmode)
1257 pout("%s: READ CAPACITY(10) failed, res=%d\n", __func__, res);
1258 try_16 = true;
1259 } else { /* rcap10 succeeded */
1260 if (0xffffffff == last_lba) {
1261 /* so number of blocks needs > 32 bits to represent */
1262 try_16 = true;
1263 device->set_rcap16_first();
1264 } else {
1265 ret_val = last_lba + 1;
1266 if (srrp) {
1267 memset(srrp, 0, sizeof(*srrp));
1268 srrp->num_lblocks = ret_val;
1269 srrp->lb_size = lb_size;
1270 }
1271 }
1272 }
a7e8ffec 1273 }
ff28b140 1274 if (try_16 || (! avoid_rcap16)) {
ee38a438 1275 res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
a7e8ffec 1276 if (res) {
ee38a438 1277 if (scsi_debugmode)
ff28b140
TL
1278 pout("%s: READ CAPACITY(16) failed, res=%d\n", __func__, res);
1279 if (try_16) /* so already tried rcap10 */
1280 return 0;
1281 try_12 = true;
1282 } else { /* rcap16 succeeded */
1283 bool prot_en;
1284 uint8_t p_type;
1285
1286 ret_val = sg_get_unaligned_be64(rc16resp + 0) + 1;
1287 lb_size = sg_get_unaligned_be32(rc16resp + 8);
1288 if (srrp) { /* writes to all fields */
1289 srrp->num_lblocks = ret_val;
1290 srrp->lb_size = lb_size;
1291 prot_en = !!(0x1 & rc16resp[12]);
1292 p_type = ((rc16resp[12] >> 1) & 0x7);
1293 srrp->prot_type = prot_en ? (1 + p_type) : 0;
1294 srrp->p_i_exp = ((rc16resp[13] >> 4) & 0xf);
1295 srrp->lb_p_pb_exp = (rc16resp[13] & 0xf);
1296 srrp->lbpme = !!(0x80 & rc16resp[14]);
1297 srrp->lbprz = !!(0x40 & rc16resp[14]);
1298 srrp->l_a_lba = sg_get_unaligned_be16(rc16resp + 14) & 0x3fff;
1299 }
a7e8ffec 1300 }
ee38a438 1301 }
ff28b140
TL
1302 if (try_12) { /* case where only rcap16 has been tried and failed */
1303 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1304 if (res) {
1305 if (scsi_debugmode)
1306 pout("%s: 2nd READ CAPACITY(10) failed, res=%d\n", __func__,
1307 res);
1308 return 0;
1309 } else { /* rcap10 succeeded */
1310 ret_val = (uint64_t)last_lba + 1;
1311 if (srrp) {
1312 memset(srrp, 0, sizeof(*srrp));
1313 srrp->num_lblocks = ret_val;
1314 srrp->lb_size = lb_size;
1315 }
1316 }
ee38a438 1317 }
ff28b140 1318 return (ret_val * lb_size);
ee38a438 1319}
a7e8ffec 1320
832b75ed
GG
1321/* Offset into mode sense (6 or 10 byte) response that actual mode page
1322 * starts at (relative to resp[0]). Returns -1 if problem */
ee38a438 1323int
ff28b140 1324scsiModePageOffset(const uint8_t * resp, int len, int modese_len)
832b75ed 1325{
832b75ed
GG
1326 int offset = -1;
1327
1328 if (resp) {
a86ec89e 1329 int resp_len, bd_len;
832b75ed 1330 if (10 == modese_len) {
ff28b140
TL
1331 resp_len = sg_get_unaligned_be16(resp + 0) + 2;
1332 bd_len = sg_get_unaligned_be16(resp + 6);
832b75ed
GG
1333 offset = bd_len + 8;
1334 } else {
1335 resp_len = resp[0] + 1;
1336 bd_len = resp[3];
1337 offset = bd_len + 4;
1338 }
1339 if ((offset + 2) > len) {
1340 pout("scsiModePageOffset: raw_curr too small, offset=%d "
1341 "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
1342 offset = -1;
1343 } else if ((offset + 2) > resp_len) {
cfbba5b9 1344 if ((resp_len > 2) || scsi_debugmode)
832b75ed
GG
1345 pout("scsiModePageOffset: response length too short, "
1346 "resp_len=%d offset=%d bd_len=%d\n", resp_len,
1347 offset, bd_len);
1348 offset = -1;
1349 }
1350 }
1351 return offset;
1352}
1353
1354/* IEC mode page byte 2 bit masks */
1355#define DEXCPT_ENABLE 0x08
1356#define EWASC_ENABLE 0x10
1357#define DEXCPT_DISABLE 0xf7
1358#define EWASC_DISABLE 0xef
1359#define TEST_DISABLE 0xfb
1360
1361/* Fetches the Informational Exceptions Control mode page. First tries
1362 * the 6 byte MODE SENSE command and if that fails with an illegal opcode
1363 * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
1364 * number if a known error (see SIMPLE_ERR_ ...) or a negative errno
1365 * value. */
ee38a438
GI
1366int
1367scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
1368 int modese_len)
832b75ed
GG
1369{
1370 int err = 0;
1371
1372 memset(iecp, 0, sizeof(*iecp));
1373 iecp->modese_len = modese_len;
1374 iecp->requestedCurrent = 1;
1375 if (iecp->modese_len <= 6) {
4d59bff9
GG
1376 if ((err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
1377 0, MPAGE_CONTROL_CURRENT,
832b75ed
GG
1378 iecp->raw_curr, sizeof(iecp->raw_curr)))) {
1379 if (SIMPLE_ERR_BAD_OPCODE == err)
1380 iecp->modese_len = 10;
1381 else {
1382 iecp->modese_len = 0;
1383 return err;
1384 }
1385 } else if (0 == iecp->modese_len)
1386 iecp->modese_len = 6;
1387 }
1388 if (10 == iecp->modese_len) {
1389 err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
4d59bff9 1390 0, MPAGE_CONTROL_CURRENT,
832b75ed
GG
1391 iecp->raw_curr, sizeof(iecp->raw_curr));
1392 if (err) {
1393 iecp->modese_len = 0;
1394 return err;
1395 }
ee38a438 1396 }
832b75ed
GG
1397 iecp->gotCurrent = 1;
1398 iecp->requestedChangeable = 1;
1399 if (10 == iecp->modese_len)
1400 err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
4d59bff9
GG
1401 0, MPAGE_CONTROL_CHANGEABLE,
1402 iecp->raw_chg, sizeof(iecp->raw_chg));
832b75ed 1403 else if (6 == iecp->modese_len)
ee38a438
GI
1404 err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
1405 0, MPAGE_CONTROL_CHANGEABLE,
832b75ed
GG
1406 iecp->raw_chg, sizeof(iecp->raw_chg));
1407 if (err)
1408 return err;
1409 iecp->gotChangeable = 1;
1410 return 0;
1411}
1412
ee38a438
GI
1413int
1414scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
832b75ed 1415{
832b75ed 1416 if (iecp && iecp->gotCurrent) {
a86ec89e
GI
1417 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1418 iecp->modese_len);
832b75ed
GG
1419 if (offset >= 0)
1420 return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1421 else
1422 return 0;
1423 } else
1424 return 0;
1425}
1426
ee38a438
GI
1427int
1428scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
832b75ed 1429{
832b75ed 1430 if (iecp && iecp->gotCurrent) {
a86ec89e
GI
1431 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1432 iecp->modese_len);
832b75ed
GG
1433 if (offset >= 0)
1434 return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1435 else
1436 return 0;
1437 } else
1438 return 0;
1439}
1440
1441/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */
ee38a438 1442#define SCSI_IEC_MP_BYTE2_ENABLED 0x10
832b75ed
GG
1443#define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
1444/* exception/warning via an unrequested REQUEST SENSE command */
ee38a438 1445#define SCSI_IEC_MP_MRIE 6
832b75ed
GG
1446#define SCSI_IEC_MP_INTERVAL_T 0
1447#define SCSI_IEC_MP_REPORT_COUNT 1
1448
1449/* Try to set (or clear) both Exception Control and Warning in the IE
1450 * mode page subject to the "changeable" mask. The object pointed to
1451 * by iecp is (possibly) inaccurate after this call, therefore
1452 * scsiFetchIECmpage() should be called again if the IEC mode page
1453 * is to be re-examined.
1454 * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
1455 * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
ee38a438
GI
1456int
1457scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
1458 const struct scsi_iec_mode_page *iecp)
832b75ed 1459{
a86ec89e 1460 int offset, resp_len;
832b75ed 1461 int err = 0;
ff28b140 1462 uint8_t rout[SCSI_IECMP_RAW_LEN];
832b75ed
GG
1463
1464 if ((! iecp) || (! iecp->gotCurrent))
1465 return -EINVAL;
1466 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1467 iecp->modese_len);
1468 if (offset < 0)
1469 return -EINVAL;
1470 memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN);
d2e702cf 1471 /* mask out DPOFUA device specific (disk) parameter bit */
832b75ed 1472 if (10 == iecp->modese_len) {
ff28b140 1473 resp_len = sg_get_unaligned_be16(rout + 0) + 2;
d2e702cf 1474 rout[3] &= 0xef;
832b75ed
GG
1475 } else {
1476 resp_len = rout[0] + 1;
d2e702cf 1477 rout[2] &= 0xef;
832b75ed 1478 }
ff28b140 1479 int sp = !! (rout[offset] & 0x80); /* PS bit becomes 'SELECT's SP bit */
832b75ed
GG
1480 if (enabled) {
1481 rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
cfbba5b9 1482 if (scsi_debugmode > 2)
832b75ed
GG
1483 rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
1484 rout[offset + 3] = SCSI_IEC_MP_MRIE;
ff28b140
TL
1485 sg_put_unaligned_be32(SCSI_IEC_MP_INTERVAL_T, rout + offset + 4);
1486 sg_put_unaligned_be32(SCSI_IEC_MP_REPORT_COUNT, rout + offset + 8);
832b75ed 1487 if (iecp->gotChangeable) {
ff28b140 1488 uint8_t chg2 = iecp->raw_chg[offset + 2];
832b75ed
GG
1489
1490 rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
1491 iecp->raw_curr[offset + 2];
a86ec89e 1492 for (int k = 3; k < 12; ++k) {
832b75ed
GG
1493 if (0 == iecp->raw_chg[offset + k])
1494 rout[offset + k] = iecp->raw_curr[offset + k];
1495 }
1496 }
1497 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
cfbba5b9 1498 if (scsi_debugmode > 0)
832b75ed
GG
1499 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1500 return 0;
1501 }
1502 } else { /* disabling Exception Control and (temperature) Warnings */
a86ec89e
GI
1503 int eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1504 int wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
832b75ed 1505 if ((! eCEnabled) && (! wEnabled)) {
cfbba5b9 1506 if (scsi_debugmode > 0)
832b75ed
GG
1507 pout("scsiSetExceptionControlAndWarning: already disabled\n");
1508 return 0; /* nothing to do, leave other setting alone */
1509 }
ee38a438 1510 if (wEnabled)
832b75ed
GG
1511 rout[offset + 2] &= EWASC_DISABLE;
1512 if (eCEnabled) {
ee38a438 1513 if (iecp->gotChangeable &&
832b75ed
GG
1514 (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
1515 rout[offset + 2] |= DEXCPT_ENABLE;
f9e10201 1516 rout[offset + 2] &= TEST_DISABLE; /* clear TEST bit for spec */
832b75ed
GG
1517 }
1518 }
1519 if (10 == iecp->modese_len)
1520 err = scsiModeSelect10(device, sp, rout, resp_len);
1521 else if (6 == iecp->modese_len)
1522 err = scsiModeSelect(device, sp, rout, resp_len);
1523 return err;
1524}
1525
ee38a438 1526int
ff28b140 1527scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp)
832b75ed 1528{
ff28b140 1529 uint8_t tBuf[252];
832b75ed
GG
1530 int err;
1531
1532 memset(tBuf, 0, sizeof(tBuf));
4d59bff9 1533 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
832b75ed
GG
1534 sizeof(tBuf), 0))) {
1535 *currenttemp = 0;
1536 *triptemp = 0;
ff28b140
TL
1537 pout("%s for temperature failed [%s]\n", logSenStr,
1538 scsiErrString(err));
832b75ed
GG
1539 return err;
1540 }
1541 *currenttemp = tBuf[9];
1542 *triptemp = tBuf[15];
1543 return 0;
1544}
1545
1546/* Read informational exception log page or Request Sense response.
1547 * Fetching asc/ascq code potentially flagging an exception or warning.
1548 * Returns 0 if ok, else error number. A current temperature of 255
1549 * (Celsius) implies that the temperature not available. */
ee38a438
GI
1550int
1551scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
ff28b140
TL
1552 uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
1553 uint8_t *triptemp)
832b75ed 1554{
ff28b140 1555 uint8_t tBuf[252];
832b75ed
GG
1556 struct scsi_sense_disect sense_info;
1557 int err;
ff28b140 1558 uint8_t currTemp, trTemp;
ee38a438 1559
832b75ed
GG
1560 *asc = 0;
1561 *ascq = 0;
1562 *currenttemp = 0;
1563 *triptemp = 0;
1564 memset(tBuf,0,sizeof(tBuf)); // need to clear stack space of junk
1565 memset(&sense_info, 0, sizeof(sense_info));
1566 if (hasIELogPage) {
4d59bff9 1567 if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
832b75ed 1568 sizeof(tBuf), 0))) {
ff28b140 1569 pout("%s failed, IE page [%s]\n", logSenStr, scsiErrString(err));
832b75ed
GG
1570 return err;
1571 }
1572 // pull out page size from response, don't forget to add 4
ff28b140 1573 unsigned short pagesize = sg_get_unaligned_be16(tBuf + 2) + 4;
832b75ed 1574 if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
ff28b140
TL
1575 pout("%s failed, IE page, bad parameter code or length\n",
1576 logSenStr);
832b75ed
GG
1577 return SIMPLE_ERR_BAD_PARAM;
1578 }
1579 if (tBuf[7] > 1) {
ee38a438 1580 sense_info.asc = tBuf[8];
832b75ed
GG
1581 sense_info.ascq = tBuf[9];
1582 if (! hasTempLogPage) {
ee38a438 1583 if (tBuf[7] > 2)
832b75ed
GG
1584 *currenttemp = tBuf[10];
1585 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
1586 *triptemp = tBuf[11];
1587 }
ee38a438 1588 }
832b75ed 1589 }
ee38a438 1590 if (0 == sense_info.asc) {
832b75ed
GG
1591 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
1592 if ((err = scsiRequestSense(device, &sense_info))) {
1593 pout("Request Sense failed, [%s]\n", scsiErrString(err));
1594 return err;
1595 }
1596 }
1597 *asc = sense_info.asc;
1598 *ascq = sense_info.ascq;
f9e10201 1599 if (hasTempLogPage) {
832b75ed
GG
1600 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
1601 *currenttemp = currTemp;
1602 *triptemp = trTemp;
1603 }
1604 }
1605 return 0;
1606}
1607
1608// The first character (W, C, I) tells the severity
ee38a438 1609static const char * TapeAlertsMessageTable[]= {
832b75ed
GG
1610 " ",
1611 /* 0x01 */
ff28b140
TL
1612 "W: The tape drive is having problems reading data. No data has been "
1613 "lost,\n"
832b75ed
GG
1614 " but there has been a reduction in the performance of the tape.",
1615 /* 0x02 */
ff28b140
TL
1616 "W: The tape drive is having problems writing data. No data has been "
1617 "lost,\n"
832b75ed
GG
1618 " but there has been a reduction in the capacity of the tape.",
1619 /* 0x03 */
ff28b140
TL
1620 "W: The operation has stopped because an error has occurred while "
1621 "reading\n"
832b75ed
GG
1622 " or writing data that the drive cannot correct.",
1623 /* 0x04 */
1624 "C: Your data is at risk:\n"
1625 " 1. Copy any data you require from this tape. \n"
1626 " 2. Do not use this tape again.\n"
1627 " 3. Restart the operation with a different tape.",
1628 /* 0x05 */
1629 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
1630 " supplier helpline.",
1631 /* 0x06 */
1632 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
1633 " 1. Use a good tape to test the drive.\n"
1634 " 2. If problem persists, call the tape drive supplier helpline.",
1635 /* 0x07 */
ff28b140
TL
1636 "W: The tape cartridge has reached the end of its calculated useful "
1637 "life:\n"
832b75ed
GG
1638 " 1. Copy data you need to another tape.\n"
1639 " 2. Discard the old tape.",
1640 /* 0x08 */
ff28b140
TL
1641 "W: The tape cartridge is not data-grade. Any data you back up to the "
1642 "tape\n"
832b75ed
GG
1643 " is at risk. Replace the cartridge with a data-grade tape.",
1644 /* 0x09 */
1645 "C: You are trying to write to a write-protected cartridge. Remove the\n"
1646 " write-protection or use another tape.",
1647 /* 0x0a */
ff28b140
TL
1648 "I: You cannot eject the cartridge because the tape drive is in use. "
1649 "Wait\n"
832b75ed
GG
1650 " until the operation is complete before ejecting the cartridge.",
1651 /* 0x0b */
1652 "I: The tape in the drive is a cleaning cartridge.",
1653 /* 0x0c */
1654 "I: You have tried to load a cartridge of a type which is not supported\n"
1655 " by this drive.",
1656 /* 0x0d */
ff28b140
TL
1657 "C: The operation has failed because the tape in the drive has "
1658 "experienced\n"
832b75ed
GG
1659 " a mechanical failure:\n"
1660 " 1. Discard the old tape.\n"
1661 " 2. Restart the operation with a different tape.",
1662 /* 0x0e */
ff28b140
TL
1663 "C: The operation has failed because the tape in the drive has "
1664 "experienced\n"
832b75ed
GG
1665 " a mechanical failure:\n"
1666 " 1. Do not attempt to extract the tape cartridge\n"
1667 " 2. Call the tape drive supplier helpline.",
1668 /* 0x0f */
1669 "W: The memory in the tape cartridge has failed, which reduces\n"
ff28b140
TL
1670 " performance. Do not use the cartridge for further write "
1671 "operations.",
832b75ed
GG
1672 /* 0x10 */
1673 "C: The operation has failed because the tape cartridge was manually\n"
1674 " de-mounted while the tape drive was actively writing or reading.",
1675 /* 0x11 */
ff28b140
TL
1676 "W: You have loaded a cartridge of a type that is read-only in this "
1677 "drive.\n"
832b75ed
GG
1678 " The cartridge will appear as write-protected.",
1679 /* 0x12 */
1680 "W: The tape directory on the tape cartridge has been corrupted. File\n"
ff28b140
TL
1681 " search performance will be degraded. The tape directory can be "
1682 "rebuilt\n"
832b75ed
GG
1683 " by reading all the data on the cartridge.",
1684 /* 0x13 */
1685 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
1686 " recommended that you:\n"
1687 " 1. Use another tape cartridge for your next backup.\n"
1688 " 2. Store this tape in a safe place in case you need to restore "
1689 " data from it.",
1690 /* 0x14 */
1691 "C: The tape drive needs cleaning:\n"
ff28b140
TL
1692 " 1. If the operation has stopped, eject the tape and clean the "
1693 "drive.\n"
1694 " 2. If the operation has not stopped, wait for it to finish and "
1695 "then\n"
832b75ed 1696 " clean the drive.\n"
ff28b140
TL
1697 " Check the tape drive users manual for device specific cleaning "
1698 "instructions.",
832b75ed
GG
1699 /* 0x15 */
1700 "W: The tape drive is due for routine cleaning:\n"
1701 " 1. Wait for the current operation to finish.\n"
1702 " 2. The use a cleaning cartridge.\n"
ff28b140
TL
1703 " Check the tape drive users manual for device specific cleaning "
1704 "instructions.",
832b75ed
GG
1705 /* 0x16 */
1706 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
1707 " 1. Discard the worn out cleaning cartridge.\n"
1708 " 2. Wait for the current operation to finish.\n"
1709 " 3. Then use a new cleaning cartridge.",
1710 /* 0x17 */
1711 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
1712 " type:\n"
1713 " 1. Do not use this cleaning cartridge in this drive.\n"
1714 " 2. Wait for the current operation to finish.\n"
1715 " 3. Then use a new cleaning cartridge.",
1716 /* 0x18 */
1717 "W: The tape drive has requested a retention operation",
1718 /* 0x19 */
1719 "W: A redundant interface port on the tape drive has failed",
1720 /* 0x1a */
1721 "W: A tape drive cooling fan has failed",
1722 /* 0x1b */
1723 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
ff28b140
TL
1724 " Check the enclosure users manual for instructions on replacing "
1725 "the\n"
832b75ed
GG
1726 " failed power supply.",
1727 /* 0x1c */
1728 "W: The tape drive power consumption is outside the specified range.",
1729 /* 0x1d */
1730 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
1731 " drive users manual for device specific preventive maintenance\n"
1732 " tasks or call the tape drive supplier helpline.",
1733 /* 0x1e */
1734 "C: The tape drive has a hardware fault:\n"
1735 " 1. Eject the tape or magazine.\n"
1736 " 2. Reset the drive.\n"
1737 " 3. Restart the operation.",
1738 /* 0x1f */
1739 "C: The tape drive has a hardware fault:\n"
1740 " 1. Turn the tape drive off and then on again.\n"
1741 " 2. Restart the operation.\n"
1742 " 3. If the problem persists, call the tape drive supplier helpline.",
1743 /* 0x20 */
1744 "W: The tape drive has a problem with the application client interface:\n"
1745 " 1. Check the cables and cable connections.\n"
1746 " 2. Restart the operation.",
1747 /* 0x21 */
1748 "C: The operation has failed:\n"
1749 " 1. Eject the tape or magazine.\n"
1750 " 2. Insert the tape or magazine again.\n"
1751 " 3. Restart the operation.",
1752 /* 0x22 */
1753 "W: The firmware download has failed because you have tried to use the\n"
1754 " incorrect firmware for this tape drive. Obtain the correct\n"
1755 " firmware and try again.",
1756 /* 0x23 */
1757 "W: Environmental conditions inside the tape drive are outside the\n"
1758 " specified humidity range.",
1759 /* 0x24 */
1760 "W: Environmental conditions inside the tape drive are outside the\n"
1761 " specified temperature range.",
1762 /* 0x25 */
1763 "W: The voltage supply to the tape drive is outside the specified range.",
1764 /* 0x26 */
1765 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
1766 " drive supplier helpline.",
1767 /* 0x27 */
1768 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
ff28b140
TL
1769 " verify and diagnose the problem. Check the tape drive users manual "
1770 "for\n"
832b75ed
GG
1771 " device specific instructions on running extended diagnostic tests.",
1772 /* 0x28 */
ff28b140
TL
1773 "C: The changer mechanism is having difficulty communicating with the "
1774 "tape\n"
832b75ed
GG
1775 " drive:\n"
1776 " 1. Turn the autoloader off then on.\n"
1777 " 2. Restart the operation.\n"
1778 " 3. If problem persists, call the tape drive supplier helpline.",
1779 /* 0x29 */
1780 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
1781 " 1. Insert an empty magazine to clear the fault.\n"
1782 " 2. If the fault does not clear, turn the autoloader off and then\n"
1783 " on again.\n"
1784 " 3. If the problem persists, call the tape drive supplier helpline.",
1785 /* 0x2a */
1786 "W: There is a problem with the autoloader mechanism.",
1787 /* 0x2b */
1788 "C: The operation has failed because the autoloader door is open:\n"
1789 " 1. Clear any obstructions from the autoloader door.\n"
1790 " 2. Eject the magazine and then insert it again.\n"
1791 " 3. If the fault does not clear, turn the autoloader off and then\n"
1792 " on again.\n"
1793 " 4. If the problem persists, call the tape drive supplier helpline.",
1794 /* 0x2c */
1795 "C: The autoloader has a hardware fault:\n"
1796 " 1. Turn the autoloader off and then on again.\n"
1797 " 2. Restart the operation.\n"
1798 " 3. If the problem persists, call the tape drive supplier helpline.\n"
1799 " Check the autoloader users manual for device specific instructions\n"
1800 " on turning the device power on and off.",
1801 /* 0x2d */
1802 "C: The autoloader cannot operate without the magazine,\n"
1803 " 1. Insert the magazine into the autoloader.\n"
1804 " 2. Restart the operation.",
1805 /* 0x2e */
1806 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
1807 " tape drive supplier helpline.",
1808 /* 0x2f */
1809 "I: Reserved.",
1810 /* 0x30 */
1811 "I: Reserved.",
1812 /* 0x31 */
1813 "I: Reserved.",
1814 /* 0x32 */
1815 "W: Media statistics have been lost at some time in the past",
1816 /* 0x33 */
1817 "W: The tape directory on the tape cartridge just unloaded has been\n"
1818 " corrupted. File search performance will be degraded. The tape\n"
1819 " directory can be rebuilt by reading all the data.",
1820 /* 0x34 */
1821 "C: The tape just unloaded could not write its system area successfully:\n"
1822 " 1. Copy data to another tape cartridge.\n"
1823 " 2. Discard the old cartridge.",
1824 /* 0x35 */
1825 "C: The tape system are could not be read successfully at load time:\n"
1826 " 1. Copy data to another tape cartridge.\n",
1827 /* 0x36 */
1828 "C: The start or data could not be found on the tape:\n"
1829 " 1. Check you are using the correct format tape.\n"
1830 " 2. Discard the tape or return the tape to your supplier",
1831 /* 0x37 */
1832 "C: The operation has failed because the media cannot be loaded\n"
1833 " and threaded.\n"
1834 " 1. Remove the cartridge, inspect it as specified in the product\n"
1835 " manual, and retry the operation.\n"
ff28b140
TL
1836 " 2. If the problem persists, call the tape drive supplier help "
1837 "line.",
832b75ed
GG
1838 /* 0x38 */
1839 "C: The operation has failed because the medium cannot be unloaded:\n"
1840 " 1. Do not attempt to extract the tape cartridge.\n"
1841 " 2. Call the tape driver supplier help line.",
1842 /* 0x39 */
1843 "C: The tape drive has a problem with the automation interface:\n"
1844 " 1. Check the power to the automation system.\n"
1845 " 2. Check the cables and cable connections.\n"
1846 " 3. Call the supplier help line if problem persists.",
1847 /* 0x3a */
1848 "W: The tape drive has reset itself due to a detected firmware\n"
1849 " fault. If problem persists, call the supplier help line.",
1850 };
1851
ee38a438
GI
1852const char *
1853scsiTapeAlertsTapeDevice(unsigned short code)
832b75ed
GG
1854{
1855 const int num = sizeof(TapeAlertsMessageTable) /
1856 sizeof(TapeAlertsMessageTable[0]);
1857
ee38a438 1858 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
832b75ed
GG
1859}
1860
1861// The first character (W, C, I) tells the severity
ee38a438 1862static const char * ChangerTapeAlertsMessageTable[]= {
832b75ed
GG
1863 " ",
1864 /* 0x01 */
1865 "C: The library mechanism is having difficulty communicating with the\n"
1866 " drive:\n"
1867 " 1. Turn the library off then on.\n"
1868 " 2. Restart the operation.\n"
1869 " 3. If the problem persists, call the library supplier help line.",
1870 /* 0x02 */
1871 "W: There is a problem with the library mechanism. If problem persists,\n"
1872 " call the library supplier help line.",
1873 /* 0x03 */
1874 "C: The library has a hardware fault:\n"
1875 " 1. Reset the library.\n"
1876 " 2. Restart the operation.\n"
ff28b140
TL
1877 " Check the library users manual for device specific instructions on "
1878 "resetting\n"
832b75ed
GG
1879 " the device.",
1880 /* 0x04 */
1881 "C: The library has a hardware fault:\n"
1882 " 1. Turn the library off then on again.\n"
1883 " 2. Restart the operation.\n"
1884 " 3. If the problem persists, call the library supplier help line.\n"
ff28b140
TL
1885 " Check the library users manual for device specific instructions on "
1886 "turning the\n"
832b75ed
GG
1887 " device power on and off.",
1888 /* 0x05 */
1889 "W: The library mechanism may have a hardware fault.\n"
ff28b140
TL
1890 " Run extended diagnostics to verify and diagnose the problem. "
1891 "Check the library\n"
1892 " users manual for device specific instructions on running extended "
1893 "diagnostic\n"
832b75ed
GG
1894 " tests.",
1895 /* 0x06 */
1896 "C: The library has a problem with the host interface:\n"
1897 " 1. Check the cables and connections.\n"
1898 " 2. Restart the operation.",
1899 /* 0x07 */
1900 "W: A hardware failure of the library is predicted. Call the library\n"
1901 " supplier help line.",
1902 /* 0x08 */
1903 "W: Preventive maintenance of the library is required.\n"
ff28b140
TL
1904 " Check the library users manual for device specific preventative "
1905 "maintenance\n"
832b75ed
GG
1906 " tasks, or call your library supplier help line.",
1907 /* 0x09 */
1908 "C: General environmental conditions inside the library are outside the\n"
1909 " specified humidity range.",
1910 /* 0x0a */
1911 "C: General environmental conditions inside the library are outside the\n"
1912 " specified temperature range.",
1913 /* 0x0b */
1914 "C: The voltage supply to the library is outside the specified range.\n"
1915 " There is a potential problem with the power supply or failure of\n"
1916 " a redundant power supply.",
1917 /* 0x0c */
1918 "C: A cartridge has been left inside the library by a previous hardware\n"
1919 " fault:\n"
1920 " 1. Insert an empty magazine to clear the fault.\n"
ff28b140
TL
1921 " 2. If the fault does not clear, turn the library off and then on "
1922 "again.\n"
832b75ed
GG
1923 " 3. If the problem persists, call the library supplier help line.",
1924 /* 0x0d */
1925 "W: There is a potential problem with the drive ejecting cartridges or\n"
1926 " with the library mechanism picking a cartridge from a slot.\n"
1927 " 1. No action needs to be taken at this time.\n"
1928 " 2. If the problem persists, call the library supplier help line.",
1929 /* 0x0e */
1930 "W: There is a potential problem with the library mechanism placing a\n"
1931 " cartridge into a slot.\n"
1932 " 1. No action needs to be taken at this time.\n"
1933 " 2. If the problem persists, call the library supplier help line.",
1934 /* 0x0f */
1935 "W: There is a potential problem with the drive or the library mechanism\n"
1936 " loading cartridges, or an incompatible cartridge.",
1937 /* 0x10 */
1938 "C: The library has failed because the door is open:\n"
1939 " 1. Clear any obstructions from the library door.\n"
1940 " 2. Close the library door.\n"
1941 " 3. If the problem persists, call the library supplier help line.",
1942 /* 0x11 */
1943 "C: There is a mechanical problem with the library media import/export\n"
1944 " mailslot.",
1945 /* 0x12 */
1946 "C: The library cannot operate without the magazine.\n"
1947 " 1. Insert the magazine into the library.\n"
1948 " 2. Restart the operation.",
1949 /* 0x13 */
1950 "W: Library security has been compromised.",
1951 /* 0x14 */
1952 "I: The library security mode has been changed.\n"
ff28b140
TL
1953 " The library has either been put into secure mode, or the library "
1954 "has exited\n"
832b75ed
GG
1955 " the secure mode.\n"
1956 " This is for information purposes only. No action is required.",
1957 /* 0x15 */
ff28b140
TL
1958 "I: The library has been manually turned offline and is unavailable for "
1959 "use.",
832b75ed
GG
1960 /* 0x16 */
1961 "I: A drive inside the library has been taken offline.\n"
1962 " This is for information purposes only. No action is required.",
1963 /* 0x17 */
1964 "W: There is a potential problem with the bar code label or the scanner\n"
1965 " hardware in the library mechanism.\n"
1966 " 1. No action needs to be taken at this time.\n"
1967 " 2. If the problem persists, call the library supplier help line.",
1968 /* 0x18 */
1969 "C: The library has detected an inconsistency in its inventory.\n"
1970 " 1. Redo the library inventory to correct inconsistency.\n"
1971 " 2. Restart the operation.\n"
ff28b140
TL
1972 " Check the applications users manual or the hardware users manual "
1973 "for\n"
832b75ed
GG
1974 " specific instructions on redoing the library inventory.",
1975 /* 0x19 */
1976 "W: A library operation has been attempted that is invalid at this time.",
1977 /* 0x1a */
1978 "W: A redundant interface port on the library has failed.",
1979 /* 0x1b */
1980 "W: A library cooling fan has failed.",
1981 /* 0x1c */
1982 "W: A redundant power supply has failed inside the library. Check the\n"
ff28b140
TL
1983 " library users manual for instructions on replacing the failed "
1984 "power supply.",
832b75ed
GG
1985 /* 0x1d */
1986 "W: The library power consumption is outside the specified range.",
1987 /* 0x1e */
ff28b140
TL
1988 "C: A failure has occurred in the cartridge pass-through mechanism "
1989 "between\n"
832b75ed
GG
1990 " two library modules.",
1991 /* 0x1f */
1992 "C: A cartridge has been left in the pass-through mechanism from a\n"
ff28b140
TL
1993 " previous hardware fault. Check the library users guide for "
1994 "instructions on\n"
832b75ed
GG
1995 " clearing this fault.",
1996 /* 0x20 */
1997 "I: The library was unable to read the bar code on a cartridge.",
1998};
1999
ee38a438
GI
2000const char *
2001scsiTapeAlertsChangerDevice(unsigned short code)
832b75ed
GG
2002{
2003 const int num = sizeof(ChangerTapeAlertsMessageTable) /
2004 sizeof(ChangerTapeAlertsMessageTable[0]);
2005
ff28b140
TL
2006 return (code < num) ? ChangerTapeAlertsMessageTable[code] :
2007 "Unknown Alert";
832b75ed
GG
2008}
2009
2010
2011/* this is a subset of the SCSI additional sense code strings indexed
2012 * by "ascq" for the case when asc==SCSI_ASC_IMPENDING_FAILURE (0x5d)
2013 */
2014static const char * strs_for_asc_5d[] = {
2015 /* 0x00 */ "FAILURE PREDICTION THRESHOLD EXCEEDED",
2016 "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED",
2017 "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED",
2018 "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED",
2019 "",
2020 "",
2021 "",
2022 "",
2023 "",
2024 "",
2025 "",
2026 "",
2027 "",
2028 "",
2029 "",
2030 "",
2031 /* 0x10 */ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2032 "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2033 "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2034 "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2035 "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2036 "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2037 "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2038 "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
2039 "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED",
2040 "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2041 "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2042 "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2043 "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2044 "",
2045 "",
2046 "",
2047 /* 0x20 */ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2048 "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2049 "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2050 "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2051 "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2052 "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2053 "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2054 "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS",
2055 "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED",
2056 "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2057 "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE",
2058 "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT",
2059 "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2060 "",
2061 "",
2062 "",
2063 /* 0x30 */ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2064 "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2065 "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2066 "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2067 "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2068 "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2069 "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2070 "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS",
2071 "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED",
2072 "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2073 "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE",
2074 "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT",
2075 "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2076 "",
2077 "",
2078 "",
2079 /* 0x40 */ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2080 "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2081 "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2082 "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2083 "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2084 "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2085 "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2086 "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS",
2087 "SERVO IMPENDING FAILURE CONTROLLER DETECTED",
2088 "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2089 "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE",
2090 "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT",
2091 "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2092 "",
2093 "",
2094 "",
2095 /* 0x50 */ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2096 "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2097 "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2098 "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2099 "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2100 "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2101 "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2102 "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS",
2103 "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED",
2104 "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2105 "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2106 "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2107 "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2108 "",
2109 "",
2110 "",
2111 /* 0x60 */ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2112 "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2113 "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2114 "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2115 "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2116 "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2117 "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2118 "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
2119 "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED",
2120 "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2121 "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2122 "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2123 /* 0x6c */ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"};
2124
2125
2126/* this is a subset of the SCSI additional sense code strings indexed
2127 * * by "ascq" for the case when asc==SCSI_ASC_WARNING (0xb)
2128 * */
2129static const char * strs_for_asc_b[] = {
2130 /* 0x00 */ "WARNING",
2131 "WARNING - SPECIFIED TEMPERATURE EXCEEDED",
2132 "WARNING - ENCLOSURE DEGRADED"};
2133
2134static char spare_buff[128];
2135
ee38a438 2136const char *
ff28b140 2137scsiGetIEString(uint8_t asc, uint8_t ascq)
832b75ed
GG
2138{
2139 const char * rp;
2140
2141 if (SCSI_ASC_IMPENDING_FAILURE == asc) {
2142 if (ascq == 0xff)
2143 return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
ee38a438 2144 else if (ascq <
832b75ed
GG
2145 (sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) {
2146 rp = strs_for_asc_5d[ascq];
2147 if (strlen(rp) > 0)
2148 return rp;
2149 }
2150 snprintf(spare_buff, sizeof(spare_buff),
2151 "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq);
2152 return spare_buff;
2153 } else if (SCSI_ASC_WARNING == asc) {
2154 if (ascq < (sizeof(strs_for_asc_b) / sizeof(strs_for_asc_b[0]))) {
2155 rp = strs_for_asc_b[ascq];
2156 if (strlen(rp) > 0)
2157 return rp;
2158 }
2159 snprintf(spare_buff, sizeof(spare_buff), "WARNING: ascq=0x%x", ascq);
2160 return spare_buff;
2161 }
2162 return NULL; /* not a IE additional sense code */
2163}
2164
2165
ee38a438
GI
2166int
2167scsiSmartDefaultSelfTest(scsi_device * device)
2168{
832b75ed
GG
2169 int res;
2170
2171 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0);
2172 if (res)
2173 pout("Default self test failed [%s]\n", scsiErrString(res));
2174 return res;
2175}
2176
ee38a438
GI
2177int
2178scsiSmartShortSelfTest(scsi_device * device)
2179{
832b75ed
GG
2180 int res;
2181
2182 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0);
2183 if (res)
2184 pout("Short offline self test failed [%s]\n", scsiErrString(res));
2185 return res;
2186}
2187
ee38a438
GI
2188int
2189scsiSmartExtendSelfTest(scsi_device * device)
2190{
832b75ed
GG
2191 int res;
2192
2193 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0);
2194 if (res)
2195 pout("Long (extended) offline self test failed [%s]\n",
2196 scsiErrString(res));
2197 return res;
2198}
2199
ee38a438
GI
2200int
2201scsiSmartShortCapSelfTest(scsi_device * device)
2202{
832b75ed
GG
2203 int res;
2204
2205 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0);
2206 if (res)
2207 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2208 return res;
2209}
2210
ee38a438
GI
2211int
2212scsiSmartExtendCapSelfTest(scsi_device * device)
832b75ed
GG
2213{
2214 int res;
2215
2216 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0);
2217 if (res)
2218 pout("Long (extended) foreground self test failed [%s]\n",
2219 scsiErrString(res));
2220 return res;
2221}
2222
ee38a438
GI
2223int
2224scsiSmartSelfTestAbort(scsi_device * device)
832b75ed
GG
2225{
2226 int res;
2227
2228 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0);
2229 if (res)
2230 pout("Abort self test failed [%s]\n", scsiErrString(res));
2231 return res;
2232}
2233
2234/* Returns 0 and the expected duration of an extended self test (in seconds)
2235 if successful; any other return value indicates a failure. */
ee38a438
GI
2236int
2237scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2238 int modese_len)
832b75ed 2239{
a86ec89e 2240 int err, offset;
ff28b140 2241 uint8_t buff[64];
832b75ed
GG
2242
2243 memset(buff, 0, sizeof(buff));
2244 if (modese_len <= 6) {
4d59bff9
GG
2245 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2246 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2247 buff, sizeof(buff)))) {
2248 if (SIMPLE_ERR_BAD_OPCODE == err)
2249 modese_len = 10;
2250 else
2251 return err;
2252 } else if (0 == modese_len)
2253 modese_len = 6;
2254 }
2255 if (10 == modese_len) {
4d59bff9 2256 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
ee38a438 2257 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2258 buff, sizeof(buff));
2259 if (err)
2260 return err;
ee38a438 2261 }
832b75ed
GG
2262 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2263 if (offset < 0)
2264 return -EINVAL;
2265 if (buff[offset + 1] >= 0xa) {
ff28b140 2266 int res = sg_get_unaligned_be16(buff + offset + 10);
832b75ed
GG
2267 *durationSec = res;
2268 return 0;
2269 }
2270 else
2271 return -EINVAL;
2272}
2273
ee38a438
GI
2274void
2275scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
832b75ed 2276{
832b75ed 2277 memset(ecp, 0, sizeof(*ecp));
ff28b140 2278 int num = sg_get_unaligned_be16(resp + 2);
a86ec89e 2279 unsigned char * ucp = &resp[0] + 4;
832b75ed 2280 while (num > 3) {
ff28b140 2281 int pc = sg_get_unaligned_be16(ucp + 0);
a86ec89e
GI
2282 int pl = ucp[3] + 4;
2283 uint64_t * ullp;
832b75ed 2284 switch (pc) {
ee38a438
GI
2285 case 0:
2286 case 1:
2287 case 2:
2288 case 3:
2289 case 4:
2290 case 5:
2291 case 6:
832b75ed
GG
2292 ecp->gotPC[pc] = 1;
2293 ullp = &ecp->counter[pc];
2294 break;
ee38a438 2295 default:
832b75ed
GG
2296 ecp->gotExtraPC = 1;
2297 ullp = &ecp->counter[7];
2298 break;
2299 }
a86ec89e
GI
2300 int k = pl - 4;
2301 unsigned char * xp = ucp + 4;
832b75ed
GG
2302 if (k > (int)sizeof(*ullp)) {
2303 xp += (k - sizeof(*ullp));
2304 k = sizeof(*ullp);
2305 }
ff28b140 2306 *ullp = sg_get_unaligned_be(k, xp);
832b75ed
GG
2307 num -= pl;
2308 ucp += pl;
2309 }
2310}
2311
ee38a438
GI
2312void
2313scsiDecodeNonMediumErrPage(unsigned char *resp,
2314 struct scsiNonMediumError *nmep)
832b75ed 2315{
832b75ed 2316 memset(nmep, 0, sizeof(*nmep));
ff28b140 2317 int num = sg_get_unaligned_be16(resp + 2);
a86ec89e
GI
2318 unsigned char * ucp = &resp[0] + 4;
2319 int szof = sizeof(nmep->counterPC0);
832b75ed 2320 while (num > 3) {
ff28b140 2321 int pc = sg_get_unaligned_be16(ucp + 0);
a86ec89e
GI
2322 int pl = ucp[3] + 4;
2323 int k;
2324 unsigned char * xp;
832b75ed 2325 switch (pc) {
ee38a438 2326 case 0:
832b75ed
GG
2327 nmep->gotPC0 = 1;
2328 k = pl - 4;
2329 xp = ucp + 4;
2330 if (k > szof) {
2331 xp += (k - szof);
2332 k = szof;
2333 }
ff28b140 2334 nmep->counterPC0 = sg_get_unaligned_be(k, xp + 0);
832b75ed 2335 break;
ee38a438 2336 case 0x8009:
832b75ed
GG
2337 nmep->gotTFE_H = 1;
2338 k = pl - 4;
2339 xp = ucp + 4;
2340 if (k > szof) {
2341 xp += (k - szof);
2342 k = szof;
2343 }
ff28b140 2344 nmep->counterTFE_H = sg_get_unaligned_be(k, xp + 0);
832b75ed 2345 break;
ee38a438 2346 case 0x8015:
832b75ed
GG
2347 nmep->gotPE_H = 1;
2348 k = pl - 4;
2349 xp = ucp + 4;
2350 if (k > szof) {
2351 xp += (k - szof);
2352 k = szof;
2353 }
ff28b140 2354 nmep->counterPE_H = sg_get_unaligned_be(k, xp + 0);
832b75ed 2355 break;
ee38a438 2356 default:
832b75ed
GG
2357 nmep->gotExtraPC = 1;
2358 break;
2359 }
2360 num -= pl;
2361 ucp += pl;
2362 }
2363}
2364
2365/* Counts number of failed self-tests. Also encodes the poweron_hour
2366 of the most recent failed self-test. Return value is negative if
2367 this function has a problem (typically -1), otherwise the bottom 8
2368 bits are the number of failed self tests and the 16 bits above that
2369 are the poweron hour of the most recent failure. Note: aborted self
ee38a438
GI
2370 tests (typically by the user) and self tests in progress are not
2371 considered failures. See Working Draft SCSI Primary Commands - 3
832b75ed 2372 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
ee38a438
GI
2373int
2374scsiCountFailedSelfTests(scsi_device * fd, int noisy)
832b75ed 2375{
a86ec89e 2376 int num, k, err, fails, fail_hour;
ff28b140 2377 uint8_t * ucp;
832b75ed
GG
2378 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2379
4d59bff9 2380 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
832b75ed
GG
2381 LOG_RESP_SELF_TEST_LEN, 0))) {
2382 if (noisy)
2383 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2384 return -1;
2385 }
4d59bff9 2386 if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
832b75ed 2387 if (noisy)
ff28b140 2388 pout("Self-test %s Failed, page mismatch\n", logSenStr);
832b75ed
GG
2389 return -1;
2390 }
2391 // compute page length
ff28b140 2392 num = sg_get_unaligned_be16(resp + 2);
832b75ed
GG
2393 // Log sense page length 0x190 bytes
2394 if (num != 0x190) {
2395 if (noisy)
ff28b140
TL
2396 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr,
2397 num);
832b75ed
GG
2398 return -1;
2399 }
2400 fails = 0;
2401 fail_hour = 0;
2402 // loop through the twenty possible entries
2403 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2404
2405 // timestamp in power-on hours (or zero if test in progress)
ff28b140 2406 int n = sg_get_unaligned_be16(ucp + 6);
832b75ed
GG
2407
2408 // The spec says "all 20 bytes will be zero if no test" but
2409 // DG has found otherwise. So this is a heuristic.
2410 if ((0 == n) && (0 == ucp[4]))
2411 break;
a86ec89e 2412 int res = ucp[4] & 0xf;
832b75ed
GG
2413 if ((res > 2) && (res < 8)) {
2414 fails++;
ee38a438 2415 if (1 == fails)
ff28b140 2416 fail_hour = sg_get_unaligned_be16(ucp + 6);
832b75ed
GG
2417 }
2418 }
2419 return (fail_hour << 8) + fails;
2420}
2421
2422/* Returns 0 if able to read self test log page; then outputs 1 into
2423 *inProgress if self test still in progress, else outputs 0. */
ee38a438
GI
2424int
2425scsiSelfTestInProgress(scsi_device * fd, int * inProgress)
832b75ed
GG
2426{
2427 int num;
ff28b140 2428 uint8_t * ucp;
832b75ed
GG
2429 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2430
4d59bff9 2431 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
832b75ed
GG
2432 LOG_RESP_SELF_TEST_LEN, 0))
2433 return -1;
2434 if (resp[0] != SELFTEST_RESULTS_LPAGE)
2435 return -1;
2436 // compute page length
ff28b140 2437 num = sg_get_unaligned_be16(resp + 2);
832b75ed
GG
2438 // Log sense page length 0x190 bytes
2439 if (num != 0x190) {
2440 return -1;
2441 }
2442 ucp = resp + 4;
2443 if (inProgress)
2444 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2445 return 0;
2446}
2447
ff28b140 2448/* Returns a negative value if failed to fetch Control mode page or it was
832b75ed
GG
2449 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2450 bit is set. Examines default mode page when current==0 else examines
2451 current mode page. */
ee38a438
GI
2452int
2453scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current)
832b75ed
GG
2454{
2455 int err, offset;
ff28b140 2456 uint8_t buff[64];
832b75ed
GG
2457 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2458
2459 memset(buff, 0, sizeof(buff));
2460 if (modese_len <= 6) {
4d59bff9 2461 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc,
832b75ed
GG
2462 buff, sizeof(buff)))) {
2463 if (SIMPLE_ERR_BAD_OPCODE == err)
2464 modese_len = 10;
2465 else
2466 return -EINVAL;
2467 } else if (0 == modese_len)
2468 modese_len = 6;
2469 }
2470 if (10 == modese_len) {
4d59bff9 2471 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
832b75ed
GG
2472 buff, sizeof(buff));
2473 if (err)
2474 return -EINVAL;
ee38a438 2475 }
832b75ed
GG
2476 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2477 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2478 return (buff[offset + 2] & 2) ? 1 : 0;
2479 return -EINVAL;
2480}
2481
ee38a438
GI
2482/* Returns a negative value on error, 0 if unknown and 1 if SSD,
2483 * otherwise the positive returned value is the speed in rpm. First checks
2484 * the Block Device Characteristics VPD page and if that fails it tries the
2485 * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page. */
2486
2487int
d2e702cf
GI
2488scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
2489 int * haw_zbcp)
ee38a438 2490{
a86ec89e 2491 int err, offset;
ff28b140 2492 uint8_t buff[64];
ee38a438
GI
2493 int pc = MPAGE_CONTROL_DEFAULT;
2494
2495 memset(buff, 0, sizeof(buff));
2496 if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS,
2497 buff, sizeof(buff))) &&
ff28b140
TL
2498 ((sg_get_unaligned_be16(buff + 2)) > 2)) {
2499 int speed = sg_get_unaligned_be16(buff + 4);
ee38a438
GI
2500 if (form_factorp)
2501 *form_factorp = buff[7] & 0xf;
d2e702cf
GI
2502 if (haw_zbcp)
2503 *haw_zbcp = !!(0x10 & buff[8]);
ee38a438
GI
2504 return speed;
2505 }
2506 if (form_factorp)
2507 *form_factorp = 0;
d2e702cf
GI
2508 if (haw_zbcp)
2509 *haw_zbcp = 0;
ee38a438
GI
2510 if (modese_len <= 6) {
2511 if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2512 buff, sizeof(buff)))) {
2513 if (SIMPLE_ERR_BAD_OPCODE == err)
2514 modese_len = 10;
2515 else
2516 return -EINVAL;
2517 } else if (0 == modese_len)
2518 modese_len = 6;
2519 }
2520 if (10 == modese_len) {
2521 err = scsiModeSense10(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2522 buff, sizeof(buff));
2523 if (err)
2524 return -EINVAL;
2525 }
2526 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
ff28b140 2527 return sg_get_unaligned_be16(buff + offset + 20);
ee38a438
GI
2528}
2529
2530/* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2531 0 - clear bit, 1 - set bit */
2532
2533int
2534scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2535 short int * rcdp)
2536{
2537 int err, offset, resp_len, sp;
ff28b140 2538 uint8_t buff[64], ch_buff[64];
ee38a438
GI
2539 short set_wce = *wcep;
2540 short set_rcd = *rcdp;
2541
2542 memset(buff, 0, sizeof(buff));
2543 if (modese_len <= 6) {
ff28b140
TL
2544 err = scsiModeSense(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT,
2545 buff, sizeof(buff));
2546 if (err) {
ee38a438
GI
2547 if (SIMPLE_ERR_BAD_OPCODE == err)
2548 modese_len = 10;
2549 else {
2550 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2551 return -EINVAL;
2552 }
2553 } else if (0 == modese_len)
2554 modese_len = 6;
2555 }
2556
2557 if (10 == modese_len) {
2558 err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT,
2559 buff, sizeof(buff));
2560 if (err) {
2561 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2562 return -EINVAL;
2563 }
2564 }
2565 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2566 if ((offset < 0) || (buff[offset + 1] < 0xa)) {
2567 device->set_err(EINVAL, "Bad response");
2568 return SIMPLE_ERR_BAD_RESP;
2569 }
2570
2571 *wcep = ((buff[offset + 2] & 0x04) != 0);
2572 *rcdp = ((buff[offset + 2] & 0x01) != 0);
2573
2574 if((*wcep == set_wce || set_wce == -1)
2575 && ((*rcdp == set_rcd) || set_rcd == -1))
2576 return 0; // no changes needed or nothing to set
2577
2578 if (modese_len == 6)
2579 err = scsiModeSense(device, CACHING_PAGE, 0,
2580 MPAGE_CONTROL_CHANGEABLE,
2581 ch_buff, sizeof(ch_buff));
2582 else
2583 err = scsiModeSense10(device, CACHING_PAGE, 0,
2584 MPAGE_CONTROL_CHANGEABLE,
2585 ch_buff, sizeof(ch_buff));
2586 if (err) {
ff28b140 2587 device->set_err(EINVAL, "WCE/RCD bits not changeable");
ee38a438
GI
2588 return err;
2589 }
2590
2591 // set WCE bit
2592 if(set_wce >= 0 && *wcep != set_wce) {
2593 if (0 == (ch_buff[offset + 2] & 0x04)) {
ff28b140 2594 device->set_err(EINVAL, "WCE bit not changeable");
ee38a438
GI
2595 return 1;
2596 }
2597 if(set_wce)
2598 buff[offset + 2] |= 0x04; // set bit
2599 else
2600 buff[offset + 2] &= 0xfb; // clear bit
2601 }
2602 // set RCD bit
2603 if(set_rcd >= 0 && *rcdp != set_rcd) {
2604 if (0 == (ch_buff[offset + 2] & 0x01)) {
ff28b140 2605 device->set_err(EINVAL, "RCD bit not changeable");
ee38a438
GI
2606 return 1;
2607 }
2608 if(set_rcd)
2609 buff[offset + 2] |= 0x01; // set bit
2610 else
2611 buff[offset + 2] &= 0xfe; // clear bit
2612 }
2613
d2e702cf 2614 /* mask out DPOFUA device specific (disk) parameter bit */
ee38a438 2615 if (10 == modese_len) {
ff28b140 2616 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
d2e702cf 2617 buff[3] &= 0xef;
ee38a438
GI
2618 } else {
2619 resp_len = buff[0] + 1;
d2e702cf 2620 buff[2] &= 0xef;
ee38a438
GI
2621 }
2622 sp = 0; /* Do not change saved values */
2623 if (10 == modese_len)
2624 err = scsiModeSelect10(device, sp, buff, resp_len);
2625 else if (6 == modese_len)
2626 err = scsiModeSelect(device, sp, buff, resp_len);
2627 if(err)
2628 device->set_err(EINVAL, "MODE SELECT command failed");
2629 return err;
2630}
2631
2632
832b75ed
GG
2633/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
2634 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
2635 successful, negative if low level error, > 0 if higher level error (e.g.
2636 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
ee38a438
GI
2637int
2638scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
832b75ed
GG
2639{
2640 int err, offset, resp_len, sp;
ff28b140
TL
2641 uint8_t buff[64];
2642 uint8_t ch_buff[64];
832b75ed
GG
2643
2644 memset(buff, 0, sizeof(buff));
2645 if (modese_len <= 6) {
4d59bff9
GG
2646 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2647 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2648 buff, sizeof(buff)))) {
2649 if (SIMPLE_ERR_BAD_OPCODE == err)
2650 modese_len = 10;
2651 else
2652 return err;
2653 } else if (0 == modese_len)
2654 modese_len = 6;
2655 }
2656 if (10 == modese_len) {
4d59bff9
GG
2657 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2658 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2659 buff, sizeof(buff));
2660 if (err)
2661 return err;
ee38a438 2662 }
832b75ed
GG
2663 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2664 if ((offset < 0) || (buff[offset + 1] < 0xa))
2665 return SIMPLE_ERR_BAD_RESP;
2666
2667 if (enabled)
2668 enabled = 2;
2669 if (enabled == (buff[offset + 2] & 2))
2670 return 0; /* GLTSD already in wanted state so nothing to do */
2671
2672 if (modese_len == 6)
4d59bff9
GG
2673 err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2674 MPAGE_CONTROL_CHANGEABLE,
832b75ed
GG
2675 ch_buff, sizeof(ch_buff));
2676 else
4d59bff9
GG
2677 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2678 MPAGE_CONTROL_CHANGEABLE,
832b75ed
GG
2679 ch_buff, sizeof(ch_buff));
2680 if (err)
2681 return err;
2682 if (0 == (ch_buff[offset + 2] & 2))
d2e702cf 2683 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not changeable */
ee38a438 2684
d2e702cf 2685 /* mask out DPOFUA device specific (disk) parameter bit */
832b75ed 2686 if (10 == modese_len) {
ff28b140
TL
2687 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2688 buff[3] &= 0xef;
832b75ed
GG
2689 } else {
2690 resp_len = buff[0] + 1;
d2e702cf 2691 buff[2] &= 0xef;
832b75ed
GG
2692 }
2693 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
2694 if (enabled)
2695 buff[offset + 2] |= 0x2; /* set GLTSD bit */
2696 else
2697 buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
2698 if (10 == modese_len)
2699 err = scsiModeSelect10(device, sp, buff, resp_len);
2700 else if (6 == modese_len)
2701 err = scsiModeSelect(device, sp, buff, resp_len);
2702 return err;
2703}
2704
ee38a438 2705/* Returns a negative value if failed to fetch Protocol specific port mode
832b75ed
GG
2706 page or it was malformed. Returns transport protocol identifier when
2707 value >= 0 . */
ee38a438
GI
2708int
2709scsiFetchTransportProtocol(scsi_device * device, int modese_len)
832b75ed
GG
2710{
2711 int err, offset;
ff28b140 2712 uint8_t buff[64];
832b75ed
GG
2713
2714 memset(buff, 0, sizeof(buff));
2715 if (modese_len <= 6) {
4d59bff9
GG
2716 if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
2717 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2718 buff, sizeof(buff)))) {
2719 if (SIMPLE_ERR_BAD_OPCODE == err)
2720 modese_len = 10;
2721 else
2722 return -EINVAL;
2723 } else if (0 == modese_len)
2724 modese_len = 6;
2725 }
2726 if (10 == modese_len) {
4d59bff9
GG
2727 err = scsiModeSense10(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
2728 MPAGE_CONTROL_CURRENT,
832b75ed
GG
2729 buff, sizeof(buff));
2730 if (err)
2731 return -EINVAL;
ee38a438 2732 }
832b75ed
GG
2733 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2734 if ((offset >= 0) && (buff[offset + 1] > 1)) {
2735 if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
ee38a438 2736 (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
832b75ed
GG
2737 return (buff[offset + 2] & 0xf);
2738 }
2739 return -EINVAL;
2740}
ee38a438
GI
2741
2742const unsigned char *
2743sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
2744 int desc_type)
2745{
a86ec89e 2746 int add_sen_len;
ee38a438
GI
2747 const unsigned char * descp;
2748
2749 if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
2750 return NULL;
2751 if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
2752 return NULL;
2753 add_sen_len = (add_sen_len < (sense_len - 8)) ?
2754 add_sen_len : (sense_len - 8);
2755 descp = &sensep[8];
a86ec89e 2756 for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
ee38a438 2757 descp += desc_len;
a86ec89e 2758 int add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
ee38a438
GI
2759 desc_len = add_len + 2;
2760 if (descp[0] == desc_type)
2761 return descp;
2762 if (add_len < 0) /* short descriptor ?? */
2763 break;
2764 }
2765 return NULL;
2766}
2767
2768// Convenience function for formatting strings from SCSI identify
2769void
ff28b140 2770scsi_format_id_string(char * out, const uint8_t * in, int n)
ee38a438
GI
2771{
2772 char tmp[65];
2773 n = n > 64 ? 64 : n;
2774 strncpy(tmp, (const char *)in, n);
2775 tmp[n] = '\0';
2776
2777 // Find the first non-space character (maybe none).
2778 int first = -1;
2779 int i;
2780 for (i = 0; tmp[i]; i++)
2781 if (!isspace((int)tmp[i])) {
2782 first = i;
2783 break;
2784 }
2785
2786 if (first == -1) {
ff28b140 2787 // There are only space characters.
ee38a438
GI
2788 out[0] = '\0';
2789 return;
2790 }
2791
2792 // Find the last non-space character.
2793 for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
2794 int last = i;
2795
2796 strncpy(out, tmp+first, last-first+1);
2797 out[last-first+1] = '\0';
2798}