]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - scsicmds.c
adjust cciss patch and actually apply it
[mirror_smartmontools-debian.git] / scsicmds.c
1 /*
2 * scsicmds.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
8 *
9 * Additional SCSI work:
10 * Copyright (C) 2003-6 Douglas Gilbert <dougg@torque.net>
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
18 * (for example COPYING); if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * This code was originally developed as a Senior Thesis by Michael Cornwell
22 * at the Concurrent Systems Laboratory (now part of the Storage Systems
23 * Research Center), Jack Baskin School of Engineering, University of
24 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
25 *
26 *
27 * In the SCSI world "SMART" is a dead or withdrawn standard. In recent
28 * SCSI standards (since SCSI-3) it goes under the awkward name of
29 * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")].
30 * The relevant information is spread around several SCSI draft
31 * standards available at http://www.t10.org . Reference is made in the
32 * code to the following acronyms:
33 * - SAM [SCSI Architectural model, versions 2 or 3]
34 * - SPC [SCSI Primary commands, versions 2 or 3]
35 * - SBC [SCSI Block commands, versions 2]
36 *
37 * Some SCSI disk vendors have snippets of "SMART" information in their
38 * product manuals.
39 */
40
41 #include <stdio.h>
42 #include <string.h>
43
44 #include "config.h"
45 #include "int64.h"
46 #include "extern.h"
47 #include "scsicmds.h"
48 #include "utility.h"
49
50 const char *scsicmds_c_cvsid="$Id: scsicmds.c,v 1.85 2006/04/12 14:54:28 ballen4705 Exp $"
51 CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
52
53 /* for passing global control variables */
54 extern smartmonctrl *con;
55
56 /* output binary in hex and optionally ascii */
57 void dStrHex(const char* str, int len, int no_ascii)
58 {
59 const char* p = str;
60 unsigned char c;
61 char buff[82];
62 int a = 0;
63 const int bpstart = 5;
64 const int cpstart = 60;
65 int cpos = cpstart;
66 int bpos = bpstart;
67 int i, k;
68
69 if (len <= 0) return;
70 memset(buff,' ',80);
71 buff[80]='\0';
72 k = sprintf(buff + 1, "%.2x", a);
73 buff[k + 1] = ' ';
74 if (bpos >= ((bpstart + (9 * 3))))
75 bpos++;
76
77 for(i = 0; i < len; i++)
78 {
79 c = *p++;
80 bpos += 3;
81 if (bpos == (bpstart + (9 * 3)))
82 bpos++;
83 sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
84 buff[bpos + 2] = ' ';
85 if (no_ascii)
86 buff[cpos++] = ' ';
87 else {
88 if ((c < ' ') || (c >= 0x7f))
89 c='.';
90 buff[cpos++] = c;
91 }
92 if (cpos > (cpstart+15))
93 {
94 pout("%s\n", buff);
95 bpos = bpstart;
96 cpos = cpstart;
97 a += 16;
98 memset(buff,' ',80);
99 k = sprintf(buff + 1, "%.2x", a);
100 buff[k + 1] = ' ';
101 }
102 }
103 if (cpos > cpstart)
104 {
105 pout("%s\n", buff);
106 }
107 }
108
109 struct scsi_opcode_name {
110 UINT8 opcode;
111 const char * name;
112 };
113
114 static struct scsi_opcode_name opcode_name_arr[] = {
115 /* in ascending opcode order */
116 {TEST_UNIT_READY, "test unit ready"}, /* 0x00 */
117 {REQUEST_SENSE, "request sense"}, /* 0x03 */
118 {INQUIRY, "inquiry"}, /* 0x12 */
119 {MODE_SELECT, "mode select"}, /* 0x15 */
120 {MODE_SENSE, "mode sense"}, /* 0x1a */
121 {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */
122 {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */
123 {READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */
124 {LOG_SENSE, "log sense"}, /* 0x4d */
125 {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */
126 {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */
127 };
128
129 const char * scsi_get_opcode_name(UINT8 opcode)
130 {
131 int k;
132 int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);
133 struct scsi_opcode_name * onp;
134
135 for (k = 0; k < len; ++k) {
136 onp = &opcode_name_arr[k];
137 if (opcode == onp->opcode)
138 return onp->name;
139 else if (opcode < onp->opcode)
140 return NULL;
141 }
142 return NULL;
143 }
144
145
146 void scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
147 struct scsi_sense_disect * out)
148 {
149 memset(out, 0, sizeof(struct scsi_sense_disect));
150 if ((SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) &&
151 (io_buf->resp_sense_len > 7)) {
152 out->error_code = (io_buf->sensep[0] & 0x7f);
153 out->sense_key = (io_buf->sensep[2] & 0xf);
154 if (io_buf->resp_sense_len > 13) {
155 out->asc = io_buf->sensep[12];
156 out->ascq = io_buf->sensep[13];
157 }
158 }
159 }
160
161 static int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo)
162 {
163 switch (sinfo->sense_key) {
164 case SCSI_SK_NOT_READY:
165 if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
166 return SIMPLE_ERR_NO_MEDIUM;
167 else if (SCSI_ASC_NOT_READY == sinfo->asc) {
168 if (0x1 == sinfo->ascq)
169 return SIMPLE_ERR_BECOMING_READY;
170 else
171 return SIMPLE_ERR_NOT_READY;
172 } else
173 return SIMPLE_ERR_NOT_READY;
174 case SCSI_SK_MEDIUM_ERROR:
175 case SCSI_SK_HARDWARE_ERROR:
176 return SIMPLE_ERR_MEDIUM_HARDWARE;
177 case SCSI_SK_ILLEGAL_REQUEST:
178 if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)
179 return SIMPLE_ERR_BAD_OPCODE;
180 else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc)
181 return SIMPLE_ERR_BAD_FIELD;
182 else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)
183 return SIMPLE_ERR_BAD_PARAM;
184 else
185 return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */
186 case SCSI_SK_UNIT_ATTENTION:
187 return SIMPLE_ERR_TRY_AGAIN;
188 default:
189 return SIMPLE_NO_ERROR;
190 }
191 }
192
193 const char * scsiErrString(int scsiErr)
194 {
195 if (scsiErr < 0)
196 return strerror(-scsiErr);
197 switch (scsiErr) {
198 case SIMPLE_NO_ERROR:
199 return "no error";
200 case SIMPLE_ERR_NOT_READY:
201 return "device not ready";
202 case SIMPLE_ERR_BAD_OPCODE:
203 return "unsupported scsi opcode";
204 case SIMPLE_ERR_BAD_FIELD:
205 return "unsupported field in scsi command";
206 case SIMPLE_ERR_BAD_PARAM:
207 return "badly formed scsi parameters";
208 case SIMPLE_ERR_BAD_RESP:
209 return "scsi response fails sanity test";
210 case SIMPLE_ERR_NO_MEDIUM:
211 return "no medium present";
212 case SIMPLE_ERR_BECOMING_READY:
213 return "device will be ready soon";
214 case SIMPLE_ERR_TRY_AGAIN:
215 return "unit attention reported, try again";
216 case SIMPLE_ERR_MEDIUM_HARDWARE:
217 return "medium or hardware error (serious)";
218 default:
219 return "unknown error";
220 }
221 }
222
223 /* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if
224 command not supported, 3 if field (within command) not supported or
225 returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a).
226 N.B. Sets PC==1 to fetch "current cumulative" log pages.
227 If known_resp_len > 0 then a single fetch is done for this response
228 length. If known_resp_len == 0 then twin fetches are performed, the
229 first to deduce the response length, then send the same command again
230 requesting the deduced response length. This protects certain fragile
231 HBAs. The twin fetch technique should not be used with the TapeAlert
232 log page since it clears its state flags after each fetch. */
233 int scsiLogSense(int device, int pagenum, UINT8 *pBuf, int bufLen,
234 int known_resp_len)
235 {
236 struct scsi_cmnd_io io_hdr;
237 struct scsi_sense_disect sinfo;
238 UINT8 cdb[10];
239 UINT8 sense[32];
240 int pageLen;
241 int status, res;
242
243 if (known_resp_len > bufLen)
244 return -EIO;
245 if (known_resp_len > 0)
246 pageLen = known_resp_len;
247 else {
248 /* Starting twin fetch strategy: first fetch to find respone length */
249 pageLen = 4;
250 if (pageLen > bufLen)
251 return -EIO;
252 else
253 memset(pBuf, 0, pageLen);
254
255 memset(&io_hdr, 0, sizeof(io_hdr));
256 memset(cdb, 0, sizeof(cdb));
257 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
258 io_hdr.dxfer_len = pageLen;
259 io_hdr.dxferp = pBuf;
260 cdb[0] = LOG_SENSE;
261 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
262 cdb[7] = (pageLen >> 8) & 0xff;
263 cdb[8] = pageLen & 0xff;
264 io_hdr.cmnd = cdb;
265 io_hdr.cmnd_len = sizeof(cdb);
266 io_hdr.sensep = sense;
267 io_hdr.max_sense_len = sizeof(sense);
268 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
269
270 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
271 if (0 != status)
272 return status;
273 scsi_do_sense_disect(&io_hdr, &sinfo);
274 if ((res = scsiSimpleSenseFilter(&sinfo)))
275 return res;
276 /* sanity check on response */
277 if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))
278 return SIMPLE_ERR_BAD_RESP;
279 if (0 == ((pBuf[2] << 8) + pBuf[3]))
280 return SIMPLE_ERR_BAD_RESP;
281 pageLen = (pBuf[2] << 8) + pBuf[3] + 4;
282 /* some SCSI HBA don't like "odd" length transfers */
283 if (pageLen % 2)
284 pageLen += 1;
285 if (pageLen > bufLen)
286 pageLen = bufLen;
287 }
288 memset(pBuf, 0, 4);
289 memset(&io_hdr, 0, sizeof(io_hdr));
290 memset(cdb, 0, sizeof(cdb));
291 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
292 io_hdr.dxfer_len = pageLen;
293 io_hdr.dxferp = pBuf;
294 cdb[0] = LOG_SENSE;
295 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
296 cdb[7] = (pageLen >> 8) & 0xff;
297 cdb[8] = pageLen & 0xff;
298 io_hdr.cmnd = cdb;
299 io_hdr.cmnd_len = sizeof(cdb);
300 io_hdr.sensep = sense;
301 io_hdr.max_sense_len = sizeof(sense);
302 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
303
304 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
305 if (0 != status)
306 return status;
307 scsi_do_sense_disect(&io_hdr, &sinfo);
308 status = scsiSimpleSenseFilter(&sinfo);
309 if (0 != status)
310 return status;
311 /* sanity check on response */
312 if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))
313 return SIMPLE_ERR_BAD_RESP;
314 if (0 == ((pBuf[2] << 8) + pBuf[3]))
315 return SIMPLE_ERR_BAD_RESP;
316 return 0;
317 }
318
319 /* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
320 * 2 if command not supported (then MODE SENSE(10) should be supported),
321 * 3 if field in command not supported or returns negated errno.
322 * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
323 int scsiModeSense(int device, int pagenum, int pc, UINT8 *pBuf, int bufLen)
324 {
325 struct scsi_cmnd_io io_hdr;
326 struct scsi_sense_disect sinfo;
327 UINT8 cdb[6];
328 UINT8 sense[32];
329 int status;
330
331 if ((bufLen < 0) || (bufLen > 255))
332 return -EINVAL;
333 memset(&io_hdr, 0, sizeof(io_hdr));
334 memset(cdb, 0, sizeof(cdb));
335 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
336 io_hdr.dxfer_len = bufLen;
337 io_hdr.dxferp = pBuf;
338 cdb[0] = MODE_SENSE;
339 cdb[2] = (pc << 6) | (pagenum & 0x3f);
340 cdb[4] = bufLen;
341 io_hdr.cmnd = cdb;
342 io_hdr.cmnd_len = sizeof(cdb);
343 io_hdr.sensep = sense;
344 io_hdr.max_sense_len = sizeof(sense);
345 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
346
347 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
348 if (0 != status)
349 return status;
350 scsi_do_sense_disect(&io_hdr, &sinfo);
351 status = scsiSimpleSenseFilter(&sinfo);
352 if (SIMPLE_ERR_TRY_AGAIN == status) {
353 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
354 if (0 != status)
355 return status;
356 scsi_do_sense_disect(&io_hdr, &sinfo);
357 status = scsiSimpleSenseFilter(&sinfo);
358 }
359 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
360 int offset;
361
362 offset = scsiModePageOffset(pBuf, bufLen, 0);
363 if (offset < 0)
364 return SIMPLE_ERR_BAD_RESP;
365 else if (pagenum != (pBuf[offset] & 0x3f))
366 return SIMPLE_ERR_BAD_RESP;
367 }
368 return status;
369 }
370
371 /* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response
372 * from a corresponding 6 byte MODE SENSE command. Such a response should
373 * have a 4 byte header followed by 0 or more 8 byte block descriptors
374 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY,
375 * 2 if command not supported (then MODE SELECT(10) may be supported),
376 * 3 if field in command not supported, 4 if bad parameter to command
377 * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
378 int scsiModeSelect(int device, int sp, UINT8 *pBuf, int bufLen)
379 {
380 struct scsi_cmnd_io io_hdr;
381 struct scsi_sense_disect sinfo;
382 UINT8 cdb[6];
383 UINT8 sense[32];
384 int status, pg_offset, pg_len, hdr_plus_1_pg;
385
386 pg_offset = 4 + pBuf[3];
387 if (pg_offset + 2 >= bufLen)
388 return -EINVAL;
389 pg_len = pBuf[pg_offset + 1] + 2;
390 hdr_plus_1_pg = pg_offset + pg_len;
391 if (hdr_plus_1_pg > bufLen)
392 return -EINVAL;
393 pBuf[0] = 0; /* Length of returned mode sense data reserved for SELECT */
394 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
395 memset(&io_hdr, 0, sizeof(io_hdr));
396 memset(cdb, 0, sizeof(cdb));
397 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
398 io_hdr.dxfer_len = hdr_plus_1_pg;
399 io_hdr.dxferp = pBuf;
400 cdb[0] = MODE_SELECT;
401 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
402 cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */
403 io_hdr.cmnd = cdb;
404 io_hdr.cmnd_len = sizeof(cdb);
405 io_hdr.sensep = sense;
406 io_hdr.max_sense_len = sizeof(sense);
407 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
408
409 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
410 if (0 != status)
411 return status;
412 scsi_do_sense_disect(&io_hdr, &sinfo);
413 return scsiSimpleSenseFilter(&sinfo);
414 }
415
416 /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
417 * not supported (then MODE SENSE(6) might be supported), 3 if field in
418 * command not supported or returns negated errno.
419 * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
420 int scsiModeSense10(int device, int pagenum, int pc, UINT8 *pBuf, int bufLen)
421 {
422 struct scsi_cmnd_io io_hdr;
423 struct scsi_sense_disect sinfo;
424 UINT8 cdb[10];
425 UINT8 sense[32];
426 int status;
427
428 memset(&io_hdr, 0, sizeof(io_hdr));
429 memset(cdb, 0, sizeof(cdb));
430 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
431 io_hdr.dxfer_len = bufLen;
432 io_hdr.dxferp = pBuf;
433 cdb[0] = MODE_SENSE_10;
434 cdb[2] = (pc << 6) | (pagenum & 0x3f);
435 cdb[7] = (bufLen >> 8) & 0xff;
436 cdb[8] = bufLen & 0xff;
437 io_hdr.cmnd = cdb;
438 io_hdr.cmnd_len = sizeof(cdb);
439 io_hdr.sensep = sense;
440 io_hdr.max_sense_len = sizeof(sense);
441 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
442
443 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
444 if (0 != status)
445 return status;
446 scsi_do_sense_disect(&io_hdr, &sinfo);
447 status = scsiSimpleSenseFilter(&sinfo);
448 if (SIMPLE_ERR_TRY_AGAIN == status) {
449 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
450 if (0 != status)
451 return status;
452 scsi_do_sense_disect(&io_hdr, &sinfo);
453 status = scsiSimpleSenseFilter(&sinfo);
454 }
455 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
456 int offset;
457
458 offset = scsiModePageOffset(pBuf, bufLen, 1);
459 if (offset < 0)
460 return SIMPLE_ERR_BAD_RESP;
461 else if (pagenum != (pBuf[offset] & 0x3f))
462 return SIMPLE_ERR_BAD_RESP;
463 }
464 return status;
465 }
466
467 /* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response
468 * from a corresponding 10 byte MODE SENSE command. Such a response should
469 * have a 8 byte header followed by 0 or more 8 byte block descriptors
470 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
471 * command not supported (then MODE SELECT(6) may be supported), 3 if field
472 * in command not supported, 4 if bad parameter to command or returns
473 * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
474 int scsiModeSelect10(int device, int sp, UINT8 *pBuf, int bufLen)
475 {
476 struct scsi_cmnd_io io_hdr;
477 struct scsi_sense_disect sinfo;
478 UINT8 cdb[10];
479 UINT8 sense[32];
480 int status, pg_offset, pg_len, hdr_plus_1_pg;
481
482 pg_offset = 8 + (pBuf[6] << 8) + pBuf[7];
483 if (pg_offset + 2 >= bufLen)
484 return -EINVAL;
485 pg_len = pBuf[pg_offset + 1] + 2;
486 hdr_plus_1_pg = pg_offset + pg_len;
487 if (hdr_plus_1_pg > bufLen)
488 return -EINVAL;
489 pBuf[0] = 0;
490 pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */
491 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
492 memset(&io_hdr, 0, sizeof(io_hdr));
493 memset(cdb, 0, sizeof(cdb));
494 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
495 io_hdr.dxfer_len = hdr_plus_1_pg;
496 io_hdr.dxferp = pBuf;
497 cdb[0] = MODE_SELECT_10;
498 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
499 cdb[8] = hdr_plus_1_pg; /* make sure only one page sent */
500 io_hdr.cmnd = cdb;
501 io_hdr.cmnd_len = sizeof(cdb);
502 io_hdr.sensep = sense;
503 io_hdr.max_sense_len = sizeof(sense);
504 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
505
506 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
507 if (0 != status)
508 return status;
509 scsi_do_sense_disect(&io_hdr, &sinfo);
510 return scsiSimpleSenseFilter(&sinfo);
511 }
512
513 /* Standard INQUIRY returns 0 for ok, anything else is a major problem.
514 * bufLen should be 36 for unsafe devices (like USB mass storage stuff)
515 * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
516 int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen)
517 {
518 struct scsi_sense_disect sinfo;
519 struct scsi_cmnd_io io_hdr;
520 UINT8 cdb[6];
521 UINT8 sense[32];
522 int status;
523
524 if ((bufLen < 0) || (bufLen > 255))
525 return -EINVAL;
526 memset(&io_hdr, 0, sizeof(io_hdr));
527 memset(cdb, 0, sizeof(cdb));
528 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
529 io_hdr.dxfer_len = bufLen;
530 io_hdr.dxferp = pBuf;
531 cdb[0] = INQUIRY;
532 cdb[4] = bufLen;
533 io_hdr.cmnd = cdb;
534 io_hdr.cmnd_len = sizeof(cdb);
535 io_hdr.sensep = sense;
536 io_hdr.max_sense_len = sizeof(sense);
537 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
538
539 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
540 if (0 != status)
541 return status;
542 scsi_do_sense_disect(&io_hdr, &sinfo);
543 return scsiSimpleSenseFilter(&sinfo);
544 }
545
546 /* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
547 * (unlikely), 2 if command not supported, 3 if field in command not
548 * supported, 5 if response indicates that EVPD bit ignored or returns
549 * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
550 int scsiInquiryVpd(int device, int vpd_page, UINT8 *pBuf, int bufLen)
551 {
552 struct scsi_cmnd_io io_hdr;
553 struct scsi_sense_disect sinfo;
554 UINT8 cdb[6];
555 UINT8 sense[32];
556 int status, res;
557
558 if ((bufLen < 0) || (bufLen > 255))
559 return -EINVAL;
560 memset(&io_hdr, 0, sizeof(io_hdr));
561 memset(cdb, 0, sizeof(cdb));
562 if (bufLen > 1)
563 pBuf[1] = 0x0;
564 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
565 io_hdr.dxfer_len = bufLen;
566 io_hdr.dxferp = pBuf;
567 cdb[0] = INQUIRY;
568 cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
569 cdb[2] = vpd_page;
570 cdb[4] = bufLen;
571 io_hdr.cmnd = cdb;
572 io_hdr.cmnd_len = sizeof(cdb);
573 io_hdr.sensep = sense;
574 io_hdr.max_sense_len = sizeof(sense);
575 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
576
577 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
578 if (0 != status)
579 return status;
580 scsi_do_sense_disect(&io_hdr, &sinfo);
581 if ((res = scsiSimpleSenseFilter(&sinfo)))
582 return res;
583 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
584 if (bufLen > 1) {
585 if (vpd_page == pBuf[1]) {
586 if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2]))
587 return SIMPLE_ERR_BAD_RESP;
588 } else
589 return SIMPLE_ERR_BAD_RESP;
590 }
591 return 0;
592 }
593
594 /* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
595 * SPC-3 section 6.27 (rev 22a) */
596 int scsiRequestSense(int device, struct scsi_sense_disect * sense_info)
597 {
598 struct scsi_cmnd_io io_hdr;
599 UINT8 cdb[6];
600 UINT8 sense[32];
601 UINT8 buff[18];
602 int status, len;
603 UINT8 ecode;
604
605 memset(&io_hdr, 0, sizeof(io_hdr));
606 memset(cdb, 0, sizeof(cdb));
607 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
608 io_hdr.dxfer_len = sizeof(buff);
609 io_hdr.dxferp = buff;
610 cdb[0] = REQUEST_SENSE;
611 cdb[4] = sizeof(buff);
612 io_hdr.cmnd = cdb;
613 io_hdr.cmnd_len = sizeof(cdb);
614 io_hdr.sensep = sense;
615 io_hdr.max_sense_len = sizeof(sense);
616 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
617
618 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
619 if ((0 == status) && (sense_info)) {
620 ecode = buff[0] & 0x7f;
621 sense_info->error_code = ecode;
622 sense_info->sense_key = buff[2] & 0xf;
623 sense_info->asc = 0;
624 sense_info->ascq = 0;
625 if ((0x70 == ecode) || (0x71 == ecode)) {
626 len = buff[7] + 8;
627 if (len > 13) {
628 sense_info->asc = buff[12];
629 sense_info->ascq = buff[13];
630 }
631 }
632 }
633 return status;
634 }
635
636 /* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
637 * not supported, 3 if field in command not supported or returns negated
638 * errno. SPC-3 section 6.28 (rev 22a) */
639 int scsiSendDiagnostic(int device, int functioncode, UINT8 *pBuf, int bufLen)
640 {
641 struct scsi_cmnd_io io_hdr;
642 struct scsi_sense_disect sinfo;
643 UINT8 cdb[6];
644 UINT8 sense[32];
645 int status;
646
647 memset(&io_hdr, 0, sizeof(io_hdr));
648 memset(cdb, 0, sizeof(cdb));
649 io_hdr.dxfer_dir = bufLen ? DXFER_TO_DEVICE: DXFER_NONE;
650 io_hdr.dxfer_len = bufLen;
651 io_hdr.dxferp = pBuf;
652 cdb[0] = SEND_DIAGNOSTIC;
653 if (SCSI_DIAG_DEF_SELF_TEST == functioncode)
654 cdb[1] = 0x4; /* SelfTest bit */
655 else if (SCSI_DIAG_NO_SELF_TEST != functioncode)
656 cdb[1] = (functioncode & 0x7) << 5; /* SelfTest _code_ */
657 else /* SCSI_DIAG_NO_SELF_TEST == functioncode */
658 cdb[1] = 0x10; /* PF bit */
659 cdb[3] = (bufLen >> 8) & 0xff;
660 cdb[4] = bufLen & 0xff;
661 io_hdr.cmnd = cdb;
662 io_hdr.cmnd_len = sizeof(cdb);
663 io_hdr.sensep = sense;
664 io_hdr.max_sense_len = sizeof(sense);
665 /* worst case is an extended foreground self test on a big disk */
666 io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST;
667
668 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
669 if (0 != status)
670 return status;
671 scsi_do_sense_disect(&io_hdr, &sinfo);
672 return scsiSimpleSenseFilter(&sinfo);
673 }
674
675 /* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if
676 * command not supported, 3 if field in command not supported or returns
677 * negated errno. SPC-3 section 6.18 (rev 22a) */
678 int scsiReceiveDiagnostic(int device, int pcv, int pagenum, UINT8 *pBuf,
679 int bufLen)
680 {
681 struct scsi_cmnd_io io_hdr;
682 struct scsi_sense_disect sinfo;
683 UINT8 cdb[6];
684 UINT8 sense[32];
685 int status;
686
687 memset(&io_hdr, 0, sizeof(io_hdr));
688 memset(cdb, 0, sizeof(cdb));
689 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
690 io_hdr.dxfer_len = bufLen;
691 io_hdr.dxferp = pBuf;
692 cdb[0] = RECEIVE_DIAGNOSTIC;
693 cdb[1] = pcv;
694 cdb[2] = pagenum;
695 cdb[3] = (bufLen >> 8) & 0xff;
696 cdb[4] = bufLen & 0xff;
697 io_hdr.cmnd = cdb;
698 io_hdr.cmnd_len = sizeof(cdb);
699 io_hdr.sensep = sense;
700 io_hdr.max_sense_len = sizeof(sense);
701 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
702
703 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
704 if (0 != status)
705 return status;
706 scsi_do_sense_disect(&io_hdr, &sinfo);
707 return scsiSimpleSenseFilter(&sinfo);
708 }
709
710 /* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
711 static int _testunitready(int device, struct scsi_sense_disect * sinfo)
712 {
713 struct scsi_cmnd_io io_hdr;
714 UINT8 cdb[6];
715 UINT8 sense[32];
716 int status;
717
718 memset(&io_hdr, 0, sizeof(io_hdr));
719 memset(cdb, 0, sizeof(cdb));
720 io_hdr.dxfer_dir = DXFER_NONE;
721 io_hdr.dxfer_len = 0;
722 io_hdr.dxferp = NULL;
723 cdb[0] = TEST_UNIT_READY;
724 io_hdr.cmnd = cdb;
725 io_hdr.cmnd_len = sizeof(cdb);
726 io_hdr.sensep = sense;
727 io_hdr.max_sense_len = sizeof(sense);
728 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
729
730 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
731 if (0 != status)
732 return status;
733 scsi_do_sense_disect(&io_hdr, sinfo);
734 return 0;
735 }
736
737 /* Returns 0 for device responds and media ready, 1 for device responds and
738 media not ready, or returns a negated errno value */
739 int scsiTestUnitReady(int device)
740 {
741 struct scsi_sense_disect sinfo;
742 int status;
743
744 status = _testunitready(device, &sinfo);
745 if (0 != status)
746 return status;
747 status = scsiSimpleSenseFilter(&sinfo);
748 if (SIMPLE_ERR_TRY_AGAIN == status) {
749 /* power on reset, media changed, ok ... try again */
750 status = _testunitready(device, &sinfo);
751 if (0 != status)
752 return status;
753 status = scsiSimpleSenseFilter(&sinfo);
754 }
755 return status;
756 }
757
758 /* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
759 * command not supported, 3 if field in command not supported or returns
760 * negated errno. SBC-2 section 5.12 (rev 16) */
761 int scsiReadDefect10(int device, int req_plist, int req_glist, int dl_format,
762 UINT8 *pBuf, int bufLen)
763 {
764 struct scsi_cmnd_io io_hdr;
765 struct scsi_sense_disect sinfo;
766 UINT8 cdb[10];
767 UINT8 sense[32];
768 int status;
769
770 memset(&io_hdr, 0, sizeof(io_hdr));
771 memset(cdb, 0, sizeof(cdb));
772 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
773 io_hdr.dxfer_len = bufLen;
774 io_hdr.dxferp = pBuf;
775 cdb[0] = READ_DEFECT_10;
776 cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) |
777 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
778 cdb[7] = (bufLen >> 8) & 0xff;
779 cdb[8] = bufLen & 0xff;
780 io_hdr.cmnd = cdb;
781 io_hdr.cmnd_len = sizeof(cdb);
782 io_hdr.sensep = sense;
783 io_hdr.max_sense_len = sizeof(sense);
784 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
785
786 status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
787 if (0 != status)
788 return status;
789 scsi_do_sense_disect(&io_hdr, &sinfo);
790 return scsiSimpleSenseFilter(&sinfo);
791 }
792
793 /* Offset into mode sense (6 or 10 byte) response that actual mode page
794 * starts at (relative to resp[0]). Returns -1 if problem */
795 int scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
796 {
797 int resp_len, bd_len;
798 int offset = -1;
799
800 if (resp) {
801 if (10 == modese_len) {
802 resp_len = (resp[0] << 8) + resp[1] + 2;
803 bd_len = (resp[6] << 8) + resp[7];
804 offset = bd_len + 8;
805 } else {
806 resp_len = resp[0] + 1;
807 bd_len = resp[3];
808 offset = bd_len + 4;
809 }
810 if ((offset + 2) > len) {
811 pout("scsiModePageOffset: raw_curr too small, offset=%d "
812 "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
813 offset = -1;
814 } else if ((offset + 2) > resp_len) {
815 if ((resp_len > 2) || con->reportscsiioctl)
816 pout("scsiModePageOffset: response length too short, "
817 "resp_len=%d offset=%d bd_len=%d\n", resp_len,
818 offset, bd_len);
819 offset = -1;
820 }
821 }
822 return offset;
823 }
824
825 /* IEC mode page byte 2 bit masks */
826 #define DEXCPT_ENABLE 0x08
827 #define EWASC_ENABLE 0x10
828 #define DEXCPT_DISABLE 0xf7
829 #define EWASC_DISABLE 0xef
830 #define TEST_DISABLE 0xfb
831
832 /* Fetches the Informational Exceptions Control mode page. First tries
833 * the 6 byte MODE SENSE command and if that fails with an illegal opcode
834 * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
835 * number if a known error (see SIMPLE_ERR_ ...) or a negative errno
836 * value. */
837 int scsiFetchIECmpage(int device, struct scsi_iec_mode_page *iecp, int modese_len)
838 {
839 int err = 0;
840
841 memset(iecp, 0, sizeof(*iecp));
842 iecp->modese_len = modese_len;
843 iecp->requestedCurrent = 1;
844 if (iecp->modese_len <= 6) {
845 if ((err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
846 MPAGE_CONTROL_CURRENT,
847 iecp->raw_curr, sizeof(iecp->raw_curr)))) {
848 if (SIMPLE_ERR_BAD_OPCODE == err)
849 iecp->modese_len = 10;
850 else {
851 iecp->modese_len = 0;
852 return err;
853 }
854 } else if (0 == iecp->modese_len)
855 iecp->modese_len = 6;
856 }
857 if (10 == iecp->modese_len) {
858 err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
859 MPAGE_CONTROL_CURRENT,
860 iecp->raw_curr, sizeof(iecp->raw_curr));
861 if (err) {
862 iecp->modese_len = 0;
863 return err;
864 }
865 }
866 iecp->gotCurrent = 1;
867 iecp->requestedChangeable = 1;
868 if (10 == iecp->modese_len)
869 err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
870 MPAGE_CONTROL_CHANGEABLE,
871 iecp->raw_chg, sizeof(iecp->raw_chg));
872 else if (6 == iecp->modese_len)
873 err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
874 MPAGE_CONTROL_CHANGEABLE,
875 iecp->raw_chg, sizeof(iecp->raw_chg));
876 if (err)
877 return err;
878 iecp->gotChangeable = 1;
879 return 0;
880 }
881
882 int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
883 {
884 int offset;
885
886 if (iecp && iecp->gotCurrent) {
887 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
888 iecp->modese_len);
889 if (offset >= 0)
890 return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
891 else
892 return 0;
893 } else
894 return 0;
895 }
896
897 int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
898 {
899 int offset;
900
901 if (iecp && iecp->gotCurrent) {
902 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
903 iecp->modese_len);
904 if (offset >= 0)
905 return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
906 else
907 return 0;
908 } else
909 return 0;
910 }
911
912 /* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */
913 #define SCSI_IEC_MP_BYTE2_ENABLED 0x10
914 #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
915 /* exception/warning via an unrequested REQUEST SENSE command */
916 #define SCSI_IEC_MP_MRIE 6
917 #define SCSI_IEC_MP_INTERVAL_T 0
918 #define SCSI_IEC_MP_REPORT_COUNT 1
919
920 /* Try to set (or clear) both Exception Control and Warning in the IE
921 * mode page subject to the "changeable" mask. The object pointed to
922 * by iecp is (possibly) inaccurate after this call, therefore
923 * scsiFetchIECmpage() should be called again if the IEC mode page
924 * is to be re-examined.
925 * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
926 * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
927 int scsiSetExceptionControlAndWarning(int device, int enabled,
928 const struct scsi_iec_mode_page *iecp)
929 {
930 int k, offset, resp_len;
931 int err = 0;
932 UINT8 rout[SCSI_IECMP_RAW_LEN];
933 int sp, eCEnabled, wEnabled;
934
935 if ((! iecp) || (! iecp->gotCurrent))
936 return -EINVAL;
937 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
938 iecp->modese_len);
939 if (offset < 0)
940 return -EINVAL;
941 memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN);
942 if (10 == iecp->modese_len) {
943 resp_len = (rout[0] << 8) + rout[1] + 2;
944 rout[3] &= 0xef; /* for disks mask out DPOFUA bit */
945 } else {
946 resp_len = rout[0] + 1;
947 rout[2] &= 0xef; /* for disks mask out DPOFUA bit */
948 }
949 sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
950 if (enabled) {
951 rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
952 if (con->reportscsiioctl > 2)
953 rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
954 rout[offset + 3] = SCSI_IEC_MP_MRIE;
955 rout[offset + 4] = (SCSI_IEC_MP_INTERVAL_T >> 24) & 0xff;
956 rout[offset + 5] = (SCSI_IEC_MP_INTERVAL_T >> 16) & 0xff;
957 rout[offset + 6] = (SCSI_IEC_MP_INTERVAL_T >> 8) & 0xff;
958 rout[offset + 7] = SCSI_IEC_MP_INTERVAL_T & 0xff;
959 rout[offset + 8] = (SCSI_IEC_MP_REPORT_COUNT >> 24) & 0xff;
960 rout[offset + 9] = (SCSI_IEC_MP_REPORT_COUNT >> 16) & 0xff;
961 rout[offset + 10] = (SCSI_IEC_MP_REPORT_COUNT >> 8) & 0xff;
962 rout[offset + 11] = SCSI_IEC_MP_REPORT_COUNT & 0xff;
963 if (iecp->gotChangeable) {
964 UINT8 chg2 = iecp->raw_chg[offset + 2];
965
966 rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
967 iecp->raw_curr[offset + 2];
968 for (k = 3; k < 12; ++k) {
969 if (0 == iecp->raw_chg[offset + k])
970 rout[offset + k] = iecp->raw_curr[offset + k];
971 }
972 }
973 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
974 if (con->reportscsiioctl > 0)
975 pout("scsiSetExceptionControlAndWarning: already enabled\n");
976 return 0;
977 }
978 } else { /* disabling Exception Control and (temperature) Warnings */
979 eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
980 wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
981 if ((! eCEnabled) && (! wEnabled)) {
982 if (con->reportscsiioctl > 0)
983 pout("scsiSetExceptionControlAndWarning: already disabled\n");
984 return 0; /* nothing to do, leave other setting alone */
985 }
986 if (wEnabled)
987 rout[offset + 2] &= EWASC_DISABLE;
988 if (eCEnabled) {
989 if (iecp->gotChangeable &&
990 (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
991 rout[offset + 2] |= DEXCPT_ENABLE;
992 rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */
993 }
994 }
995 if (10 == iecp->modese_len)
996 err = scsiModeSelect10(device, sp, rout, resp_len);
997 else if (6 == iecp->modese_len)
998 err = scsiModeSelect(device, sp, rout, resp_len);
999 return err;
1000 }
1001
1002 int scsiGetTemp(int device, UINT8 *currenttemp, UINT8 *triptemp)
1003 {
1004 UINT8 tBuf[252];
1005 int err;
1006
1007 memset(tBuf, 0, sizeof(tBuf));
1008 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, tBuf,
1009 sizeof(tBuf), 0))) {
1010 *currenttemp = 0;
1011 *triptemp = 0;
1012 pout("Log Sense for temperature failed [%s]\n", scsiErrString(err));
1013 return err;
1014 }
1015 *currenttemp = tBuf[9];
1016 *triptemp = tBuf[15];
1017 return 0;
1018 }
1019
1020 /* Read informational exception log page or Request Sense response.
1021 * Fetching asc/ascq code potentially flagging an exception or warning.
1022 * Returns 0 if ok, else error number. A current temperature of 255
1023 * (Celsius) implies that the temperature not available. */
1024 int scsiCheckIE(int device, int hasIELogPage, int hasTempLogPage,
1025 UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp,
1026 UINT8 *triptemp)
1027 {
1028 UINT8 tBuf[252];
1029 struct scsi_sense_disect sense_info;
1030 int err;
1031 int temperatureSet = 0;
1032 unsigned short pagesize;
1033 UINT8 currTemp, trTemp;
1034
1035 *asc = 0;
1036 *ascq = 0;
1037 *currenttemp = 0;
1038 *triptemp = 0;
1039 memset(tBuf,0,sizeof(tBuf)); // need to clear stack space of junk
1040 memset(&sense_info, 0, sizeof(sense_info));
1041 if (hasIELogPage) {
1042 if ((err = scsiLogSense(device, IE_LPAGE, tBuf,
1043 sizeof(tBuf), 0))) {
1044 pout("Log Sense failed, IE page [%s]\n", scsiErrString(err));
1045 return err;
1046 }
1047 // pull out page size from response, don't forget to add 4
1048 pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4;
1049 if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
1050 pout("Log Sense failed, IE page, bad parameter code or length\n");
1051 return SIMPLE_ERR_BAD_PARAM;
1052 }
1053 if (tBuf[7] > 1) {
1054 sense_info.asc = tBuf[8];
1055 sense_info.ascq = tBuf[9];
1056 if (! hasTempLogPage) {
1057 if (tBuf[7] > 2)
1058 *currenttemp = tBuf[10];
1059 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
1060 *triptemp = tBuf[11];
1061 }
1062 }
1063 }
1064 if (0 == sense_info.asc) {
1065 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
1066 if ((err = scsiRequestSense(device, &sense_info))) {
1067 pout("Request Sense failed, [%s]\n", scsiErrString(err));
1068 return err;
1069 }
1070 }
1071 *asc = sense_info.asc;
1072 *ascq = sense_info.ascq;
1073 if ((! temperatureSet) && hasTempLogPage) {
1074 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
1075 *currenttemp = currTemp;
1076 *triptemp = trTemp;
1077 }
1078 }
1079 return 0;
1080 }
1081
1082 // The first character (W, C, I) tells the severity
1083 static const char * TapeAlertsMessageTable[]= {
1084 " ",
1085 /* 0x01 */
1086 "W: The tape drive is having problems reading data. No data has been lost,\n"
1087 " but there has been a reduction in the performance of the tape.",
1088 /* 0x02 */
1089 "W: The tape drive is having problems writing data. No data has been lost,\n"
1090 " but there has been a reduction in the capacity of the tape.",
1091 /* 0x03 */
1092 "W: The operation has stopped because an error has occurred while reading\n"
1093 " or writing data that the drive cannot correct.",
1094 /* 0x04 */
1095 "C: Your data is at risk:\n"
1096 " 1. Copy any data you require from this tape. \n"
1097 " 2. Do not use this tape again.\n"
1098 " 3. Restart the operation with a different tape.",
1099 /* 0x05 */
1100 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
1101 " supplier helpline.",
1102 /* 0x06 */
1103 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
1104 " 1. Use a good tape to test the drive.\n"
1105 " 2. If problem persists, call the tape drive supplier helpline.",
1106 /* 0x07 */
1107 "W: The tape cartridge has reached the end of its calculated useful life:\n"
1108 " 1. Copy data you need to another tape.\n"
1109 " 2. Discard the old tape.",
1110 /* 0x08 */
1111 "W: The tape cartridge is not data-grade. Any data you back up to the tape\n"
1112 " is at risk. Replace the cartridge with a data-grade tape.",
1113 /* 0x09 */
1114 "C: You are trying to write to a write-protected cartridge. Remove the\n"
1115 " write-protection or use another tape.",
1116 /* 0x0a */
1117 "I: You cannot eject the cartridge because the tape drive is in use. Wait\n"
1118 " until the operation is complete before ejecting the cartridge.",
1119 /* 0x0b */
1120 "I: The tape in the drive is a cleaning cartridge.",
1121 /* 0x0c */
1122 "I: You have tried to load a cartridge of a type which is not supported\n"
1123 " by this drive.",
1124 /* 0x0d */
1125 "C: The operation has failed because the tape in the drive has experienced\n"
1126 " a mechanical failure:\n"
1127 " 1. Discard the old tape.\n"
1128 " 2. Restart the operation with a different tape.",
1129 /* 0x0e */
1130 "C: The operation has failed because the tape in the drive has experienced\n"
1131 " a mechanical failure:\n"
1132 " 1. Do not attempt to extract the tape cartridge\n"
1133 " 2. Call the tape drive supplier helpline.",
1134 /* 0x0f */
1135 "W: The memory in the tape cartridge has failed, which reduces\n"
1136 " performance. Do not use the cartridge for further write operations.",
1137 /* 0x10 */
1138 "C: The operation has failed because the tape cartridge was manually\n"
1139 " de-mounted while the tape drive was actively writing or reading.",
1140 /* 0x11 */
1141 "W: You have loaded a cartridge of a type that is read-only in this drive.\n"
1142 " The cartridge will appear as write-protected.",
1143 /* 0x12 */
1144 "W: The tape directory on the tape cartridge has been corrupted. File\n"
1145 " search performance will be degraded. The tape directory can be rebuilt\n"
1146 " by reading all the data on the cartridge.",
1147 /* 0x13 */
1148 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
1149 " recommended that you:\n"
1150 " 1. Use another tape cartridge for your next backup.\n"
1151 " 2. Store this tape in a safe place in case you need to restore "
1152 " data from it.",
1153 /* 0x14 */
1154 "C: The tape drive needs cleaning:\n"
1155 " 1. If the operation has stopped, eject the tape and clean the drive.\n"
1156 " 2. If the operation has not stopped, wait for it to finish and then\n"
1157 " clean the drive.\n"
1158 " Check the tape drive users manual for device specific cleaning instructions.",
1159 /* 0x15 */
1160 "W: The tape drive is due for routine cleaning:\n"
1161 " 1. Wait for the current operation to finish.\n"
1162 " 2. The use a cleaning cartridge.\n"
1163 " Check the tape drive users manual for device specific cleaning instructions.",
1164 /* 0x16 */
1165 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
1166 " 1. Discard the worn out cleaning cartridge.\n"
1167 " 2. Wait for the current operation to finish.\n"
1168 " 3. Then use a new cleaning cartridge.",
1169 /* 0x17 */
1170 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
1171 " type:\n"
1172 " 1. Do not use this cleaning cartridge in this drive.\n"
1173 " 2. Wait for the current operation to finish.\n"
1174 " 3. Then use a new cleaning cartridge.",
1175 /* 0x18 */
1176 "W: The tape drive has requested a retention operation",
1177 /* 0x19 */
1178 "W: A redundant interface port on the tape drive has failed",
1179 /* 0x1a */
1180 "W: A tape drive cooling fan has failed",
1181 /* 0x1b */
1182 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
1183 " Check the enclosure users manual for instructions on replacing the\n"
1184 " failed power supply.",
1185 /* 0x1c */
1186 "W: The tape drive power consumption is outside the specified range.",
1187 /* 0x1d */
1188 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
1189 " drive users manual for device specific preventive maintenance\n"
1190 " tasks or call the tape drive supplier helpline.",
1191 /* 0x1e */
1192 "C: The tape drive has a hardware fault:\n"
1193 " 1. Eject the tape or magazine.\n"
1194 " 2. Reset the drive.\n"
1195 " 3. Restart the operation.",
1196 /* 0x1f */
1197 "C: The tape drive has a hardware fault:\n"
1198 " 1. Turn the tape drive off and then on again.\n"
1199 " 2. Restart the operation.\n"
1200 " 3. If the problem persists, call the tape drive supplier helpline.",
1201 /* 0x20 */
1202 "W: The tape drive has a problem with the application client interface:\n"
1203 " 1. Check the cables and cable connections.\n"
1204 " 2. Restart the operation.",
1205 /* 0x21 */
1206 "C: The operation has failed:\n"
1207 " 1. Eject the tape or magazine.\n"
1208 " 2. Insert the tape or magazine again.\n"
1209 " 3. Restart the operation.",
1210 /* 0x22 */
1211 "W: The firmware download has failed because you have tried to use the\n"
1212 " incorrect firmware for this tape drive. Obtain the correct\n"
1213 " firmware and try again.",
1214 /* 0x23 */
1215 "W: Environmental conditions inside the tape drive are outside the\n"
1216 " specified humidity range.",
1217 /* 0x24 */
1218 "W: Environmental conditions inside the tape drive are outside the\n"
1219 " specified temperature range.",
1220 /* 0x25 */
1221 "W: The voltage supply to the tape drive is outside the specified range.",
1222 /* 0x26 */
1223 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
1224 " drive supplier helpline.",
1225 /* 0x27 */
1226 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
1227 " verify and diagnose the problem. Check the tape drive users manual for\n"
1228 " device specific instructions on running extended diagnostic tests.",
1229 /* 0x28 */
1230 "C: The changer mechanism is having difficulty communicating with the tape\n"
1231 " drive:\n"
1232 " 1. Turn the autoloader off then on.\n"
1233 " 2. Restart the operation.\n"
1234 " 3. If problem persists, call the tape drive supplier helpline.",
1235 /* 0x29 */
1236 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
1237 " 1. Insert an empty magazine to clear the fault.\n"
1238 " 2. If the fault does not clear, turn the autoloader off and then\n"
1239 " on again.\n"
1240 " 3. If the problem persists, call the tape drive supplier helpline.",
1241 /* 0x2a */
1242 "W: There is a problem with the autoloader mechanism.",
1243 /* 0x2b */
1244 "C: The operation has failed because the autoloader door is open:\n"
1245 " 1. Clear any obstructions from the autoloader door.\n"
1246 " 2. Eject the magazine and then insert it again.\n"
1247 " 3. If the fault does not clear, turn the autoloader off and then\n"
1248 " on again.\n"
1249 " 4. If the problem persists, call the tape drive supplier helpline.",
1250 /* 0x2c */
1251 "C: The autoloader has a hardware fault:\n"
1252 " 1. Turn the autoloader off and then on again.\n"
1253 " 2. Restart the operation.\n"
1254 " 3. If the problem persists, call the tape drive supplier helpline.\n"
1255 " Check the autoloader users manual for device specific instructions\n"
1256 " on turning the device power on and off.",
1257 /* 0x2d */
1258 "C: The autoloader cannot operate without the magazine,\n"
1259 " 1. Insert the magazine into the autoloader.\n"
1260 " 2. Restart the operation.",
1261 /* 0x2e */
1262 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
1263 " tape drive supplier helpline.",
1264 /* 0x2f */
1265 "I: Reserved.",
1266 /* 0x30 */
1267 "I: Reserved.",
1268 /* 0x31 */
1269 "I: Reserved.",
1270 /* 0x32 */
1271 "W: Media statistics have been lost at some time in the past",
1272 /* 0x33 */
1273 "W: The tape directory on the tape cartridge just unloaded has been\n"
1274 " corrupted. File search performance will be degraded. The tape\n"
1275 " directory can be rebuilt by reading all the data.",
1276 /* 0x34 */
1277 "C: The tape just unloaded could not write its system area successfully:\n"
1278 " 1. Copy data to another tape cartridge.\n"
1279 " 2. Discard the old cartridge.",
1280 /* 0x35 */
1281 "C: The tape system are could not be read successfully at load time:\n"
1282 " 1. Copy data to another tape cartridge.\n",
1283 /* 0x36 */
1284 "C: The start or data could not be found on the tape:\n"
1285 " 1. Check you are using the correct format tape.\n"
1286 " 2. Discard the tape or return the tape to your supplier",
1287 /* 0x37 */
1288 "C: The operation has failed because the media cannot be loaded\n"
1289 " and threaded.\n"
1290 " 1. Remove the cartridge, inspect it as specified in the product\n"
1291 " manual, and retry the operation.\n"
1292 " 2. If the problem persists, call the tape drive supplier help line.",
1293 /* 0x38 */
1294 "C: The operation has failed because the medium cannot be unloaded:\n"
1295 " 1. Do not attempt to extract the tape cartridge.\n"
1296 " 2. Call the tape driver supplier help line.",
1297 /* 0x39 */
1298 "C: The tape drive has a problem with the automation interface:\n"
1299 " 1. Check the power to the automation system.\n"
1300 " 2. Check the cables and cable connections.\n"
1301 " 3. Call the supplier help line if problem persists.",
1302 /* 0x3a */
1303 "W: The tape drive has reset itself due to a detected firmware\n"
1304 " fault. If problem persists, call the supplier help line.",
1305 };
1306
1307 const char * scsiTapeAlertsTapeDevice(unsigned short code)
1308 {
1309 const int num = sizeof(TapeAlertsMessageTable) /
1310 sizeof(TapeAlertsMessageTable[0]);
1311
1312 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
1313 }
1314
1315 // The first character (W, C, I) tells the severity
1316 static const char * ChangerTapeAlertsMessageTable[]= {
1317 " ",
1318 /* 0x01 */
1319 "C: The library mechanism is having difficulty communicating with the\n"
1320 " drive:\n"
1321 " 1. Turn the library off then on.\n"
1322 " 2. Restart the operation.\n"
1323 " 3. If the problem persists, call the library supplier help line.",
1324 /* 0x02 */
1325 "W: There is a problem with the library mechanism. If problem persists,\n"
1326 " call the library supplier help line.",
1327 /* 0x03 */
1328 "C: The library has a hardware fault:\n"
1329 " 1. Reset the library.\n"
1330 " 2. Restart the operation.\n"
1331 " Check the library users manual for device specific instructions on resetting\n"
1332 " the device.",
1333 /* 0x04 */
1334 "C: The library has a hardware fault:\n"
1335 " 1. Turn the library off then on again.\n"
1336 " 2. Restart the operation.\n"
1337 " 3. If the problem persists, call the library supplier help line.\n"
1338 " Check the library users manual for device specific instructions on turning the\n"
1339 " device power on and off.",
1340 /* 0x05 */
1341 "W: The library mechanism may have a hardware fault.\n"
1342 " Run extended diagnostics to verify and diagnose the problem. Check the library\n"
1343 " users manual for device specific instructions on running extended diagnostic\n"
1344 " tests.",
1345 /* 0x06 */
1346 "C: The library has a problem with the host interface:\n"
1347 " 1. Check the cables and connections.\n"
1348 " 2. Restart the operation.",
1349 /* 0x07 */
1350 "W: A hardware failure of the library is predicted. Call the library\n"
1351 " supplier help line.",
1352 /* 0x08 */
1353 "W: Preventive maintenance of the library is required.\n"
1354 " Check the library users manual for device specific preventative maintenance\n"
1355 " tasks, or call your library supplier help line.",
1356 /* 0x09 */
1357 "C: General environmental conditions inside the library are outside the\n"
1358 " specified humidity range.",
1359 /* 0x0a */
1360 "C: General environmental conditions inside the library are outside the\n"
1361 " specified temperature range.",
1362 /* 0x0b */
1363 "C: The voltage supply to the library is outside the specified range.\n"
1364 " There is a potential problem with the power supply or failure of\n"
1365 " a redundant power supply.",
1366 /* 0x0c */
1367 "C: A cartridge has been left inside the library by a previous hardware\n"
1368 " fault:\n"
1369 " 1. Insert an empty magazine to clear the fault.\n"
1370 " 2. If the fault does not clear, turn the library off and then on again.\n"
1371 " 3. If the problem persists, call the library supplier help line.",
1372 /* 0x0d */
1373 "W: There is a potential problem with the drive ejecting cartridges or\n"
1374 " with the library mechanism picking a cartridge from a slot.\n"
1375 " 1. No action needs to be taken at this time.\n"
1376 " 2. If the problem persists, call the library supplier help line.",
1377 /* 0x0e */
1378 "W: There is a potential problem with the library mechanism placing a\n"
1379 " cartridge into a slot.\n"
1380 " 1. No action needs to be taken at this time.\n"
1381 " 2. If the problem persists, call the library supplier help line.",
1382 /* 0x0f */
1383 "W: There is a potential problem with the drive or the library mechanism\n"
1384 " loading cartridges, or an incompatible cartridge.",
1385 /* 0x10 */
1386 "C: The library has failed because the door is open:\n"
1387 " 1. Clear any obstructions from the library door.\n"
1388 " 2. Close the library door.\n"
1389 " 3. If the problem persists, call the library supplier help line.",
1390 /* 0x11 */
1391 "C: There is a mechanical problem with the library media import/export\n"
1392 " mailslot.",
1393 /* 0x12 */
1394 "C: The library cannot operate without the magazine.\n"
1395 " 1. Insert the magazine into the library.\n"
1396 " 2. Restart the operation.",
1397 /* 0x13 */
1398 "W: Library security has been compromised.",
1399 /* 0x14 */
1400 "I: The library security mode has been changed.\n"
1401 " The library has either been put into secure mode, or the library has exited\n"
1402 " the secure mode.\n"
1403 " This is for information purposes only. No action is required.",
1404 /* 0x15 */
1405 "I: The library has been manually turned offline and is unavailable for use.",
1406 /* 0x16 */
1407 "I: A drive inside the library has been taken offline.\n"
1408 " This is for information purposes only. No action is required.",
1409 /* 0x17 */
1410 "W: There is a potential problem with the bar code label or the scanner\n"
1411 " hardware in the library mechanism.\n"
1412 " 1. No action needs to be taken at this time.\n"
1413 " 2. If the problem persists, call the library supplier help line.",
1414 /* 0x18 */
1415 "C: The library has detected an inconsistency in its inventory.\n"
1416 " 1. Redo the library inventory to correct inconsistency.\n"
1417 " 2. Restart the operation.\n"
1418 " Check the applications users manual or the hardware users manual for\n"
1419 " specific instructions on redoing the library inventory.",
1420 /* 0x19 */
1421 "W: A library operation has been attempted that is invalid at this time.",
1422 /* 0x1a */
1423 "W: A redundant interface port on the library has failed.",
1424 /* 0x1b */
1425 "W: A library cooling fan has failed.",
1426 /* 0x1c */
1427 "W: A redundant power supply has failed inside the library. Check the\n"
1428 " library users manual for instructions on replacing the failed power supply.",
1429 /* 0x1d */
1430 "W: The library power consumption is outside the specified range.",
1431 /* 0x1e */
1432 "C: A failure has occurred in the cartridge pass-through mechanism between\n"
1433 " two library modules.",
1434 /* 0x1f */
1435 "C: A cartridge has been left in the pass-through mechanism from a\n"
1436 " previous hardware fault. Check the library users guide for instructions on\n"
1437 " clearing this fault.",
1438 /* 0x20 */
1439 "I: The library was unable to read the bar code on a cartridge.",
1440 };
1441
1442 const char * scsiTapeAlertsChangerDevice(unsigned short code)
1443 {
1444 const int num = sizeof(ChangerTapeAlertsMessageTable) /
1445 sizeof(ChangerTapeAlertsMessageTable[0]);
1446
1447 return (code < num) ? ChangerTapeAlertsMessageTable[code] : "Unknown Alert";
1448 }
1449
1450
1451 /* this is a subset of the SCSI additional sense code strings indexed
1452 * by "ascq" for the case when asc==SCSI_ASC_IMPENDING_FAILURE (0x5d)
1453 */
1454 static const char * strs_for_asc_5d[] = {
1455 /* 0x00 */ "FAILURE PREDICTION THRESHOLD EXCEEDED",
1456 "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED",
1457 "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED",
1458 "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED",
1459 "",
1460 "",
1461 "",
1462 "",
1463 "",
1464 "",
1465 "",
1466 "",
1467 "",
1468 "",
1469 "",
1470 "",
1471 /* 0x10 */ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1472 "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1473 "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1474 "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1475 "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1476 "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1477 "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1478 "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
1479 "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED",
1480 "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1481 "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
1482 "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
1483 "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1484 "",
1485 "",
1486 "",
1487 /* 0x20 */ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1488 "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1489 "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1490 "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1491 "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1492 "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1493 "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1494 "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS",
1495 "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED",
1496 "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1497 "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE",
1498 "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT",
1499 "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1500 "",
1501 "",
1502 "",
1503 /* 0x30 */ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1504 "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1505 "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1506 "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1507 "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1508 "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1509 "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1510 "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS",
1511 "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED",
1512 "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1513 "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE",
1514 "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT",
1515 "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1516 "",
1517 "",
1518 "",
1519 /* 0x40 */ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1520 "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1521 "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1522 "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1523 "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1524 "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1525 "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1526 "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS",
1527 "SERVO IMPENDING FAILURE CONTROLLER DETECTED",
1528 "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1529 "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE",
1530 "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT",
1531 "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1532 "",
1533 "",
1534 "",
1535 /* 0x50 */ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1536 "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1537 "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1538 "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1539 "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1540 "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1541 "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1542 "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS",
1543 "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED",
1544 "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1545 "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE",
1546 "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT",
1547 "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1548 "",
1549 "",
1550 "",
1551 /* 0x60 */ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1552 "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1553 "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1554 "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1555 "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1556 "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1557 "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1558 "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
1559 "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED",
1560 "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1561 "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
1562 "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
1563 /* 0x6c */ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"};
1564
1565
1566 /* this is a subset of the SCSI additional sense code strings indexed
1567 * * by "ascq" for the case when asc==SCSI_ASC_WARNING (0xb)
1568 * */
1569 static const char * strs_for_asc_b[] = {
1570 /* 0x00 */ "WARNING",
1571 "WARNING - SPECIFIED TEMPERATURE EXCEEDED",
1572 "WARNING - ENCLOSURE DEGRADED"};
1573
1574 static char spare_buff[128];
1575
1576 const char * scsiGetIEString(UINT8 asc, UINT8 ascq)
1577 {
1578 const char * rp;
1579
1580 if (SCSI_ASC_IMPENDING_FAILURE == asc) {
1581 if (ascq == 0xff)
1582 return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
1583 else if (ascq <
1584 (sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) {
1585 rp = strs_for_asc_5d[ascq];
1586 if (strlen(rp) > 0)
1587 return rp;
1588 }
1589 snprintf(spare_buff, sizeof(spare_buff),
1590 "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq);
1591 return spare_buff;
1592 } else if (SCSI_ASC_WARNING == asc) {
1593 if (ascq < (sizeof(strs_for_asc_b) / sizeof(strs_for_asc_b[0]))) {
1594 rp = strs_for_asc_b[ascq];
1595 if (strlen(rp) > 0)
1596 return rp;
1597 }
1598 snprintf(spare_buff, sizeof(spare_buff), "WARNING: ascq=0x%x", ascq);
1599 return spare_buff;
1600 }
1601 return NULL; /* not a IE additional sense code */
1602 }
1603
1604
1605 /* This is not documented in t10.org, page 0x80 is vendor specific */
1606 /* Some IBM disks do an offline read-scan when they get this command. */
1607 int scsiSmartIBMOfflineTest(int device)
1608 {
1609 UINT8 tBuf[256];
1610 int res;
1611
1612 memset(tBuf, 0, sizeof(tBuf));
1613 /* Build SMART Off-line Immediate Diag Header */
1614 tBuf[0] = 0x80; /* Page Code */
1615 tBuf[1] = 0x00; /* Reserved */
1616 tBuf[2] = 0x00; /* Page Length MSB */
1617 tBuf[3] = 0x04; /* Page Length LSB */
1618 tBuf[4] = 0x03; /* SMART Revision */
1619 tBuf[5] = 0x00; /* Reserved */
1620 tBuf[6] = 0x00; /* Off-line Immediate Time MSB */
1621 tBuf[7] = 0x00; /* Off-line Immediate Time LSB */
1622 res = scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8);
1623 if (res)
1624 pout("IBM offline test failed [%s]\n", scsiErrString(res));
1625 return res;
1626 }
1627
1628 int scsiSmartDefaultSelfTest(int device)
1629 {
1630 int res;
1631
1632 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0);
1633 if (res)
1634 pout("Default self test failed [%s]\n", scsiErrString(res));
1635 return res;
1636 }
1637
1638 int scsiSmartShortSelfTest(int device)
1639 {
1640 int res;
1641
1642 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0);
1643 if (res)
1644 pout("Short offline self test failed [%s]\n", scsiErrString(res));
1645 return res;
1646 }
1647
1648 int scsiSmartExtendSelfTest(int device)
1649 {
1650 int res;
1651
1652 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0);
1653 if (res)
1654 pout("Long (extended) offline self test failed [%s]\n",
1655 scsiErrString(res));
1656 return res;
1657 }
1658
1659 int scsiSmartShortCapSelfTest(int device)
1660 {
1661 int res;
1662
1663 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0);
1664 if (res)
1665 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
1666 return res;
1667 }
1668
1669 int scsiSmartExtendCapSelfTest(int device)
1670 {
1671 int res;
1672
1673 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0);
1674 if (res)
1675 pout("Long (extended) foreground self test failed [%s]\n",
1676 scsiErrString(res));
1677 return res;
1678 }
1679
1680 int scsiSmartSelfTestAbort(int device)
1681 {
1682 int res;
1683
1684 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0);
1685 if (res)
1686 pout("Abort self test failed [%s]\n", scsiErrString(res));
1687 return res;
1688 }
1689
1690 /* Returns 0 and the expected duration of an extended self test (in seconds)
1691 if successful; any other return value indicates a failure. */
1692 int scsiFetchExtendedSelfTestTime(int device, int * durationSec, int modese_len)
1693 {
1694 int err, offset, res;
1695 UINT8 buff[64];
1696
1697 memset(buff, 0, sizeof(buff));
1698 if (modese_len <= 6) {
1699 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE,
1700 MPAGE_CONTROL_CURRENT,
1701 buff, sizeof(buff)))) {
1702 if (SIMPLE_ERR_BAD_OPCODE == err)
1703 modese_len = 10;
1704 else
1705 return err;
1706 } else if (0 == modese_len)
1707 modese_len = 6;
1708 }
1709 if (10 == modese_len) {
1710 err = scsiModeSense10(device, CONTROL_MODE_PAGE,
1711 MPAGE_CONTROL_CURRENT,
1712 buff, sizeof(buff));
1713 if (err)
1714 return err;
1715 }
1716 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
1717 if (offset < 0)
1718 return -EINVAL;
1719 if (buff[offset + 1] >= 0xa) {
1720 res = (buff[offset + 10] << 8) | buff[offset + 11];
1721 *durationSec = res;
1722 return 0;
1723 }
1724 else
1725 return -EINVAL;
1726 }
1727
1728 void scsiDecodeErrCounterPage(unsigned char * resp,
1729 struct scsiErrorCounter *ecp)
1730 {
1731 int k, j, num, pl, pc;
1732 unsigned char * ucp;
1733 unsigned char * xp;
1734 uint64_t * ullp;
1735
1736 memset(ecp, 0, sizeof(*ecp));
1737 num = (resp[2] << 8) | resp[3];
1738 ucp = &resp[0] + 4;
1739 while (num > 3) {
1740 pc = (ucp[0] << 8) | ucp[1];
1741 pl = ucp[3] + 4;
1742 switch (pc) {
1743 case 0:
1744 case 1:
1745 case 2:
1746 case 3:
1747 case 4:
1748 case 5:
1749 case 6:
1750 ecp->gotPC[pc] = 1;
1751 ullp = &ecp->counter[pc];
1752 break;
1753 default:
1754 ecp->gotExtraPC = 1;
1755 ullp = &ecp->counter[7];
1756 break;
1757 }
1758 k = pl - 4;
1759 xp = ucp + 4;
1760 if (k > (int)sizeof(*ullp)) {
1761 xp += (k - sizeof(*ullp));
1762 k = sizeof(*ullp);
1763 }
1764 *ullp = 0;
1765 for (j = 0; j < k; ++j) {
1766 if (j > 0)
1767 *ullp <<= 8;
1768 *ullp |= xp[j];
1769 }
1770 num -= pl;
1771 ucp += pl;
1772 }
1773 }
1774
1775 void scsiDecodeNonMediumErrPage(unsigned char *resp,
1776 struct scsiNonMediumError *nmep)
1777 {
1778 int k, j, num, pl, pc, szof;
1779 unsigned char * ucp;
1780 unsigned char * xp;
1781
1782 memset(nmep, 0, sizeof(*nmep));
1783 num = (resp[2] << 8) | resp[3];
1784 ucp = &resp[0] + 4;
1785 szof = sizeof(nmep->counterPC0);
1786 while (num > 3) {
1787 pc = (ucp[0] << 8) | ucp[1];
1788 pl = ucp[3] + 4;
1789 switch (pc) {
1790 case 0:
1791 nmep->gotPC0 = 1;
1792 k = pl - 4;
1793 xp = ucp + 4;
1794 if (k > szof) {
1795 xp += (k - szof);
1796 k = szof;
1797 }
1798 nmep->counterPC0 = 0;
1799 for (j = 0; j < k; ++j) {
1800 if (j > 0)
1801 nmep->counterPC0 <<= 8;
1802 nmep->counterPC0 |= xp[j];
1803 }
1804 break;
1805 case 0x8009:
1806 nmep->gotTFE_H = 1;
1807 k = pl - 4;
1808 xp = ucp + 4;
1809 if (k > szof) {
1810 xp += (k - szof);
1811 k = szof;
1812 }
1813 nmep->counterTFE_H = 0;
1814 for (j = 0; j < k; ++j) {
1815 if (j > 0)
1816 nmep->counterTFE_H <<= 8;
1817 nmep->counterTFE_H |= xp[j];
1818 }
1819 break;
1820 case 0x8015:
1821 nmep->gotPE_H = 1;
1822 k = pl - 4;
1823 xp = ucp + 4;
1824 if (k > szof) {
1825 xp += (k - szof);
1826 k = szof;
1827 }
1828 nmep->counterPE_H = 0;
1829 for (j = 0; j < k; ++j) {
1830 if (j > 0)
1831 nmep->counterPE_H <<= 8;
1832 nmep->counterPE_H |= xp[j];
1833 }
1834 break;
1835 default:
1836 nmep->gotExtraPC = 1;
1837 break;
1838 }
1839 num -= pl;
1840 ucp += pl;
1841 }
1842 }
1843
1844 /* Counts number of failed self-tests. Also encodes the poweron_hour
1845 of the most recent failed self-test. Return value is negative if
1846 this function has a problem (typically -1), otherwise the bottom 8
1847 bits are the number of failed self tests and the 16 bits above that
1848 are the poweron hour of the most recent failure. Note: aborted self
1849 tests (typically by the user) and self tests in progress are not
1850 considered failures. See Working Draft SCSI Primary Commands - 3
1851 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
1852 int scsiCountFailedSelfTests(int fd, int noisy)
1853 {
1854 int num, k, n, err, res, fails, fail_hour;
1855 UINT8 * ucp;
1856 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
1857
1858 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, resp,
1859 LOG_RESP_SELF_TEST_LEN, 0))) {
1860 if (noisy)
1861 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
1862 return -1;
1863 }
1864 if (resp[0] != SELFTEST_RESULTS_LPAGE) {
1865 if (noisy)
1866 pout("Self-test Log Sense Failed, page mismatch\n");
1867 return -1;
1868 }
1869 // compute page length
1870 num = (resp[2] << 8) + resp[3];
1871 // Log sense page length 0x190 bytes
1872 if (num != 0x190) {
1873 if (noisy)
1874 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n", num);
1875 return -1;
1876 }
1877 fails = 0;
1878 fail_hour = 0;
1879 // loop through the twenty possible entries
1880 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
1881
1882 // timestamp in power-on hours (or zero if test in progress)
1883 n = (ucp[6] << 8) | ucp[7];
1884
1885 // The spec says "all 20 bytes will be zero if no test" but
1886 // DG has found otherwise. So this is a heuristic.
1887 if ((0 == n) && (0 == ucp[4]))
1888 break;
1889 res = ucp[4] & 0xf;
1890 if ((res > 2) && (res < 8)) {
1891 fails++;
1892 if (1 == fails)
1893 fail_hour = (ucp[6] << 8) + ucp[7];
1894 }
1895 }
1896 return (fail_hour << 8) + fails;
1897 }
1898
1899 /* Returns 0 if able to read self test log page; then outputs 1 into
1900 *inProgress if self test still in progress, else outputs 0. */
1901 int scsiSelfTestInProgress(int fd, int * inProgress)
1902 {
1903 int num;
1904 UINT8 * ucp;
1905 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
1906
1907 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, resp,
1908 LOG_RESP_SELF_TEST_LEN, 0))
1909 return -1;
1910 if (resp[0] != SELFTEST_RESULTS_LPAGE)
1911 return -1;
1912 // compute page length
1913 num = (resp[2] << 8) + resp[3];
1914 // Log sense page length 0x190 bytes
1915 if (num != 0x190) {
1916 return -1;
1917 }
1918 ucp = resp + 4;
1919 if (inProgress)
1920 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
1921 return 0;
1922 }
1923
1924 /* Returns a negative value if failed to fetch Contol mode page or it was
1925 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
1926 bit is set. Examines default mode page when current==0 else examines
1927 current mode page. */
1928 int scsiFetchControlGLTSD(int device, int modese_len, int current)
1929 {
1930 int err, offset;
1931 UINT8 buff[64];
1932 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
1933
1934 memset(buff, 0, sizeof(buff));
1935 if (modese_len <= 6) {
1936 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, pc,
1937 buff, sizeof(buff)))) {
1938 if (SIMPLE_ERR_BAD_OPCODE == err)
1939 modese_len = 10;
1940 else
1941 return -EINVAL;
1942 } else if (0 == modese_len)
1943 modese_len = 6;
1944 }
1945 if (10 == modese_len) {
1946 err = scsiModeSense10(device, CONTROL_MODE_PAGE, pc,
1947 buff, sizeof(buff));
1948 if (err)
1949 return -EINVAL;
1950 }
1951 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
1952 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
1953 return (buff[offset + 2] & 2) ? 1 : 0;
1954 return -EINVAL;
1955 }
1956
1957 /* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
1958 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
1959 successful, negative if low level error, > 0 if higher level error (e.g.
1960 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
1961 int scsiSetControlGLTSD(int device, int enabled, int modese_len)
1962 {
1963 int err, offset, resp_len, sp;
1964 UINT8 buff[64];
1965 UINT8 ch_buff[64];
1966
1967 memset(buff, 0, sizeof(buff));
1968 if (modese_len <= 6) {
1969 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE,
1970 MPAGE_CONTROL_CURRENT,
1971 buff, sizeof(buff)))) {
1972 if (SIMPLE_ERR_BAD_OPCODE == err)
1973 modese_len = 10;
1974 else
1975 return err;
1976 } else if (0 == modese_len)
1977 modese_len = 6;
1978 }
1979 if (10 == modese_len) {
1980 err = scsiModeSense10(device, CONTROL_MODE_PAGE,
1981 MPAGE_CONTROL_CURRENT,
1982 buff, sizeof(buff));
1983 if (err)
1984 return err;
1985 }
1986 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
1987 if ((offset < 0) || (buff[offset + 1] < 0xa))
1988 return SIMPLE_ERR_BAD_RESP;
1989
1990 if (enabled)
1991 enabled = 2;
1992 if (enabled == (buff[offset + 2] & 2))
1993 return 0; /* GLTSD already in wanted state so nothing to do */
1994
1995 if (modese_len == 6)
1996 err = scsiModeSense(device, CONTROL_MODE_PAGE,
1997 MPAGE_CONTROL_CHANGEABLE,
1998 ch_buff, sizeof(ch_buff));
1999 else
2000 err = scsiModeSense10(device, CONTROL_MODE_PAGE,
2001 MPAGE_CONTROL_CHANGEABLE,
2002 ch_buff, sizeof(ch_buff));
2003 if (err)
2004 return err;
2005 if (0 == (ch_buff[offset + 2] & 2))
2006 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not chageable */
2007
2008 if (10 == modese_len) {
2009 resp_len = (buff[0] << 8) + buff[1] + 2;
2010 buff[3] &= 0xef; /* for disks mask out DPOFUA bit */
2011 } else {
2012 resp_len = buff[0] + 1;
2013 buff[2] &= 0xef; /* for disks mask out DPOFUA bit */
2014 }
2015 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
2016 if (enabled)
2017 buff[offset + 2] |= 0x2; /* set GLTSD bit */
2018 else
2019 buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
2020 if (10 == modese_len)
2021 err = scsiModeSelect10(device, sp, buff, resp_len);
2022 else if (6 == modese_len)
2023 err = scsiModeSelect(device, sp, buff, resp_len);
2024 return err;
2025 }
2026
2027 /* Returns a negative value if failed to fetch Protocol specific port mode
2028 page or it was malformed. Returns transport protocol identifier when
2029 value >= 0 . */
2030 int scsiFetchTransportProtocol(int device, int modese_len)
2031 {
2032 int err, offset;
2033 UINT8 buff[64];
2034
2035 memset(buff, 0, sizeof(buff));
2036 if (modese_len <= 6) {
2037 if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE,
2038 MPAGE_CONTROL_CURRENT,
2039 buff, sizeof(buff)))) {
2040 if (SIMPLE_ERR_BAD_OPCODE == err)
2041 modese_len = 10;
2042 else
2043 return -EINVAL;
2044 } else if (0 == modese_len)
2045 modese_len = 6;
2046 }
2047 if (10 == modese_len) {
2048 err = scsiModeSense10(device, PROTOCOL_SPECIFIC_PORT_PAGE,
2049 MPAGE_CONTROL_CURRENT,
2050 buff, sizeof(buff));
2051 if (err)
2052 return -EINVAL;
2053 }
2054 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2055 if ((offset >= 0) && (buff[offset + 1] > 1)) {
2056 if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
2057 (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
2058 return (buff[offset + 2] & 0xf);
2059 }
2060 return -EINVAL;
2061 }
2062
2063
2064 /* This is Linux specific code to look for the libata ATA-SCSI
2065 simulator in the vendor device identification page.
2066 Returns 1 if found else 0. */
2067 int isLinuxLibAta(unsigned char * vpd_di_buff, int len)
2068 {
2069 int k, id_len, c_set, assoc, id_type, i_len;
2070 unsigned char * ucp;
2071 unsigned char * ip;
2072
2073 if (len < 4) {
2074 /* Device identification VPD page length too short */
2075 return 0;
2076 }
2077 len -= 4;
2078 ucp = vpd_di_buff + 4;
2079 for (k = 0; k < len; k += id_len, ucp += id_len) {
2080 i_len = ucp[3];
2081 id_len = i_len + 4;
2082 if ((k + id_len) > len) {
2083 /* short descriptor, badly formed */
2084 return 0;
2085 }
2086 ip = ucp + 4;
2087 c_set = (ucp[0] & 0xf);
2088 assoc = ((ucp[1] >> 4) & 0x3);
2089 id_type = (ucp[1] & 0xf);
2090 if ((0 == id_type) && (2 == c_set) && (0 == assoc) &&
2091 (0 == strncmp((const char *)ip,
2092 "Linux ATA-SCSI simulator", i_len))) {
2093 return 1;
2094 }
2095 }
2096 return 0;
2097 }