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