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