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