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