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