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