Print this page
NEX-17999 SCSI enclosure services (ses) non-response causes device tree operation deadlock
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
+++ new/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #pragma ident "%Z%%M% %I% %E% SMI"
28 28
29 29 /*
30 30 * This file contains routines for sending and receiving SCSI commands. The
31 31 * higher level logic is contained in ds_scsi.c.
32 32 */
33 33
34 34 #include <assert.h>
35 35 #include <sys/types.h>
36 36 #include <sys/param.h>
37 37 #include <inttypes.h>
38 38 #include <stdio.h>
39 39 #include <stdlib.h>
40 40 #include <string.h>
41 41 #include <errno.h>
42 42 #include <stdarg.h>
43 43 #include <limits.h>
44 44 #include <utility.h>
45 45 #include <unistd.h>
46 46 #include <stropts.h>
47 47 #include <alloca.h>
48 48
49 49 #include "ds_scsi.h"
50 50 #include "ds_scsi_uscsi.h"
51 51
52 52 #define MSGBUFLEN 64
53 53 #define USCSI_DEFAULT_TIMEOUT 45
54 54 #define USCSI_TIMEOUT_MAX INT_MAX
55 55
56 56 static diskaddr_t scsi_extract_sense_info_descr(
57 57 struct scsi_descr_sense_hdr *sdsp, int rqlen);
58 58 static void scsi_print_extended_sense(struct scsi_extended_sense *rq,
59 59 int rqlen);
60 60 static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *rq, int rqlen);
61 61
62 62 typedef struct slist {
63 63 char *str;
64 64 int value;
65 65 } slist_t;
66 66
67 67 static char *
68 68 find_string(slist_t *slist, int match_value)
69 69 {
70 70 for (; slist->str != NULL; slist++) {
71 71 if (slist->value == match_value) {
72 72 return (slist->str);
73 73 }
74 74 }
75 75
76 76 return ((char *)NULL);
77 77 }
78 78
79 79 /*
80 80 * Strings for printing mode sense page control values
81 81 */
82 82 static slist_t page_control_strings[] = {
83 83 { "current", PC_CURRENT },
84 84 { "changeable", PC_CHANGEABLE },
85 85 { "default", PC_DEFAULT },
86 86 { "saved", PC_SAVED },
87 87 { NULL, 0 }
88 88 };
89 89
90 90 /*
91 91 * Strings for printing the mode select options
92 92 */
93 93 static slist_t mode_select_strings[] = {
94 94 { "", 0 },
95 95 { "(pf)", MODE_SELECT_PF },
96 96 { "(sp)", MODE_SELECT_SP },
97 97 { "(pf,sp)", MODE_SELECT_PF|MODE_SELECT_SP },
98 98 { NULL, 0 }
99 99 };
100 100
101 101 static slist_t sensekey_strings[] = {
102 102 { "No sense error", KEY_NO_SENSE },
103 103 { "Recoverable error", KEY_RECOVERABLE_ERROR },
104 104 { "Not ready error", KEY_NOT_READY },
105 105 { "Medium error", KEY_MEDIUM_ERROR },
106 106 { "Hardware error", KEY_HARDWARE_ERROR },
107 107 { "Illegal request", KEY_ILLEGAL_REQUEST },
108 108 { "Unit attention error", KEY_UNIT_ATTENTION },
109 109 { "Write protect error", KEY_WRITE_PROTECT },
110 110 { "Blank check error", KEY_BLANK_CHECK },
111 111 { "Vendor unique error", KEY_VENDOR_UNIQUE },
112 112 { "Copy aborted error", KEY_COPY_ABORTED },
113 113 { "Aborted command", KEY_ABORTED_COMMAND },
114 114 { "Equal error", KEY_EQUAL },
115 115 { "Volume overflow", KEY_VOLUME_OVERFLOW },
116 116 { "Miscompare error", KEY_MISCOMPARE },
117 117 { "Reserved error", KEY_RESERVED },
118 118 { NULL, 0 }
119 119 };
120 120
121 121 static slist_t scsi_cmdname_strings[] = {
122 122 { "mode select", SCMD_MODE_SELECT },
123 123 { "mode sense", SCMD_MODE_SENSE },
124 124 { "mode select(10)", SCMD_MODE_SELECT_G1 },
125 125 { "mode sense(10)", SCMD_MODE_SENSE_G1 },
126 126 { "log sense", SCMD_LOG_SENSE_G1 },
127 127 { "request sense", SCMD_REQUEST_SENSE },
128 128 { NULL, 0 }
129 129 };
130 130
131 131 static struct _scsi_asq_key_strings {
132 132 uint_t asc;
133 133 uint_t ascq;
134 134 const char *message;
135 135 } extended_sense_list[] = {
136 136 { 0x00, 0x00, "no additional sense info" },
137 137 { 0x00, 0x01, "filemark detected" },
138 138 { 0x00, 0x02, "end of partition/medium detected" },
139 139 { 0x00, 0x03, "setmark detected" },
140 140 { 0x00, 0x04, "begining of partition/medium detected" },
141 141 { 0x00, 0x05, "end of data detected" },
142 142 { 0x00, 0x06, "i/o process terminated" },
143 143 { 0x00, 0x11, "audio play operation in progress" },
144 144 { 0x00, 0x12, "audio play operation paused" },
145 145 { 0x00, 0x13, "audio play operation successfully completed" },
146 146 { 0x00, 0x14, "audio play operation stopped due to error" },
147 147 { 0x00, 0x15, "no current audio status to return" },
148 148 { 0x00, 0x16, "operation in progress" },
149 149 { 0x00, 0x17, "cleaning requested" },
150 150 { 0x00, 0x18, "erase operation in progress" },
151 151 { 0x00, 0x19, "locate operation in progress" },
152 152 { 0x00, 0x1A, "rewind operation in progress" },
153 153 { 0x00, 0x1B, "set capacity operation in progress" },
154 154 { 0x00, 0x1C, "verify operation in progress" },
155 155 { 0x01, 0x00, "no index/sector signal" },
156 156 { 0x02, 0x00, "no seek complete" },
157 157 { 0x03, 0x00, "peripheral device write fault" },
158 158 { 0x03, 0x01, "no write current" },
159 159 { 0x03, 0x02, "excessive write errors" },
160 160 { 0x04, 0x00, "LUN not ready" },
161 161 { 0x04, 0x01, "LUN is becoming ready" },
162 162 { 0x04, 0x02, "LUN initializing command required" },
163 163 { 0x04, 0x03, "LUN not ready intervention required" },
164 164 { 0x04, 0x04, "LUN not ready format in progress" },
165 165 { 0x04, 0x05, "LUN not ready, rebuild in progress" },
166 166 { 0x04, 0x06, "LUN not ready, recalculation in progress" },
167 167 { 0x04, 0x07, "LUN not ready, operation in progress" },
168 168 { 0x04, 0x08, "LUN not ready, long write in progress" },
169 169 { 0x04, 0x09, "LUN not ready, self-test in progress" },
170 170 { 0x04, 0x0A, "LUN not accessible, asymmetric access state "
171 171 "transition" },
172 172 { 0x04, 0x0B, "LUN not accessible, target port in standby state" },
173 173 { 0x04, 0x0C, "LUN not accessible, target port in unavailable state" },
174 174 { 0x04, 0x10, "LUN not ready, auxiliary memory not accessible" },
175 175 { 0x05, 0x00, "LUN does not respond to selection" },
176 176 { 0x06, 0x00, "reference position found" },
177 177 { 0x07, 0x00, "multiple peripheral devices selected" },
178 178 { 0x08, 0x00, "LUN communication failure" },
179 179 { 0x08, 0x01, "LUN communication time-out" },
180 180 { 0x08, 0x02, "LUN communication parity error" },
181 181 { 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)" },
182 182 { 0x08, 0x04, "unreachable copy target" },
183 183 { 0x09, 0x00, "track following error" },
184 184 { 0x09, 0x01, "tracking servo failure" },
185 185 { 0x09, 0x02, "focus servo failure" },
186 186 { 0x09, 0x03, "spindle servo failure" },
187 187 { 0x09, 0x04, "head select fault" },
188 188 { 0x0a, 0x00, "error log overflow" },
189 189 { 0x0b, 0x00, "warning" },
190 190 { 0x0b, 0x01, "warning - specified temperature exceeded" },
191 191 { 0x0b, 0x02, "warning - enclosure degraded" },
192 192 { 0x0c, 0x00, "write error" },
193 193 { 0x0c, 0x01, "write error - recovered with auto reallocation" },
194 194 { 0x0c, 0x02, "write error - auto reallocation failed" },
195 195 { 0x0c, 0x03, "write error - recommend reassignment" },
196 196 { 0x0c, 0x04, "compression check miscompare error" },
197 197 { 0x0c, 0x05, "data expansion occurred during compression" },
198 198 { 0x0c, 0x06, "block not compressible" },
199 199 { 0x0c, 0x07, "write error - recovery needed" },
200 200 { 0x0c, 0x08, "write error - recovery failed" },
201 201 { 0x0c, 0x09, "write error - loss of streaming" },
202 202 { 0x0c, 0x0a, "write error - padding blocks added" },
203 203 { 0x0c, 0x0b, "auxiliary memory write error" },
204 204 { 0x0c, 0x0c, "write error - unexpected unsolicited data" },
205 205 { 0x0c, 0x0d, "write error - not enough unsolicited data" },
206 206 { 0x0d, 0x00, "error detected by third party temporary initiator" },
207 207 { 0x0d, 0x01, "third party device failure" },
208 208 { 0x0d, 0x02, "copy target device not reachable" },
209 209 { 0x0d, 0x03, "incorrect copy target device type" },
210 210 { 0x0d, 0x04, "copy target device data underrun" },
211 211 { 0x0d, 0x05, "copy target device data overrun" },
212 212 { 0x0e, 0x00, "invalid information unit" },
213 213 { 0x0e, 0x01, "information unit too short" },
214 214 { 0x0e, 0x02, "information unit too long" },
215 215 { 0x10, 0x00, "ID CRC or ECC error" },
216 216 { 0x11, 0x00, "unrecovered read error" },
217 217 { 0x11, 0x01, "read retries exhausted" },
218 218 { 0x11, 0x02, "error too long to correct" },
219 219 { 0x11, 0x03, "multiple read errors" },
220 220 { 0x11, 0x04, "unrecovered read error - auto reallocate failed" },
221 221 { 0x11, 0x05, "L-EC uncorrectable error" },
222 222 { 0x11, 0x06, "CIRC unrecovered error" },
223 223 { 0x11, 0x07, "data re-synchronization error" },
224 224 { 0x11, 0x08, "incomplete block read" },
225 225 { 0x11, 0x09, "no gap found" },
226 226 { 0x11, 0x0a, "miscorrected error" },
227 227 { 0x11, 0x0b, "unrecovered read error - recommend reassignment" },
228 228 { 0x11, 0x0c, "unrecovered read error - recommend rewrite the data" },
229 229 { 0x11, 0x0d, "de-compression crc error" },
230 230 { 0x11, 0x0e, "cannot decompress using declared algorithm" },
231 231 { 0x11, 0x0f, "error reading UPC/EAN number" },
232 232 { 0x11, 0x10, "error reading ISRC number" },
233 233 { 0x11, 0x11, "read error - loss of streaming" },
234 234 { 0x11, 0x12, "auxiliary memory read error" },
235 235 { 0x11, 0x13, "read error - failed retransmission request" },
236 236 { 0x12, 0x00, "address mark not found for ID field" },
237 237 { 0x13, 0x00, "address mark not found for data field" },
238 238 { 0x14, 0x00, "recorded entity not found" },
239 239 { 0x14, 0x01, "record not found" },
240 240 { 0x14, 0x02, "filemark or setmark not found" },
241 241 { 0x14, 0x03, "end-of-data not found" },
242 242 { 0x14, 0x04, "block sequence error" },
243 243 { 0x14, 0x05, "record not found - recommend reassignment" },
244 244 { 0x14, 0x06, "record not found - data auto-reallocated" },
245 245 { 0x14, 0x07, "locate operation failure" },
246 246 { 0x15, 0x00, "random positioning error" },
247 247 { 0x15, 0x01, "mechanical positioning error" },
248 248 { 0x15, 0x02, "positioning error detected by read of medium" },
249 249 { 0x16, 0x00, "data sync mark error" },
250 250 { 0x16, 0x01, "data sync error - data rewritten" },
251 251 { 0x16, 0x02, "data sync error - recommend rewrite" },
252 252 { 0x16, 0x03, "data sync error - data auto-reallocated" },
253 253 { 0x16, 0x04, "data sync error - recommend reassignment" },
254 254 { 0x17, 0x00, "recovered data with no error correction" },
255 255 { 0x17, 0x01, "recovered data with retries" },
256 256 { 0x17, 0x02, "recovered data with positive head offset" },
257 257 { 0x17, 0x03, "recovered data with negative head offset" },
258 258 { 0x17, 0x04, "recovered data with retries and/or CIRC applied" },
259 259 { 0x17, 0x05, "recovered data using previous sector id" },
260 260 { 0x17, 0x06, "recovered data without ECC - data auto-reallocated" },
261 261 { 0x17, 0x07, "recovered data without ECC - recommend reassignment" },
262 262 { 0x17, 0x08, "recovered data without ECC - recommend rewrite" },
263 263 { 0x17, 0x09, "recovered data without ECC - data rewritten" },
264 264 { 0x18, 0x00, "recovered data with error correction" },
265 265 { 0x18, 0x01, "recovered data with error corr. & retries applied" },
266 266 { 0x18, 0x02, "recovered data - data auto-reallocated" },
267 267 { 0x18, 0x03, "recovered data with CIRC" },
268 268 { 0x18, 0x04, "recovered data with L-EC" },
269 269 { 0x18, 0x05, "recovered data - recommend reassignment" },
270 270 { 0x18, 0x06, "recovered data - recommend rewrite" },
271 271 { 0x18, 0x07, "recovered data with ECC - data rewritten" },
272 272 { 0x18, 0x08, "recovered data with linking" },
273 273 { 0x19, 0x00, "defect list error" },
274 274 { 0x1a, 0x00, "parameter list length error" },
275 275 { 0x1b, 0x00, "synchronous data xfer error" },
276 276 { 0x1c, 0x00, "defect list not found" },
277 277 { 0x1c, 0x01, "primary defect list not found" },
278 278 { 0x1c, 0x02, "grown defect list not found" },
279 279 { 0x1d, 0x00, "miscompare during verify" },
280 280 { 0x1e, 0x00, "recovered ID with ECC" },
281 281 { 0x1f, 0x00, "partial defect list transfer" },
282 282 { 0x20, 0x00, "invalid command operation code" },
283 283 { 0x20, 0x01, "access denied - initiator pending-enrolled" },
284 284 { 0x20, 0x02, "access denied - no access rights" },
285 285 { 0x20, 0x03, "access denied - invalid mgmt id key" },
286 286 { 0x20, 0x04, "illegal command while in write capable state" },
287 287 { 0x20, 0x06, "illegal command while in explicit address mode" },
288 288 { 0x20, 0x07, "illegal command while in implicit address mode" },
289 289 { 0x20, 0x08, "access denied - enrollment conflict" },
290 290 { 0x20, 0x09, "access denied - invalid lu identifier" },
291 291 { 0x20, 0x0a, "access denied - invalid proxy token" },
292 292 { 0x20, 0x0b, "access denied - ACL LUN conflict" },
293 293 { 0x21, 0x00, "logical block address out of range" },
294 294 { 0x21, 0x01, "invalid element address" },
295 295 { 0x21, 0x02, "invalid address for write" },
296 296 { 0x22, 0x00, "illegal function" },
297 297 { 0x24, 0x00, "invalid field in cdb" },
298 298 { 0x24, 0x01, "cdb decryption error" },
299 299 { 0x25, 0x00, "LUN not supported" },
300 300 { 0x26, 0x00, "invalid field in param list" },
301 301 { 0x26, 0x01, "parameter not supported" },
302 302 { 0x26, 0x02, "parameter value invalid" },
303 303 { 0x26, 0x03, "threshold parameters not supported" },
304 304 { 0x26, 0x04, "invalid release of persistent reservation" },
305 305 { 0x26, 0x05, "data decryption error" },
306 306 { 0x26, 0x06, "too many target descriptors" },
307 307 { 0x26, 0x07, "unsupported target descriptor type code" },
308 308 { 0x26, 0x08, "too many segment descriptors" },
309 309 { 0x26, 0x09, "unsupported segment descriptor type code" },
310 310 { 0x26, 0x0a, "unexpected inexact segment" },
311 311 { 0x26, 0x0b, "inline data length exceeded" },
312 312 { 0x26, 0x0c, "invalid operation for copy source or destination" },
313 313 { 0x26, 0x0d, "copy segment granularity violation" },
314 314 { 0x27, 0x00, "write protected" },
315 315 { 0x27, 0x01, "hardware write protected" },
316 316 { 0x27, 0x02, "LUN software write protected" },
317 317 { 0x27, 0x03, "associated write protect" },
318 318 { 0x27, 0x04, "persistent write protect" },
319 319 { 0x27, 0x05, "permanent write protect" },
320 320 { 0x27, 0x06, "conditional write protect" },
321 321 { 0x28, 0x00, "medium may have changed" },
322 322 { 0x28, 0x01, "import or export element accessed" },
323 323 { 0x29, 0x00, "power on, reset, or bus reset occurred" },
324 324 { 0x29, 0x01, "power on occurred" },
325 325 { 0x29, 0x02, "scsi bus reset occurred" },
326 326 { 0x29, 0x03, "bus device reset message occurred" },
327 327 { 0x29, 0x04, "device internal reset" },
328 328 { 0x29, 0x05, "transceiver mode changed to single-ended" },
329 329 { 0x29, 0x06, "transceiver mode changed to LVD" },
330 330 { 0x29, 0x07, "i_t nexus loss occurred" },
331 331 { 0x2a, 0x00, "parameters changed" },
332 332 { 0x2a, 0x01, "mode parameters changed" },
333 333 { 0x2a, 0x02, "log parameters changed" },
334 334 { 0x2a, 0x03, "reservations preempted" },
335 335 { 0x2a, 0x04, "reservations released" },
336 336 { 0x2a, 0x05, "registrations preempted" },
337 337 { 0x2a, 0x06, "asymmetric access state changed" },
338 338 { 0x2a, 0x07, "implicit asymmetric access state transition failed" },
339 339 { 0x2b, 0x00, "copy cannot execute since host cannot disconnect" },
340 340 { 0x2c, 0x00, "command sequence error" },
341 341 { 0x2c, 0x03, "current program area is not empty" },
342 342 { 0x2c, 0x04, "current program area is empty" },
343 343 { 0x2c, 0x06, "persistent prevent conflict" },
344 344 { 0x2c, 0x07, "previous busy status" },
345 345 { 0x2c, 0x08, "previous task set full status" },
346 346 { 0x2c, 0x09, "previous reservation conflict status" },
347 347 { 0x2d, 0x00, "overwrite error on update in place" },
348 348 { 0x2e, 0x00, "insufficient time for operation" },
349 349 { 0x2f, 0x00, "commands cleared by another initiator" },
350 350 { 0x30, 0x00, "incompatible medium installed" },
351 351 { 0x30, 0x01, "cannot read medium - unknown format" },
352 352 { 0x30, 0x02, "cannot read medium - incompatible format" },
353 353 { 0x30, 0x03, "cleaning cartridge installed" },
354 354 { 0x30, 0x04, "cannot write medium - unknown format" },
355 355 { 0x30, 0x05, "cannot write medium - incompatible format" },
356 356 { 0x30, 0x06, "cannot format medium - incompatible medium" },
357 357 { 0x30, 0x07, "cleaning failure" },
358 358 { 0x30, 0x08, "cannot write - application code mismatch" },
359 359 { 0x30, 0x09, "current session not fixated for append" },
360 360 { 0x30, 0x10, "medium not formatted" },
361 361 { 0x31, 0x00, "medium format corrupted" },
362 362 { 0x31, 0x01, "format command failed" },
363 363 { 0x31, 0x02, "zoned formatting failed due to spare linking" },
364 364 { 0x32, 0x00, "no defect spare location available" },
365 365 { 0x32, 0x01, "defect list update failure" },
366 366 { 0x33, 0x00, "tape length error" },
367 367 { 0x34, 0x00, "enclosure failure" },
368 368 { 0x35, 0x00, "enclosure services failure" },
369 369 { 0x35, 0x01, "unsupported enclosure function" },
370 370 { 0x35, 0x02, "enclosure services unavailable" },
371 371 { 0x35, 0x03, "enclosure services transfer failure" },
372 372 { 0x35, 0x04, "enclosure services transfer refused" },
373 373 { 0x36, 0x00, "ribbon, ink, or toner failure" },
374 374 { 0x37, 0x00, "rounded parameter" },
375 375 { 0x39, 0x00, "saving parameters not supported" },
376 376 { 0x3a, 0x00, "medium not present" },
377 377 { 0x3a, 0x01, "medium not present - tray closed" },
378 378 { 0x3a, 0x02, "medium not present - tray open" },
379 379 { 0x3a, 0x03, "medium not present - loadable" },
380 380 { 0x3a, 0x04, "medium not present - medium auxiliary memory "
381 381 "accessible" },
382 382 { 0x3b, 0x00, "sequential positioning error" },
383 383 { 0x3b, 0x01, "tape position error at beginning-of-medium" },
384 384 { 0x3b, 0x02, "tape position error at end-of-medium" },
385 385 { 0x3b, 0x08, "reposition error" },
386 386 { 0x3b, 0x0c, "position past beginning of medium" },
387 387 { 0x3b, 0x0d, "medium destination element full" },
388 388 { 0x3b, 0x0e, "medium source element empty" },
389 389 { 0x3b, 0x0f, "end of medium reached" },
390 390 { 0x3b, 0x11, "medium magazine not accessible" },
391 391 { 0x3b, 0x12, "medium magazine removed" },
392 392 { 0x3b, 0x13, "medium magazine inserted" },
393 393 { 0x3b, 0x14, "medium magazine locked" },
394 394 { 0x3b, 0x15, "medium magazine unlocked" },
395 395 { 0x3b, 0x16, "mechanical positioning or changer error" },
396 396 { 0x3d, 0x00, "invalid bits in indentify message" },
397 397 { 0x3e, 0x00, "LUN has not self-configured yet" },
398 398 { 0x3e, 0x01, "LUN failure" },
399 399 { 0x3e, 0x02, "timeout on LUN" },
400 400 { 0x3e, 0x03, "LUN failed self-test" },
401 401 { 0x3e, 0x04, "LUN unable to update self-test log" },
402 402 { 0x3f, 0x00, "target operating conditions have changed" },
403 403 { 0x3f, 0x01, "microcode has been changed" },
404 404 { 0x3f, 0x02, "changed operating definition" },
405 405 { 0x3f, 0x03, "inquiry data has changed" },
406 406 { 0x3f, 0x04, "component device attached" },
407 407 { 0x3f, 0x05, "device identifier changed" },
408 408 { 0x3f, 0x06, "redundancy group created or modified" },
409 409 { 0x3f, 0x07, "redundancy group deleted" },
410 410 { 0x3f, 0x08, "spare created or modified" },
411 411 { 0x3f, 0x09, "spare deleted" },
412 412 { 0x3f, 0x0a, "volume set created or modified" },
413 413 { 0x3f, 0x0b, "volume set deleted" },
414 414 { 0x3f, 0x0c, "volume set deassigned" },
415 415 { 0x3f, 0x0d, "volume set reassigned" },
416 416 { 0x3f, 0x0e, "reported LUNs data has changed" },
417 417 { 0x3f, 0x0f, "echo buffer overwritten" },
418 418 { 0x3f, 0x10, "medium loadable" },
419 419 { 0x3f, 0x11, "medium auxiliary memory accessible" },
420 420 { 0x40, 0x00, "ram failure" },
421 421 { 0x41, 0x00, "data path failure" },
422 422 { 0x42, 0x00, "power-on or self-test failure" },
423 423 { 0x43, 0x00, "message error" },
424 424 { 0x44, 0x00, "internal target failure" },
425 425 { 0x45, 0x00, "select or reselect failure" },
426 426 { 0x46, 0x00, "unsuccessful soft reset" },
427 427 { 0x47, 0x00, "scsi parity error" },
428 428 { 0x47, 0x01, "data phase crc error detected" },
429 429 { 0x47, 0x02, "scsi parity error detected during st data phase" },
430 430 { 0x47, 0x03, "information unit iucrc error detected" },
431 431 { 0x47, 0x04, "asynchronous information protection error detected" },
432 432 { 0x47, 0x05, "protocol service crc error" },
433 433 { 0x47, 0x7f, "some commands cleared by iscsi protocol event" },
434 434 { 0x48, 0x00, "initiator detected error message received" },
435 435 { 0x49, 0x00, "invalid message error" },
436 436 { 0x4a, 0x00, "command phase error" },
437 437 { 0x4b, 0x00, "data phase error" },
438 438 { 0x4b, 0x01, "invalid target port transfer tag received" },
439 439 { 0x4b, 0x02, "too much write data" },
440 440 { 0x4b, 0x03, "ack/nak timeout" },
441 441 { 0x4b, 0x04, "nak received" },
442 442 { 0x4b, 0x05, "data offset error" },
443 443 { 0x4c, 0x00, "logical unit failed self-configuration" },
444 444 { 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)" },
445 445 { 0x4e, 0x00, "overlapped commands attempted" },
446 446 { 0x50, 0x00, "write append error" },
447 447 { 0x51, 0x00, "erase failure" },
448 448 { 0x52, 0x00, "cartridge fault" },
449 449 { 0x53, 0x00, "media load or eject failed" },
450 450 { 0x53, 0x01, "unload tape failure" },
451 451 { 0x53, 0x02, "medium removal prevented" },
452 452 { 0x54, 0x00, "scsi to host system interface failure" },
453 453 { 0x55, 0x00, "system resource failure" },
454 454 { 0x55, 0x01, "system buffer full" },
455 455 { 0x55, 0x02, "insufficient reservation resources" },
456 456 { 0x55, 0x03, "insufficient resources" },
457 457 { 0x55, 0x04, "insufficient registration resources" },
458 458 { 0x55, 0x05, "insufficient access control resources" },
459 459 { 0x55, 0x06, "auxiliary memory out of space" },
460 460 { 0x57, 0x00, "unable to recover TOC" },
461 461 { 0x58, 0x00, "generation does not exist" },
462 462 { 0x59, 0x00, "updated block read" },
463 463 { 0x5a, 0x00, "operator request or state change input" },
464 464 { 0x5a, 0x01, "operator medium removal request" },
465 465 { 0x5a, 0x02, "operator selected write protect" },
466 466 { 0x5a, 0x03, "operator selected write permit" },
467 467 { 0x5b, 0x00, "log exception" },
468 468 { 0x5b, 0x01, "threshold condition met" },
469 469 { 0x5b, 0x02, "log counter at maximum" },
470 470 { 0x5b, 0x03, "log list codes exhausted" },
471 471 { 0x5c, 0x00, "RPL status change" },
472 472 { 0x5c, 0x01, "spindles synchronized" },
473 473 { 0x5c, 0x02, "spindles not synchronized" },
474 474 { 0x5d, 0x00, "drive operation marginal, service immediately"
475 475 " (failure prediction threshold exceeded)" },
476 476 { 0x5d, 0x01, "media failure prediction threshold exceeded" },
477 477 { 0x5d, 0x02, "LUN failure prediction threshold exceeded" },
478 478 { 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded" },
479 479 { 0x5d, 0x10, "hardware impending failure general hard drive failure" },
480 480 { 0x5d, 0x11, "hardware impending failure drive error rate too high" },
481 481 { 0x5d, 0x12, "hardware impending failure data error rate too high" },
482 482 { 0x5d, 0x13, "hardware impending failure seek error rate too high" },
483 483 { 0x5d, 0x14, "hardware impending failure too many block reassigns" },
484 484 { 0x5d, 0x15, "hardware impending failure access times too high" },
485 485 { 0x5d, 0x16, "hardware impending failure start unit times too high" },
486 486 { 0x5d, 0x17, "hardware impending failure channel parametrics" },
487 487 { 0x5d, 0x18, "hardware impending failure controller detected" },
488 488 { 0x5d, 0x19, "hardware impending failure throughput performance" },
489 489 { 0x5d, 0x1a, "hardware impending failure seek time performance" },
490 490 { 0x5d, 0x1b, "hardware impending failure spin-up retry count" },
491 491 { 0x5d, 0x1c, "hardware impending failure drive calibration retry "
492 492 "count" },
493 493 { 0x5d, 0x20, "controller impending failure general hard drive "
494 494 "failure" },
495 495 { 0x5d, 0x21, "controller impending failure drive error rate too "
496 496 "high" },
497 497 { 0x5d, 0x22, "controller impending failure data error rate too high" },
498 498 { 0x5d, 0x23, "controller impending failure seek error rate too high" },
499 499 { 0x5d, 0x24, "controller impending failure too many block reassigns" },
500 500 { 0x5d, 0x25, "controller impending failure access times too high" },
501 501 { 0x5d, 0x26, "controller impending failure start unit times too "
502 502 "high" },
503 503 { 0x5d, 0x27, "controller impending failure channel parametrics" },
504 504 { 0x5d, 0x28, "controller impending failure controller detected" },
505 505 { 0x5d, 0x29, "controller impending failure throughput performance" },
506 506 { 0x5d, 0x2a, "controller impending failure seek time performance" },
507 507 { 0x5d, 0x2b, "controller impending failure spin-up retry count" },
508 508 { 0x5d, 0x2c, "controller impending failure drive calibration retry "
509 509 "cnt" },
510 510 { 0x5d, 0x30, "data channel impending failure general hard drive "
511 511 "failure" },
512 512 { 0x5d, 0x31, "data channel impending failure drive error rate too "
513 513 "high" },
514 514 { 0x5d, 0x32, "data channel impending failure data error rate too "
515 515 "high" },
516 516 { 0x5d, 0x33, "data channel impending failure seek error rate too "
517 517 "high" },
518 518 { 0x5d, 0x34, "data channel impending failure too many block "
519 519 "reassigns" },
520 520 { 0x5d, 0x35, "data channel impending failure access times too high" },
521 521 { 0x5d, 0x36, "data channel impending failure start unit times too "
522 522 "high" },
523 523 { 0x5d, 0x37, "data channel impending failure channel parametrics" },
524 524 { 0x5d, 0x38, "data channel impending failure controller detected" },
525 525 { 0x5d, 0x39, "data channel impending failure throughput performance" },
526 526 { 0x5d, 0x3a, "data channel impending failure seek time performance" },
527 527 { 0x5d, 0x3b, "data channel impending failure spin-up retry count" },
528 528 { 0x5d, 0x3c, "data channel impending failure drive calibrate retry "
529 529 "cnt" },
530 530 { 0x5d, 0x40, "servo impending failure general hard drive failure" },
531 531 { 0x5d, 0x41, "servo impending failure drive error rate too high" },
532 532 { 0x5d, 0x42, "servo impending failure data error rate too high" },
533 533 { 0x5d, 0x43, "servo impending failure seek error rate too high" },
534 534 { 0x5d, 0x44, "servo impending failure too many block reassigns" },
535 535 { 0x5d, 0x45, "servo impending failure access times too high" },
536 536 { 0x5d, 0x46, "servo impending failure start unit times too high" },
537 537 { 0x5d, 0x47, "servo impending failure channel parametrics" },
538 538 { 0x5d, 0x48, "servo impending failure controller detected" },
539 539 { 0x5d, 0x49, "servo impending failure throughput performance" },
540 540 { 0x5d, 0x4a, "servo impending failure seek time performance" },
541 541 { 0x5d, 0x4b, "servo impending failure spin-up retry count" },
542 542 { 0x5d, 0x4c, "servo impending failure drive calibration retry count" },
543 543 { 0x5d, 0x50, "spindle impending failure general hard drive failure" },
544 544 { 0x5d, 0x51, "spindle impending failure drive error rate too high" },
545 545 { 0x5d, 0x52, "spindle impending failure data error rate too high" },
546 546 { 0x5d, 0x53, "spindle impending failure seek error rate too high" },
547 547 { 0x5d, 0x54, "spindle impending failure too many block reassigns" },
548 548 { 0x5d, 0x55, "spindle impending failure access times too high" },
549 549 { 0x5d, 0x56, "spindle impending failure start unit times too high" },
550 550 { 0x5d, 0x57, "spindle impending failure channel parametrics" },
551 551 { 0x5d, 0x58, "spindle impending failure controller detected" },
552 552 { 0x5d, 0x59, "spindle impending failure throughput performance" },
553 553 { 0x5d, 0x5a, "spindle impending failure seek time performance" },
554 554 { 0x5d, 0x5b, "spindle impending failure spin-up retry count" },
555 555 { 0x5d, 0x5c, "spindle impending failure drive calibration retry "
556 556 "count" },
557 557 { 0x5d, 0x60, "firmware impending failure general hard drive failure" },
558 558 { 0x5d, 0x61, "firmware impending failure drive error rate too high" },
559 559 { 0x5d, 0x62, "firmware impending failure data error rate too high" },
560 560 { 0x5d, 0x63, "firmware impending failure seek error rate too high" },
561 561 { 0x5d, 0x64, "firmware impending failure too many block reassigns" },
562 562 { 0x5d, 0x65, "firmware impending failure access times too high" },
563 563 { 0x5d, 0x66, "firmware impending failure start unit times too high" },
564 564 { 0x5d, 0x67, "firmware impending failure channel parametrics" },
565 565 { 0x5d, 0x68, "firmware impending failure controller detected" },
566 566 { 0x5d, 0x69, "firmware impending failure throughput performance" },
567 567 { 0x5d, 0x6a, "firmware impending failure seek time performance" },
568 568 { 0x5d, 0x6b, "firmware impending failure spin-up retry count" },
569 569 { 0x5d, 0x6c, "firmware impending failure drive calibration retry "
570 570 "count" },
571 571 { 0x5d, 0xff, "failure prediction threshold exceeded (false)" },
572 572 { 0x5e, 0x00, "low power condition active" },
573 573 { 0x5e, 0x01, "idle condition activated by timer" },
574 574 { 0x5e, 0x02, "standby condition activated by timer" },
575 575 { 0x5e, 0x03, "idle condition activated by command" },
576 576 { 0x5e, 0x04, "standby condition activated by command" },
577 577 { 0x60, 0x00, "lamp failure" },
578 578 { 0x61, 0x00, "video aquisition error" },
579 579 { 0x62, 0x00, "scan head positioning error" },
580 580 { 0x63, 0x00, "end of user area encountered on this track" },
581 581 { 0x63, 0x01, "packet does not fit in available space" },
582 582 { 0x64, 0x00, "illegal mode for this track" },
583 583 { 0x64, 0x01, "invalid packet size" },
584 584 { 0x65, 0x00, "voltage fault" },
585 585 { 0x66, 0x00, "automatic document feeder cover up" },
586 586 { 0x67, 0x00, "configuration failure" },
587 587 { 0x67, 0x01, "configuration of incapable LUNs failed" },
588 588 { 0x67, 0x02, "add LUN failed" },
589 589 { 0x67, 0x03, "modification of LUN failed" },
590 590 { 0x67, 0x04, "exchange of LUN failed" },
591 591 { 0x67, 0x05, "remove of LUN failed" },
592 592 { 0x67, 0x06, "attachment of LUN failed" },
593 593 { 0x67, 0x07, "creation of LUN failed" },
594 594 { 0x67, 0x08, "assign failure occurred" },
595 595 { 0x67, 0x09, "multiply assigned LUN" },
596 596 { 0x67, 0x0a, "set target port groups command failed" },
597 597 { 0x68, 0x00, "logical unit not configured" },
598 598 { 0x69, 0x00, "data loss on logical unit" },
599 599 { 0x69, 0x01, "multiple LUN failures" },
600 600 { 0x69, 0x02, "parity/data mismatch" },
601 601 { 0x6a, 0x00, "informational, refer to log" },
602 602 { 0x6b, 0x00, "state change has occured" },
603 603 { 0x6b, 0x01, "redundancy level got better" },
604 604 { 0x6b, 0x02, "redundancy level got worse" },
605 605 { 0x6c, 0x00, "rebuild failure occured" },
606 606 { 0x6d, 0x00, "recalculate failure occured" },
607 607 { 0x6e, 0x00, "command to logical unit failed" },
608 608 { 0x6f, 0x00, "copy protect key exchange failure authentication "
609 609 "failure" },
610 610 { 0x6f, 0x01, "copy protect key exchange failure key not present" },
611 611 { 0x6f, 0x02, "copy protect key exchange failure key not established" },
612 612 { 0x6f, 0x03, "read of scrambled sector without authentication" },
613 613 { 0x6f, 0x04, "media region code is mismatched to LUN region" },
614 614 { 0x6f, 0x05, "drive region must be permanent/region reset count "
615 615 "error" },
616 616 { 0x70, 0xffff, "decompression exception short algorithm id of ASCQ" },
617 617 { 0x71, 0x00, "decompression exception long algorithm id" },
618 618 { 0x72, 0x00, "session fixation error" },
619 619 { 0x72, 0x01, "session fixation error writing lead-in" },
620 620 { 0x72, 0x02, "session fixation error writing lead-out" },
621 621 { 0x72, 0x03, "session fixation error - incomplete track in session" },
622 622 { 0x72, 0x04, "empty or partially written reserved track" },
623 623 { 0x72, 0x05, "no more track reservations allowed" },
624 624 { 0x73, 0x00, "cd control error" },
625 625 { 0x73, 0x01, "power calibration area almost full" },
626 626 { 0x73, 0x02, "power calibration area is full" },
627 627 { 0x73, 0x03, "power calibration area error" },
628 628 { 0x73, 0x04, "program memory area update failure" },
629 629 { 0x73, 0x05, "program memory area is full" },
630 630 { 0x73, 0x06, "rma/pma is almost full" },
631 631 { 0xffff, 0xffff, NULL }
632 632 };
633 633
634 634 /*
635 635 * Given an asc (Additional Sense Code) and ascq (Additional Sense Code
636 636 * Qualifier), return a string describing the error information.
637 637 */
638 638 static char *
639 639 scsi_util_asc_ascq_name(uint_t asc, uint_t ascq, char *buf, int buflen)
640 640 {
641 641 int i = 0;
642 642
643 643 while (extended_sense_list[i].asc != 0xffff) {
644 644 if ((asc == extended_sense_list[i].asc) &&
645 645 ((ascq == extended_sense_list[i].ascq) ||
646 646 (extended_sense_list[i].ascq == 0xffff))) {
647 647 return ((char *)extended_sense_list[i].message);
648 648 }
649 649 i++;
650 650 }
651 651 (void) snprintf(buf, buflen, "<vendor unique code 0x%x>", asc);
652 652 return (buf);
653 653 }
654 654
655 655 /*
656 656 * Dumps detailed information about a particular SCSI error condition.
657 657 */
658 658 static void
659 659 scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, int rqlen)
660 660 {
661 661 diskaddr_t blkno;
662 662 struct scsi_descr_sense_hdr *sdsp = (struct scsi_descr_sense_hdr *)rq;
663 663 char msgbuf[MSGBUFLEN];
664 664
665 665 if (find_string(sensekey_strings, rq->es_key) == NULL)
666 666 dprintf("unknown error");
667 667
668 668 dprintf("during %s:",
669 669 find_string(scsi_cmdname_strings, ucmd->uscsi_cdb[0]));
670 670
671 671 /*
672 672 * Get asc, ascq and info field from sense data. There are two
673 673 * possible formats (fixed sense data and descriptor sense data)
674 674 * depending on the value of es_code.
675 675 */
676 676 switch (rq->es_code) {
677 677 case CODE_FMT_DESCR_CURRENT:
678 678 case CODE_FMT_DESCR_DEFERRED:
679 679 blkno = (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen);
680 680 if (blkno != (diskaddr_t)-1)
681 681 dprintf(": block %lld (0x%llx)", blkno, blkno);
682 682 dprintf("\n");
683 683 dprintf("ASC: 0x%x ASCQ: 0x%x (%s)\n",
684 684 sdsp->ds_add_code, sdsp->ds_qual_code,
685 685 scsi_util_asc_ascq_name(sdsp->ds_add_code,
686 686 sdsp->ds_qual_code, msgbuf, MSGBUFLEN));
687 687
688 688 break;
689 689
690 690 case CODE_FMT_FIXED_CURRENT:
691 691 case CODE_FMT_FIXED_DEFERRED:
692 692 default:
693 693 if (rq->es_valid) {
694 694 blkno = (rq->es_info_1 << 24) |
695 695 (rq->es_info_2 << 16) |
696 696 (rq->es_info_3 << 8) | rq->es_info_4;
697 697 dprintf(": block %lld (0x%llx)", blkno, blkno);
698 698 }
699 699 dprintf("\n");
700 700 if (rq->es_add_len >= 6) {
701 701 dprintf("ASC: 0x%x ASCQ: 0x%x (%s)\n",
702 702 rq->es_add_code,
703 703 rq->es_qual_code,
704 704 scsi_util_asc_ascq_name(rq->es_add_code,
705 705 rq->es_qual_code, msgbuf, MSGBUFLEN));
706 706 }
707 707 break;
708 708 }
709 709
710 710 if (rq->es_key == KEY_ILLEGAL_REQUEST) {
711 711 ddump("cmd:", (caddr_t)ucmd,
712 712 sizeof (struct uscsi_cmd));
713 713 ddump("cdb:", (caddr_t)ucmd->uscsi_cdb,
714 714 ucmd->uscsi_cdblen);
715 715 }
716 716 ddump("sense:", (caddr_t)rq, rqlen);
717 717
718 718 switch (rq->es_code) {
719 719 case CODE_FMT_DESCR_CURRENT:
720 720 case CODE_FMT_DESCR_DEFERRED:
721 721 scsi_print_descr_sense(sdsp, rqlen);
722 722 break;
723 723 case CODE_FMT_FIXED_CURRENT:
724 724 case CODE_FMT_FIXED_DEFERRED:
725 725 default:
726 726 scsi_print_extended_sense(rq, rqlen);
727 727 break;
728 728 }
729 729 }
730 730
731 731 /*
732 732 * Retrieve "information" field from descriptor format sense data. Iterates
733 733 * through each sense descriptor looking for the information descriptor and
734 734 * returns the information field from that descriptor.
735 735 */
736 736 static diskaddr_t
737 737 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen)
738 738 {
739 739 diskaddr_t result;
740 740 uint8_t *descr_offset;
741 741 int valid_sense_length;
742 742 struct scsi_information_sense_descr *isd;
743 743
744 744 /*
745 745 * Initialize result to -1 indicating there is no information
746 746 * descriptor
747 747 */
748 748 result = (diskaddr_t)-1;
749 749
750 750 /*
751 751 * The first descriptor will immediately follow the header
752 752 */
753 753 descr_offset = (uint8_t *)(sdsp+1);
754 754
755 755 /*
756 756 * Calculate the amount of valid sense data
757 757 */
758 758 valid_sense_length =
759 759 MIN((sizeof (struct scsi_descr_sense_hdr) +
760 760 sdsp->ds_addl_sense_length), rqlen);
761 761
762 762 /*
763 763 * Iterate through the list of descriptors, stopping when we run out of
764 764 * sense data
765 765 */
766 766 while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <=
767 767 (uint8_t *)sdsp + valid_sense_length) {
768 768 /*
769 769 * Check if this is an information descriptor. We can use the
770 770 * scsi_information_sense_descr structure as a template since
771 771 * the first two fields are always the same
772 772 */
773 773 isd = (struct scsi_information_sense_descr *)descr_offset;
774 774 if (isd->isd_descr_type == DESCR_INFORMATION) {
775 775 /*
776 776 * Found an information descriptor. Copy the
777 777 * information field. There will only be one
778 778 * information descriptor so we can stop looking.
779 779 */
780 780 result =
781 781 (((diskaddr_t)isd->isd_information[0] << 56) |
782 782 ((diskaddr_t)isd->isd_information[1] << 48) |
783 783 ((diskaddr_t)isd->isd_information[2] << 40) |
784 784 ((diskaddr_t)isd->isd_information[3] << 32) |
785 785 ((diskaddr_t)isd->isd_information[4] << 24) |
786 786 ((diskaddr_t)isd->isd_information[5] << 16) |
787 787 ((diskaddr_t)isd->isd_information[6] << 8) |
788 788 ((diskaddr_t)isd->isd_information[7]));
789 789 break;
790 790 }
791 791
792 792 /*
793 793 * Get pointer to the next descriptor. The "additional length"
794 794 * field holds the length of the descriptor except for the
795 795 * "type" and "additional length" fields, so we need to add 2 to
796 796 * get the total length.
797 797 */
798 798 descr_offset += (isd->isd_addl_length + 2);
799 799 }
800 800
801 801 return (result);
802 802 }
803 803
804 804 /*
805 805 * Display the full scsi_extended_sense as returned by the device
806 806 */
807 807 static void
808 808 scsi_print_extended_sense(struct scsi_extended_sense *rq, int rqlen)
809 809 {
810 810 static char *scsi_extended_sense_labels[] = {
811 811 "Request sense valid: ",
812 812 "Error class and code: ",
813 813 "Segment number: ",
814 814 "Filemark: ",
815 815 "End-of-medium: ",
816 816 "Incorrect length indicator: ",
817 817 "Sense key: ",
818 818 "Information field: ",
819 819 "Additional sense length: ",
820 820 "Command-specific information: ",
821 821 "Additional sense code: ",
822 822 "Additional sense code qualifier: ",
823 823 "Field replaceable unit code: ",
824 824 "Sense-key specific: ",
825 825 "Additional sense bytes: "
826 826 };
827 827
828 828 char **p = scsi_extended_sense_labels;
829 829
830 830 if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) {
831 831 /*
832 832 * target should be capable of returning at least 18
833 833 * bytes of data, i.e upto rq->es_skey_specific field.
834 834 * The additional sense bytes (2 or more ...) are optional.
835 835 */
836 836 return;
837 837 }
838 838
839 839 dprintf("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no");
840 840 dprintf("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code);
841 841 dprintf("%s%d\n", *p++, rq->es_segnum);
842 842 dprintf("%s%s\n", *p++, rq->es_filmk ? "yes" : "no");
843 843 dprintf("%s%s\n", *p++, rq->es_eom ? "yes" : "no");
844 844 dprintf("%s%s\n", *p++, rq->es_ili ? "yes" : "no");
845 845 dprintf("%s%d\n", *p++, rq->es_key);
846 846
847 847 dprintf("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1,
848 848 rq->es_info_2, rq->es_info_3, rq->es_info_4);
849 849 dprintf("%s%d\n", *p++, rq->es_add_len);
850 850 dprintf("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++,
851 851 rq->es_cmd_info[0], rq->es_cmd_info[1], rq->es_cmd_info[2],
852 852 rq->es_cmd_info[3]);
853 853 dprintf("%s0x%02x = %d\n", *p++, rq->es_add_code,
854 854 rq->es_add_code);
855 855 dprintf("%s0x%02x = %d\n", *p++, rq->es_qual_code,
856 856 rq->es_qual_code);
857 857 dprintf("%s%d\n", *p++, rq->es_fru_code);
858 858 dprintf("%s0x%02x 0x%02x 0x%02x\n", *p++,
859 859 rq->es_skey_specific[0], rq->es_skey_specific[1],
860 860 rq->es_skey_specific[2]);
861 861 if (rqlen >= sizeof (*rq)) {
862 862 dprintf("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0],
863 863 rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : "");
864 864 }
865 865
866 866 dprintf("\n");
867 867 }
868 868
869 869 /*
870 870 * Display the full descriptor sense data as returned by the device
871 871 */
872 872 static void
873 873 scsi_print_descr_sense(struct scsi_descr_sense_hdr *rq, int rqlen)
874 874 {
875 875 /*
876 876 * Labels for the various fields of the scsi_descr_sense_hdr structure
877 877 */
878 878 static char *scsi_descr_sense_labels[] = {
879 879 "Error class and code: ",
880 880 "Sense key: ",
881 881 "Additional sense length: ",
882 882 "Additional sense code: ",
883 883 "Additional sense code qualifier: ",
884 884 "Additional sense bytes: "
885 885 };
886 886
887 887 struct scsi_information_sense_descr *isd;
888 888 uint8_t *descr_offset;
889 889 int valid_sense_length;
890 890 char **p = scsi_descr_sense_labels;
891 891
892 892 /* Target must return at least 8 bytes of data */
893 893 if (rqlen < sizeof (struct scsi_descr_sense_hdr))
894 894 return;
895 895
896 896 /* Print descriptor sense header */
897 897 dprintf("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code);
898 898 dprintf("%s%d\n", *p++, rq->ds_key);
899 899
900 900 dprintf("%s%d\n", *p++, rq->ds_addl_sense_length);
901 901 dprintf("%s0x%02x = %d\n", *p++, rq->ds_add_code,
902 902 rq->ds_add_code);
903 903 dprintf("%s0x%02x = %d\n", *p++, rq->ds_qual_code,
904 904 rq->ds_qual_code);
905 905 dprintf("\n");
906 906
907 907 /*
908 908 * Now print any sense descriptors. The first descriptor will
909 909 * immediately follow the header
910 910 */
911 911 descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */
912 912
913 913 /*
914 914 * Calculate the amount of valid sense data
915 915 */
916 916 valid_sense_length =
917 917 MIN((sizeof (struct scsi_descr_sense_hdr) +
918 918 rq->ds_addl_sense_length), rqlen);
919 919
920 920 /*
921 921 * Iterate through the list of descriptors, stopping when we
922 922 * run out of sense data. Descriptor format is:
923 923 *
924 924 * <Descriptor type> <Descriptor length> <Descriptor data> ...
925 925 */
926 926 while ((descr_offset + *(descr_offset + 1)) <=
927 927 (uint8_t *)rq + valid_sense_length) {
928 928 /*
929 929 * Determine descriptor type. We can use the
930 930 * scsi_information_sense_descr structure as a
931 931 * template since the first two fields are always the
932 932 * same.
933 933 */
934 934 isd = (struct scsi_information_sense_descr *)descr_offset;
935 935 switch (isd->isd_descr_type) {
936 936 case DESCR_INFORMATION: {
937 937 uint64_t information;
938 938
939 939 information =
940 940 (((uint64_t)isd->isd_information[0] << 56) |
941 941 ((uint64_t)isd->isd_information[1] << 48) |
942 942 ((uint64_t)isd->isd_information[2] << 40) |
943 943 ((uint64_t)isd->isd_information[3] << 32) |
944 944 ((uint64_t)isd->isd_information[4] << 24) |
945 945 ((uint64_t)isd->isd_information[5] << 16) |
946 946 ((uint64_t)isd->isd_information[6] << 8) |
947 947 ((uint64_t)isd->isd_information[7]));
948 948 dprintf("Information field: "
949 949 "%0" PRIx64 "\n", information);
950 950 break;
951 951 }
952 952 case DESCR_COMMAND_SPECIFIC: {
953 953 struct scsi_cmd_specific_sense_descr *c =
954 954 (struct scsi_cmd_specific_sense_descr *)isd;
955 955 uint64_t cmd_specific;
956 956
957 957 cmd_specific =
958 958 (((uint64_t)c->css_cmd_specific_info[0] << 56) |
959 959 ((uint64_t)c->css_cmd_specific_info[1] << 48) |
960 960 ((uint64_t)c->css_cmd_specific_info[2] << 40) |
961 961 ((uint64_t)c->css_cmd_specific_info[3] << 32) |
962 962 ((uint64_t)c->css_cmd_specific_info[4] << 24) |
963 963 ((uint64_t)c->css_cmd_specific_info[5] << 16) |
964 964 ((uint64_t)c->css_cmd_specific_info[6] << 8) |
965 965 ((uint64_t)c->css_cmd_specific_info[7]));
966 966 dprintf("Command-specific information: "
967 967 "%0" PRIx64 "\n", cmd_specific);
968 968 break;
969 969 }
970 970 case DESCR_SENSE_KEY_SPECIFIC: {
971 971 struct scsi_sk_specific_sense_descr *ssd =
972 972 (struct scsi_sk_specific_sense_descr *)isd;
973 973 uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data;
974 974 dprintf("Sense-key specific: "
975 975 "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0],
976 976 sk_spec_ptr[1], sk_spec_ptr[2]);
977 977 break;
978 978 }
979 979 case DESCR_FRU: {
980 980 struct scsi_fru_sense_descr *fsd =
981 981 (struct scsi_fru_sense_descr *)isd;
982 982 dprintf("Field replaceable unit code: "
983 983 "%d\n", fsd->fs_fru_code);
984 984 break;
985 985 }
986 986 case DESCR_BLOCK_COMMANDS: {
987 987 struct scsi_block_cmd_sense_descr *bsd =
988 988 (struct scsi_block_cmd_sense_descr *)isd;
989 989 dprintf("Incorrect length indicator: "
990 990 "%s\n", bsd->bcs_ili ? "yes" : "no");
991 991 break;
992 992 }
993 993 default:
994 994 /* Ignore */
995 995 break;
996 996 }
997 997
998 998 /*
999 999 * Get pointer to the next descriptor. The "additional
1000 1000 * length" field holds the length of the descriptor except
1001 1001 * for the "type" and "additional length" fields, so
1002 1002 * we need to add 2 to get the total length.
1003 1003 */
1004 1004 descr_offset += (isd->isd_addl_length + 2);
1005 1005 }
1006 1006
1007 1007 dprintf("\n");
1008 1008 }
1009 1009
1010 1010 static int
1011 1011 uscsi_timeout(void)
1012 1012 {
1013 1013 const char *env = getenv("USCSI_TIMEOUT");
|
↓ open down ↓ |
1013 lines elided |
↑ open up ↑ |
1014 1014 static int timeo = -1;
1015 1015 int i;
1016 1016
1017 1017 if (timeo > 0)
1018 1018 return (timeo);
1019 1019
1020 1020 if (env != NULL) {
1021 1021 i = atoi(env);
1022 1022 if (i > USCSI_TIMEOUT_MAX)
1023 1023 i = USCSI_TIMEOUT_MAX;
1024 - else if (i < 0)
1024 + else if (i <= 0)
1025 1025 i = USCSI_DEFAULT_TIMEOUT;
1026 1026 } else
1027 1027 i = USCSI_DEFAULT_TIMEOUT;
1028 1028
1029 1029 timeo = i;
1030 1030 return (i);
1031 1031 }
1032 1032
1033 1033 /*
1034 1034 * Execute a command and determine the result. Uses the "uscsi" ioctl
1035 1035 * interface, which is fully supported.
1036 1036 *
1037 1037 * If the user wants request sense data to be returned in case of error then ,
1038 1038 * the "uscsi_cmd" structure should have the request sense buffer allocated in
1039 1039 * uscsi_rqbuf.
1040 1040 */
1041 1041 static int
1042 1042 uscsi_cmd(int fd, struct uscsi_cmd *ucmd, void *rqbuf, int *rqlen)
1043 1043 {
1044 1044 struct scsi_extended_sense *rq;
1045 1045 int status;
1046 1046
1047 1047 /*
1048 1048 * Set function flags for driver.
1049 1049 */
1050 1050 ucmd->uscsi_flags = USCSI_ISOLATE;
1051 1051 if (!ds_debug)
1052 1052 ucmd->uscsi_flags |= USCSI_SILENT;
1053 1053
1054 1054 /*
1055 1055 * If this command will perform a read, set the USCSI_READ flag
1056 1056 */
1057 1057 if (ucmd->uscsi_buflen > 0) {
1058 1058 /*
1059 1059 * uscsi_cdb is declared as a caddr_t, so any CDB
1060 1060 * command byte with the MSB set will result in a
1061 1061 * compiler error unless we cast to an unsigned value.
1062 1062 */
1063 1063 switch ((uint8_t)ucmd->uscsi_cdb[0]) {
1064 1064 case SCMD_MODE_SENSE:
1065 1065 case SCMD_MODE_SENSE_G1:
1066 1066 case SCMD_LOG_SENSE_G1:
1067 1067 case SCMD_REQUEST_SENSE:
1068 1068 ucmd->uscsi_flags |= USCSI_READ;
1069 1069 break;
1070 1070
1071 1071 case SCMD_MODE_SELECT:
1072 1072 case SCMD_MODE_SELECT_G1:
1073 1073 /* LINTED */
1074 1074 ucmd->uscsi_flags |= USCSI_WRITE;
1075 1075 break;
1076 1076 default:
1077 1077 assert(0);
1078 1078 break;
1079 1079 }
1080 1080 }
1081 1081
1082 1082 /* Set timeout */
1083 1083 ucmd->uscsi_timeout = uscsi_timeout();
1084 1084
1085 1085 /*
1086 1086 * Set up Request Sense buffer
1087 1087 */
1088 1088
1089 1089 if (ucmd->uscsi_rqbuf == NULL) {
1090 1090 ucmd->uscsi_rqbuf = rqbuf;
1091 1091 ucmd->uscsi_rqlen = *rqlen;
1092 1092 ucmd->uscsi_rqresid = *rqlen;
1093 1093 }
1094 1094 if (ucmd->uscsi_rqbuf)
1095 1095 ucmd->uscsi_flags |= USCSI_RQENABLE;
1096 1096 ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
1097 1097
1098 1098 if (ucmd->uscsi_rqbuf != NULL && ucmd->uscsi_rqlen > 0)
1099 1099 (void) memset(ucmd->uscsi_rqbuf, 0, ucmd->uscsi_rqlen);
1100 1100
1101 1101 /*
1102 1102 * Execute the ioctl
1103 1103 */
1104 1104 status = ioctl(fd, USCSICMD, ucmd);
1105 1105 if (status == 0 && ucmd->uscsi_status == 0)
1106 1106 return (status);
1107 1107
1108 1108 /*
1109 1109 * If an automatic Request Sense gave us valid info about the error, we
1110 1110 * may be able to use that to print a reasonable error msg.
1111 1111 */
1112 1112 if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) {
1113 1113 dprintf("No request sense for command %s\n",
1114 1114 find_string(scsi_cmdname_strings,
1115 1115 ucmd->uscsi_cdb[0]));
1116 1116 return (-1);
1117 1117 }
1118 1118 if (ucmd->uscsi_rqstatus != STATUS_GOOD) {
1119 1119 dprintf("Request sense status for command %s: 0x%x\n",
1120 1120 find_string(scsi_cmdname_strings,
1121 1121 ucmd->uscsi_cdb[0]),
1122 1122 ucmd->uscsi_rqstatus);
1123 1123 return (-1);
1124 1124 }
1125 1125
1126 1126 rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf;
1127 1127 *rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid;
1128 1128
1129 1129 if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN ||
1130 1130 rq->es_class != CLASS_EXTENDED_SENSE ||
1131 1131 *rqlen < MIN_REQUEST_SENSE_LEN) {
1132 1132 dprintf("Request sense for command %s failed\n",
1133 1133 find_string(scsi_cmdname_strings,
1134 1134 ucmd->uscsi_cdb[0]));
1135 1135
1136 1136 dprintf("Sense data:\n");
1137 1137 ddump(NULL, (caddr_t)rqbuf, *rqlen);
1138 1138
1139 1139 return (-1);
1140 1140 }
1141 1141
1142 1142 /*
1143 1143 * If the failed command is a Mode Select, and the
1144 1144 * target is indicating that it has rounded one of
1145 1145 * the mode select parameters, as defined in the SCSI-2
1146 1146 * specification, then we should accept the command
1147 1147 * as successful.
1148 1148 */
1149 1149 if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT ||
1150 1150 ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT_G1) {
1151 1151 if (rq->es_key == KEY_RECOVERABLE_ERROR &&
1152 1152 rq->es_add_code == ROUNDED_PARAMETER &&
1153 1153 rq->es_qual_code == 0) {
1154 1154 return (0);
1155 1155 }
1156 1156 }
1157 1157
1158 1158 if (ds_debug)
1159 1159 scsi_printerr(ucmd, rq, *rqlen);
1160 1160 if (rq->es_key != KEY_RECOVERABLE_ERROR)
1161 1161 return (-1);
1162 1162 return (0);
1163 1163 }
1164 1164
1165 1165 int
1166 1166 uscsi_request_sense(int fd, caddr_t buf, int buflen, void *rqbuf, int *rqblen)
1167 1167 {
1168 1168 struct uscsi_cmd ucmd;
1169 1169 union scsi_cdb cdb;
1170 1170 int status;
1171 1171
1172 1172 (void) memset(buf, 0, buflen);
1173 1173 (void) memset(&ucmd, 0, sizeof (ucmd));
1174 1174 (void) memset(&cdb, 0, sizeof (union scsi_cdb));
1175 1175 cdb.scc_cmd = SCMD_REQUEST_SENSE;
1176 1176 FORMG0COUNT(&cdb, (uchar_t)buflen);
1177 1177 ucmd.uscsi_cdb = (caddr_t)&cdb;
1178 1178 ucmd.uscsi_cdblen = CDB_GROUP0;
1179 1179 ucmd.uscsi_bufaddr = buf;
1180 1180 ucmd.uscsi_buflen = buflen;
1181 1181 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1182 1182 if (status)
1183 1183 dprintf("Request sense failed\n");
1184 1184 if (status == 0)
1185 1185 ddump("Request Sense data:", buf, buflen);
1186 1186
1187 1187 return (status);
1188 1188 }
1189 1189
1190 1190 /*
1191 1191 * Execute a uscsi mode sense command. This can only be used to return one page
1192 1192 * at a time. Return the mode header/block descriptor and the actual page data
1193 1193 * separately - this allows us to support devices which return either 0 or 1
1194 1194 * block descriptors. Whatever a device gives us in the mode header/block
1195 1195 * descriptor will be returned to it upon subsequent mode selects.
1196 1196 */
1197 1197 int
1198 1198 uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
1199 1199 int page_size, struct scsi_ms_header *header, void *rqbuf, int *rqblen)
1200 1200 {
1201 1201 caddr_t mode_sense_buf;
1202 1202 struct mode_header *hdr;
1203 1203 struct mode_page *pg;
1204 1204 int nbytes;
1205 1205 struct uscsi_cmd ucmd;
1206 1206 union scsi_cdb cdb;
1207 1207 int status;
1208 1208 int maximum;
1209 1209 char *pc;
1210 1210
1211 1211 assert(page_size >= 0 && page_size < 256);
1212 1212 assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1213 1213 page_control == PC_DEFAULT || page_control == PC_SAVED);
1214 1214
1215 1215 nbytes = sizeof (struct scsi_ms_header) + page_size;
1216 1216 mode_sense_buf = alloca((uint_t)nbytes);
1217 1217
1218 1218 /*
1219 1219 * Build and execute the uscsi ioctl
1220 1220 */
1221 1221 (void) memset(mode_sense_buf, 0, nbytes);
1222 1222 (void) memset(&ucmd, 0, sizeof (ucmd));
1223 1223 (void) memset(&cdb, 0, sizeof (union scsi_cdb));
1224 1224 cdb.scc_cmd = SCMD_MODE_SENSE;
1225 1225 FORMG0COUNT(&cdb, (uchar_t)nbytes);
1226 1226 cdb.cdb_opaque[2] = page_control | page_code;
1227 1227 ucmd.uscsi_cdb = (caddr_t)&cdb;
1228 1228 ucmd.uscsi_cdblen = CDB_GROUP0;
1229 1229 ucmd.uscsi_bufaddr = mode_sense_buf;
1230 1230 ucmd.uscsi_buflen = nbytes;
1231 1231 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1232 1232 if (status) {
1233 1233 dprintf("Mode sense page 0x%x failed\n", page_code);
1234 1234 return (-1);
1235 1235 }
1236 1236
1237 1237 ddump("RAW MODE SENSE BUFFER", mode_sense_buf, nbytes);
1238 1238
1239 1239 /*
1240 1240 * Verify that the returned data looks reasonable, find the actual page
1241 1241 * data, and copy it into the user's buffer. Copy the mode_header and
1242 1242 * block_descriptor into the header structure, which can then be used to
1243 1243 * return the same data to the drive when issuing a mode select.
1244 1244 */
1245 1245 hdr = (struct mode_header *)mode_sense_buf;
1246 1246 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
1247 1247 if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
1248 1248 hdr->bdesc_length != 0) {
1249 1249 dprintf("\nMode sense page 0x%x: block descriptor "
1250 1250 "length %d incorrect\n", page_code, hdr->bdesc_length);
1251 1251 ddump("Mode sense:", mode_sense_buf, nbytes);
1252 1252 return (-1);
1253 1253 }
1254 1254 (void) memcpy((caddr_t)header, mode_sense_buf,
1255 1255 (int)(MODE_HEADER_LENGTH + hdr->bdesc_length));
1256 1256 pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1257 1257 MODE_HEADER_LENGTH + hdr->bdesc_length);
1258 1258
1259 1259 if (page_code == MODEPAGE_ALLPAGES) {
1260 1260 /* special case */
1261 1261
1262 1262 (void) memcpy(page_data, (caddr_t)pg,
1263 1263 (hdr->length + sizeof (header->ms_header.length)) -
1264 1264 (MODE_HEADER_LENGTH + hdr->bdesc_length));
1265 1265
1266 1266 pc = find_string(page_control_strings, page_control);
1267 1267 dprintf("\nMode sense page 0x%x (%s):\n", page_code,
1268 1268 pc != NULL ? pc : "");
1269 1269 ddump("header:", (caddr_t)header,
1270 1270 sizeof (struct scsi_ms_header));
1271 1271 ddump("data:", page_data,
1272 1272 (hdr->length +
1273 1273 sizeof (header->ms_header.length)) -
1274 1274 (MODE_HEADER_LENGTH + hdr->bdesc_length));
1275 1275
1276 1276 return (0);
1277 1277 }
1278 1278
1279 1279 if (pg->code != page_code) {
1280 1280 dprintf("\nMode sense page 0x%x: incorrect page code 0x%x\n",
1281 1281 page_code, pg->code);
1282 1282 ddump("Mode sense:", mode_sense_buf, nbytes);
1283 1283 return (-1);
1284 1284 }
1285 1285
1286 1286 /*
1287 1287 * Accept up to "page_size" bytes of mode sense data. This allows us to
1288 1288 * accept both CCS and SCSI-2 structures, as long as we request the
1289 1289 * greater of the two.
1290 1290 */
1291 1291 maximum = page_size - sizeof (struct mode_page);
1292 1292 if (((int)pg->length) > maximum) {
1293 1293 dprintf("Mode sense page 0x%x: incorrect page "
1294 1294 "length %d - expected max %d\n",
1295 1295 page_code, pg->length, maximum);
1296 1296 ddump("Mode sense:", mode_sense_buf, nbytes);
1297 1297 return (-1);
1298 1298 }
1299 1299
1300 1300 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1301 1301
1302 1302 pc = find_string(page_control_strings, page_control);
1303 1303 dprintf("\nMode sense page 0x%x (%s):\n", page_code,
1304 1304 pc != NULL ? pc : "");
1305 1305 ddump("header:", (caddr_t)header, sizeof (struct scsi_ms_header));
1306 1306 ddump("data:", page_data, MODESENSE_PAGE_LEN(pg));
1307 1307
1308 1308 return (0);
1309 1309 }
1310 1310
1311 1311 /*
1312 1312 * Execute a uscsi MODE SENSE(10) command. This can only be used to return one
1313 1313 * page at a time. Return the mode header/block descriptor and the actual page
1314 1314 * data separately - this allows us to support devices which return either 0 or
1315 1315 * 1 block descriptors. Whatever a device gives us in the mode header/block
1316 1316 * descriptor will be returned to it upon subsequent mode selects.
1317 1317 */
1318 1318 int
1319 1319 uscsi_mode_sense_10(int fd, int page_code, int page_control,
1320 1320 caddr_t page_data, int page_size, struct scsi_ms_header_g1 *header,
1321 1321 void *rqbuf, int *rqblen)
1322 1322 {
1323 1323 caddr_t mode_sense_buf;
1324 1324 struct mode_header_g1 *hdr;
1325 1325 struct mode_page *pg;
1326 1326 int nbytes;
1327 1327 struct uscsi_cmd ucmd;
1328 1328 union scsi_cdb cdb;
1329 1329 int status;
1330 1330 int maximum;
1331 1331 ushort_t length, bdesc_length;
1332 1332 char *pc;
1333 1333
1334 1334 assert(page_size >= 0 && page_size < UINT16_MAX);
1335 1335 assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1336 1336 page_control == PC_DEFAULT || page_control == PC_SAVED);
1337 1337
1338 1338 nbytes = sizeof (struct scsi_ms_header_g1) + page_size;
1339 1339 mode_sense_buf = alloca((uint_t)nbytes);
1340 1340
1341 1341 (void) memset(mode_sense_buf, 0, nbytes);
1342 1342 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1343 1343 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1344 1344 cdb.scc_cmd = SCMD_MODE_SENSE_G1;
1345 1345 FORMG1COUNT(&cdb, (uint16_t)nbytes);
1346 1346 cdb.cdb_opaque[2] = page_control | page_code;
1347 1347 ucmd.uscsi_cdb = (caddr_t)&cdb;
1348 1348 ucmd.uscsi_cdblen = CDB_GROUP1;
1349 1349 ucmd.uscsi_bufaddr = mode_sense_buf;
1350 1350 ucmd.uscsi_buflen = nbytes;
1351 1351
1352 1352 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1353 1353 if (status) {
1354 1354 dprintf("Mode sense(10) page 0x%x failed\n",
1355 1355 page_code);
1356 1356 return (-1);
1357 1357 }
1358 1358
1359 1359 ddump("RAW MODE SENSE(10) BUFFER", mode_sense_buf, nbytes);
1360 1360
1361 1361 /*
1362 1362 * Verify that the returned data looks reasonable, find the actual page
1363 1363 * data, and copy it into the user's buffer. Copy the mode_header and
1364 1364 * block_descriptor into the header structure, which can then be used to
1365 1365 * return the same data to the drive when issuing a mode select.
1366 1366 */
1367 1367 /* LINTED */
1368 1368 hdr = (struct mode_header_g1 *)mode_sense_buf;
1369 1369
1370 1370 length = BE_16(hdr->length);
1371 1371 bdesc_length = BE_16(hdr->bdesc_length);
1372 1372
1373 1373 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header_g1));
1374 1374 if (bdesc_length != sizeof (struct block_descriptor) &&
1375 1375 bdesc_length != 0) {
1376 1376 dprintf("\nMode sense(10) page 0x%x: block descriptor "
1377 1377 "length %d incorrect\n", page_code, bdesc_length);
1378 1378 ddump("Mode sense(10):", mode_sense_buf, nbytes);
1379 1379 return (-1);
1380 1380 }
1381 1381 (void) memcpy((caddr_t)header, mode_sense_buf,
1382 1382 (int)(MODE_HEADER_LENGTH_G1 + bdesc_length));
1383 1383 pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1384 1384 MODE_HEADER_LENGTH_G1 + bdesc_length);
1385 1385
1386 1386 if (page_code == MODEPAGE_ALLPAGES) {
1387 1387 /* special case */
1388 1388
1389 1389 (void) memcpy(page_data, (caddr_t)pg,
1390 1390 (length + sizeof (header->ms_header.length)) -
1391 1391 (MODE_HEADER_LENGTH_G1 + bdesc_length));
1392 1392
1393 1393 pc = find_string(page_control_strings, page_control);
1394 1394 dprintf("\nMode sense(10) page 0x%x (%s):\n",
1395 1395 page_code, pc != NULL ? pc : "");
1396 1396 ddump("header:", (caddr_t)header,
1397 1397 MODE_HEADER_LENGTH_G1 + bdesc_length);
1398 1398
1399 1399 ddump("data:", page_data,
1400 1400 (length + sizeof (header->ms_header.length)) -
1401 1401 (MODE_HEADER_LENGTH_G1 + bdesc_length));
1402 1402
1403 1403 return (0);
1404 1404 }
1405 1405
1406 1406 if (pg->code != page_code) {
1407 1407 dprintf("\nMode sense(10) page 0x%x: incorrect page "
1408 1408 "code 0x%x\n", page_code, pg->code);
1409 1409 ddump("Mode sense(10):", mode_sense_buf, nbytes);
1410 1410 return (-1);
1411 1411 }
1412 1412
1413 1413 /*
1414 1414 * Accept up to "page_size" bytes of mode sense data. This allows us to
1415 1415 * accept both CCS and SCSI-2 structures, as long as we request the
1416 1416 * greater of the two.
1417 1417 */
1418 1418 maximum = page_size - sizeof (struct mode_page);
1419 1419 if (((int)pg->length) > maximum) {
1420 1420 dprintf("Mode sense(10) page 0x%x: incorrect page "
1421 1421 "length %d - expected max %d\n",
1422 1422 page_code, pg->length, maximum);
1423 1423 ddump("Mode sense(10):", mode_sense_buf,
1424 1424 nbytes);
1425 1425 return (-1);
1426 1426 }
1427 1427
1428 1428 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1429 1429
1430 1430 pc = find_string(page_control_strings, page_control);
1431 1431 dprintf("\nMode sense(10) page 0x%x (%s):\n", page_code,
1432 1432 pc != NULL ? pc : "");
1433 1433 ddump("header:", (caddr_t)header,
1434 1434 sizeof (struct scsi_ms_header_g1));
1435 1435 ddump("data:", page_data, MODESENSE_PAGE_LEN(pg));
1436 1436
1437 1437 return (0);
1438 1438 }
1439 1439
1440 1440 /*
1441 1441 * Execute a uscsi mode select command.
1442 1442 */
1443 1443 int
1444 1444 uscsi_mode_select(int fd, int page_code, int options, caddr_t page_data,
1445 1445 int page_size, struct scsi_ms_header *header, void *rqbuf, int *rqblen)
1446 1446 {
1447 1447 caddr_t mode_select_buf;
1448 1448 int nbytes;
1449 1449 struct uscsi_cmd ucmd;
1450 1450 union scsi_cdb cdb;
1451 1451 int status;
1452 1452 char *s;
1453 1453
1454 1454 assert(((struct mode_page *)page_data)->ps == 0);
1455 1455 assert(header->ms_header.length == 0);
1456 1456 assert(header->ms_header.device_specific == 0);
1457 1457 assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
1458 1458
1459 1459 nbytes = sizeof (struct scsi_ms_header) + page_size;
1460 1460 mode_select_buf = alloca((uint_t)nbytes);
1461 1461
1462 1462 /*
1463 1463 * Build the mode select data out of the header and page data This
1464 1464 * allows us to support devices which return either 0 or 1 block
1465 1465 * descriptors.
1466 1466 */
1467 1467 (void) memset(mode_select_buf, 0, nbytes);
1468 1468 nbytes = MODE_HEADER_LENGTH;
1469 1469 if (header->ms_header.bdesc_length ==
1470 1470 sizeof (struct block_descriptor)) {
1471 1471 nbytes += sizeof (struct block_descriptor);
1472 1472 }
1473 1473
1474 1474 s = find_string(mode_select_strings,
1475 1475 options & (MODE_SELECT_SP|MODE_SELECT_PF));
1476 1476 dprintf("\nMode select page 0x%x%s:\n", page_code,
1477 1477 s != NULL ? s : "");
1478 1478 ddump("header:", (caddr_t)header, nbytes);
1479 1479 ddump("data:", (caddr_t)page_data, page_size);
1480 1480
1481 1481 /*
1482 1482 * Put the header and data together
1483 1483 */
1484 1484 (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
1485 1485 (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
1486 1486 nbytes += page_size;
1487 1487
1488 1488 /*
1489 1489 * Build and execute the uscsi ioctl
1490 1490 */
1491 1491 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1492 1492 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1493 1493 cdb.scc_cmd = SCMD_MODE_SELECT;
1494 1494 FORMG0COUNT(&cdb, (uchar_t)nbytes);
1495 1495 cdb.cdb_opaque[1] = (uchar_t)options;
1496 1496 ucmd.uscsi_cdb = (caddr_t)&cdb;
1497 1497 ucmd.uscsi_cdblen = CDB_GROUP0;
1498 1498 ucmd.uscsi_bufaddr = mode_select_buf;
1499 1499 ucmd.uscsi_buflen = nbytes;
1500 1500 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1501 1501
1502 1502 if (status)
1503 1503 dprintf("Mode select page 0x%x failed\n", page_code);
1504 1504
1505 1505 return (status);
1506 1506 }
1507 1507
1508 1508 /*
1509 1509 * Execute a uscsi mode select(10) command.
1510 1510 */
1511 1511 int
1512 1512 uscsi_mode_select_10(int fd, int page_code, int options,
1513 1513 caddr_t page_data, int page_size, struct scsi_ms_header_g1 *header,
1514 1514 void *rqbuf, int *rqblen)
1515 1515 {
1516 1516 caddr_t mode_select_buf;
1517 1517 int nbytes;
1518 1518 struct uscsi_cmd ucmd;
1519 1519 union scsi_cdb cdb;
1520 1520 int status;
1521 1521 char *s;
1522 1522
1523 1523 assert(((struct mode_page *)page_data)->ps == 0);
1524 1524 assert(header->ms_header.length == 0);
1525 1525 assert(header->ms_header.device_specific == 0);
1526 1526 assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
1527 1527
1528 1528 nbytes = sizeof (struct scsi_ms_header_g1) + page_size;
1529 1529 mode_select_buf = alloca((uint_t)nbytes);
1530 1530
1531 1531 /*
1532 1532 * Build the mode select data out of the header and page data
1533 1533 * This allows us to support devices which return either
1534 1534 * 0 or 1 block descriptors.
1535 1535 */
1536 1536 (void) memset(mode_select_buf, 0, nbytes);
1537 1537 nbytes = sizeof (struct mode_header_g1);
1538 1538 if (BE_16(header->ms_header.bdesc_length) ==
1539 1539 sizeof (struct block_descriptor)) {
1540 1540 nbytes += sizeof (struct block_descriptor);
1541 1541 }
1542 1542
1543 1543 /*
1544 1544 * Dump the structures
1545 1545 */
1546 1546 s = find_string(mode_select_strings,
1547 1547 options & (MODE_SELECT_SP|MODE_SELECT_PF));
1548 1548 dprintf("\nMode select(10) page 0x%x%s:\n", page_code,
1549 1549 s != NULL ? s : "");
1550 1550 ddump("header:", (caddr_t)header, nbytes);
1551 1551 ddump("data:", (caddr_t)page_data, page_size);
1552 1552
1553 1553 /*
1554 1554 * Put the header and data together
1555 1555 */
1556 1556 (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
1557 1557 (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
1558 1558 nbytes += page_size;
1559 1559
1560 1560 /*
1561 1561 * Build and execute the uscsi ioctl
1562 1562 */
1563 1563 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1564 1564 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1565 1565 cdb.scc_cmd = SCMD_MODE_SELECT_G1;
1566 1566 FORMG1COUNT(&cdb, (uint16_t)nbytes);
1567 1567 cdb.cdb_opaque[1] = (uchar_t)options;
1568 1568 ucmd.uscsi_cdb = (caddr_t)&cdb;
1569 1569 ucmd.uscsi_cdblen = CDB_GROUP1;
1570 1570 ucmd.uscsi_bufaddr = mode_select_buf;
1571 1571 ucmd.uscsi_buflen = nbytes;
1572 1572 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1573 1573
1574 1574 if (status)
1575 1575 dprintf("Mode select(10) page 0x%x failed\n", page_code);
1576 1576
1577 1577 return (status);
1578 1578 }
1579 1579
1580 1580 int
1581 1581 uscsi_log_sense(int fd, int page_code, int page_control, caddr_t page_data,
1582 1582 int page_size, void *rqbuf, int *rqblen)
1583 1583 {
1584 1584 caddr_t log_sense_buf;
1585 1585 scsi_log_header_t *hdr;
1586 1586 struct uscsi_cmd ucmd;
1587 1587 union scsi_cdb cdb;
1588 1588 int status;
1589 1589 ushort_t len;
1590 1590 char *pc;
1591 1591
1592 1592 assert(page_size >= 0 && page_size < UINT16_MAX);
1593 1593 assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1594 1594 page_control == PC_DEFAULT || page_control == PC_SAVED);
1595 1595
1596 1596 if (page_size < sizeof (scsi_log_header_t))
1597 1597 return (-1);
1598 1598
1599 1599 log_sense_buf = alloca((uint_t)page_size);
1600 1600
1601 1601 /*
1602 1602 * Build and execute the uscsi ioctl
1603 1603 */
1604 1604 (void) memset(log_sense_buf, 0, page_size);
1605 1605 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1606 1606 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1607 1607 cdb.scc_cmd = SCMD_LOG_SENSE_G1;
1608 1608 FORMG1COUNT(&cdb, (uint16_t)page_size);
1609 1609 cdb.cdb_opaque[2] = page_control | page_code;
1610 1610 ucmd.uscsi_cdb = (caddr_t)&cdb;
1611 1611 ucmd.uscsi_cdblen = CDB_GROUP1;
1612 1612 ucmd.uscsi_bufaddr = log_sense_buf;
1613 1613 ucmd.uscsi_buflen = page_size;
1614 1614 status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1615 1615 if (status) {
1616 1616 dprintf("Log sense page 0x%x failed\n", page_code);
1617 1617 return (-1);
1618 1618 }
1619 1619
1620 1620 /*
1621 1621 * Verify that the returned data looks reasonable, then copy it into the
1622 1622 * user's buffer.
1623 1623 */
1624 1624 hdr = (scsi_log_header_t *)log_sense_buf;
1625 1625
1626 1626 /*
1627 1627 * Ensure we have a host-understandable length field
1628 1628 */
1629 1629 len = BE_16(hdr->lh_length);
1630 1630
1631 1631 if (hdr->lh_code != page_code) {
1632 1632 dprintf("\nLog sense page 0x%x: incorrect page code 0x%x\n",
1633 1633 page_code, hdr->lh_code);
1634 1634 ddump("Log sense:", log_sense_buf, page_size);
1635 1635 return (-1);
1636 1636 }
1637 1637
1638 1638 ddump("LOG SENSE RAW OUTPUT", log_sense_buf,
1639 1639 sizeof (scsi_log_header_t) + len);
1640 1640
1641 1641 /*
1642 1642 * Accept up to "page_size" bytes of mode sense data. This allows us to
1643 1643 * accept both CCS and SCSI-2 structures, as long as we request the
1644 1644 * greater of the two.
1645 1645 */
1646 1646 (void) memcpy(page_data, (caddr_t)hdr, len +
1647 1647 sizeof (scsi_log_header_t));
1648 1648
1649 1649 pc = find_string(page_control_strings, page_control);
1650 1650 dprintf("\nLog sense page 0x%x (%s):\n", page_code,
1651 1651 pc != NULL ? pc : "");
1652 1652 ddump("header:", (caddr_t)hdr,
1653 1653 sizeof (scsi_log_header_t));
1654 1654 ddump("data:", (caddr_t)hdr +
1655 1655 sizeof (scsi_log_header_t), len);
1656 1656
1657 1657 return (0);
1658 1658 }
|
↓ open down ↓ |
624 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX