1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * This file contains the routines for embedded scsi disks
27 */
28 #include "global.h"
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/ioctl.h>
33 #include <sys/uio.h>
34 #include <sys/fcntl.h>
35 #include <errno.h>
36 #include <memory.h>
37 #include <malloc.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <values.h>
41 #include <sys/byteorder.h>
42
43
44
45 #include "startup.h"
46 #include "scsi_com.h"
47 #include "misc.h"
48 #include "ctlr_scsi.h"
49 #include "analyze.h"
50 #include "param.h"
51 #include "io.h"
52
53
54 #ifndef DAD_MODE_CACHE_CCS
55 #define DAD_MODE_CACHE_CCS 0x38
56 #endif /* DAD_MODE_CACHE_CCS */
57
58 /* format defect header bits */
59 #define FDH_FOV 0x80
60 #define FDH_IMMED 0x02
61
62 #define SENSE_LEN 20
63
64 #define RETRY_DELAY 5
65
66 #define PROGRESS_INDICATION_BASE 65536
67
68 #ifdef __STDC__
69 /*
70 * Local prototypes for ANSI C compilers
71 */
72 static int scsi_format(uint64_t, uint64_t, struct defect_list *);
73 static int scsi_raw_format(void);
74 static int scsi_ms_page8(int);
75 static int scsi_ms_page38(int);
76 static void scsi_convert_list_to_new(struct defect_list *,
77 struct scsi_defect_list *, int);
78 static char *scsi_find_command_name(uint_t);
79 static int chg_list_affects_page(struct chg_list *, int);
80 static void scsi_printerr(struct uscsi_cmd *,
81 struct scsi_extended_sense *, int);
82 static diskaddr_t
83 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen);
84
85 static void scsi_print_extended_sense(struct scsi_extended_sense *, int);
86 static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *, int);
87
88 static int test_until_ready(int fd);
89 static int uscsi_reserve_release(int, int);
90 static int check_support_for_defects(void);
91 static int scsi_format_without_defects(void);
92 static int scsi_ms_page1(int);
93 static int scsi_ms_page2(int);
94 static int scsi_ms_page3(int);
95 static int scsi_ms_page4(int);
96 static int scsi_repair(uint64_t, int);
97 static int scsi_read_defect_data(struct defect_list *, int);
98 static int scsi_ck_format(void);
99
100 #else /* __STDC__ */
101
102 static int scsi_format();
103 static int scsi_raw_format();
104 static int scsi_ms_page8();
105 static int scsi_ms_page38();
106 static void scsi_convert_list_to_new();
107 static char *scsi_find_command_name();
108 static int chg_list_affects_page();
109 static void scsi_printerr();
110 static diskaddr_t scsi_extract_sense_info_descr();
111 static void scsi_print_extended_sense();
112 static void scsi_print_descr_sense();
113
114 static int test_until_ready();
115
116 static int uscsi_reserve_release();
117 static int check_support_for_defects();
118 static int scsi_format_without_defects();
119 static int scsi_ms_page1();
120 static int scsi_ms_page2();
121 static int scsi_ms_page3();
122 static int scsi_ms_page4();
123 static int scsi_repair();
124 static int scsi_read_defect_data();
125 static int scsi_ck_format();
126
127 #endif /* __STDC__ */
128
129
130
131 struct ctlr_ops scsiops = {
132 scsi_rdwr,
133 scsi_ck_format,
134 scsi_format,
135 scsi_ex_man,
136 scsi_ex_cur,
137 scsi_repair,
138 0,
139 };
140
141 #define SCMD_UNKNOWN 0xff
142
143 /*
144 * Names of commands. Must have SCMD_UNKNOWN at end of list.
145 */
146 static struct scsi_command_name {
147 uchar_t command;
148 char *name;
149 } scsi_command_names[] = {
150 SCMD_FORMAT, "format",
151 SCMD_READ, "read",
152 SCMD_WRITE, "write",
153 SCMD_READ|SCMD_GROUP1, "read",
154 SCMD_WRITE|SCMD_GROUP1, "write",
155 SCMD_INQUIRY, "inquiry",
156 SCMD_MODE_SELECT, "mode select",
157 SCMD_MODE_SENSE, "mode sense",
158 SCMD_REASSIGN_BLOCK, "reassign block",
159 SCMD_READ_DEFECT_LIST, "read defect list",
160 SCMD_UNKNOWN, "unknown"
161 };
162
163
164 /*
165 * Strings for printing mode sense page control values
166 */
167 static slist_t page_control_strings[] = {
168 { "current", "", MODE_SENSE_PC_CURRENT },
169 { "changeable", "", MODE_SENSE_PC_CHANGEABLE },
170 { "default", "", MODE_SENSE_PC_DEFAULT },
171 { "saved", "", MODE_SENSE_PC_SAVED }
172 };
173
174 /*
175 * Strings for printing the mode select options
176 */
177 static slist_t mode_select_strings[] = {
178 { "", "", 0 },
179 { " (pf)", "", MODE_SELECT_PF },
180 { " (sp)", "", MODE_SELECT_SP },
181 { " (pf,sp)", "", MODE_SELECT_PF|MODE_SELECT_SP }
182 };
183
184 static int scsi_format_revolutions = 5;
185 static int scsi_format_timeout = 2*60*60; /* two hours */
186
187 /*
188 * READ DEFECT DATA commands is optional as per SCSI-2 spec.
189 * Hence check if the read_defect_data command fails with
190 * Invalid Opcode so that we can give a more meaningful message
191 * to the user.
192 */
193 #define INVALID_OPCODE 0x20
194
195 /*
196 * Read or write the disk.
197 */
198 int
scsi_rdwr(dir,fd,blkno,secnt,bufaddr,flags,xfercntp)199 scsi_rdwr(dir, fd, blkno, secnt, bufaddr, flags, xfercntp)
200 int dir;
201 int fd;
202 diskaddr_t blkno;
203 int secnt;
204 caddr_t bufaddr;
205 int flags;
206 int *xfercntp;
207 {
208 struct uscsi_cmd ucmd;
209 union scsi_cdb cdb;
210 int max_sectors;
211 int rc = 0;
212
213 /*
214 * If the max xfercnt hasn't been determined start with BUF_SECTS
215 * (currently 126 == 63K), otherwise use the xfercnt value
216 * my caller saved from the previous invocation.
217 */
218 if (xfercntp == NULL) {
219 max_sectors = BUF_SECTS;
220 } else if (*xfercntp == 0) {
221 max_sectors = BUF_SECTS;
222 *xfercntp = max_sectors;
223 } else {
224 max_sectors = *xfercntp;
225 }
226
227 /*
228 * Build and execute the uscsi ioctl. We build a group0
229 * or group1 command as necessary, since some targets
230 * do not support group1 commands.
231 */
232 while (secnt) {
233 int nsectors;
234
235 nsectors = (max_sectors < secnt) ? max_sectors : secnt;
236 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
237 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
238 cdb.scc_cmd = (dir == DIR_READ) ? SCMD_READ : SCMD_WRITE;
239 if (blkno < (2<<20) && nsectors <= 0xff) {
240 FORMG0ADDR(&cdb, blkno);
241 FORMG0COUNT(&cdb, nsectors);
242 ucmd.uscsi_cdblen = CDB_GROUP0;
243 } else {
244 if (blkno > 0xffffffff) {
245 FORMG4LONGADDR(&cdb, blkno);
246 FORMG4COUNT(&cdb, nsectors);
247 ucmd.uscsi_cdblen = CDB_GROUP4;
248 cdb.scc_cmd |= SCMD_GROUP4;
249 } else {
250 FORMG1ADDR(&cdb, blkno);
251 FORMG1COUNT(&cdb, nsectors);
252 ucmd.uscsi_cdblen = CDB_GROUP1;
253 cdb.scc_cmd |= SCMD_GROUP1;
254 }
255 }
256 ucmd.uscsi_cdb = (caddr_t)&cdb;
257 ucmd.uscsi_bufaddr = bufaddr;
258 ucmd.uscsi_buflen = nsectors * cur_blksz;
259 rc = uscsi_cmd(fd, &ucmd, flags);
260
261 if (rc != 0)
262 break;
263
264 /*
265 * check if partial DMA breakup required
266 * if so, reduce the request size by half and retry
267 * the last request
268 */
269 if (ucmd.uscsi_resid == ucmd.uscsi_buflen) {
270 max_sectors >>= 1;
271 if (max_sectors <= 0) {
272 rc = -1;
273 break;
274 }
275 continue;
276 }
277 if (ucmd.uscsi_resid != 0) {
278 rc = -1;
279 break;
280 }
281
282 blkno += nsectors;
283 secnt -= nsectors;
284 bufaddr += nsectors * cur_blksz;
285 }
286
287 /*
288 * If the xfercnt wasn't previously saved or if the
289 * new value is smaller than the old value, save the
290 * current value in my caller's save area.
291 */
292 if (xfercntp != NULL && max_sectors < *xfercntp) {
293 if (diag_msg)
294 err_print("reducing xfercnt %d %d\n",
295 *xfercntp, max_sectors);
296 *xfercntp = max_sectors;
297 }
298 return (rc);
299 }
300
301
302 /*
303 * Check to see if the disk has been formatted.
304 * If we are able to read the first track, we conclude that
305 * the disk has been formatted.
306 */
307 #ifdef i386
308 static int
309 #else /* i386 */
310 static int
311 #endif /* i386 */
scsi_ck_format(void)312 scsi_ck_format(void)
313 {
314 int status;
315
316 /*
317 * Try to read the first four blocks.
318 */
319 status = scsi_rdwr(DIR_READ, cur_file, (diskaddr_t)0, 4,
320 (caddr_t)cur_buf, F_SILENT, NULL);
321 return (!status);
322 }
323
324
325 /*
326 * Format the disk, the whole disk, and nothing but the disk.
327 */
328 /*ARGSUSED*/
329 static int
scsi_format(start,end,list)330 scsi_format(start, end, list)
331 uint64_t start; /* irrelevant for us */
332 uint64_t end;
333 struct defect_list *list;
334 {
335 struct uscsi_cmd ucmd;
336 union scsi_cdb cdb;
337 int status;
338 int flag;
339 char rawbuf[MAX_MODE_SENSE_SIZE];
340 struct scsi_inquiry *inq;
341 uint8_t fmt_prot_info;
342 uint8_t prot_field_usage;
343 uint8_t param_long_list = 1;
344 uint8_t fmt_long_param_header[8];
345
346 /*
347 * Determine if the target appears to be SCSI-2
348 * compliant. We handle mode sense/mode selects
349 * a little differently, depending upon CCS/SCSI-2
350 */
351 if (uscsi_inquiry(cur_file, rawbuf, sizeof (rawbuf))) {
352 err_print("Inquiry failed\n");
353 return (-1);
354 }
355 inq = (struct scsi_inquiry *)rawbuf;
356 flag = (inq->inq_rdf == RDF_SCSI2);
357
358 /*
359 * Reserve the scsi disk before performing mode select and
360 * format operations. This will keep other hosts, if any, from
361 * touching the disk while we are here.
362 */
363 if (uscsi_reserve_release(cur_file, SCMD_RESERVE)) {
364 err_print("Reserve failed\n");
365 return (-1);
366 }
367
368 /*
369 * Set up the various SCSI parameters specified before
370 * formatting the disk. Each routine handles the
371 * parameters relevant to a particular page.
372 * If no parameters are specified for a page, there's
373 * no need to do anything. Otherwise, issue a mode
374 * sense for that page. If a specified parameter
375 * differs from the drive's default value, and that
376 * parameter is not fixed, then issue a mode select to
377 * set the default value for the disk as specified
378 * in format.dat.
379 */
380 if (scsi_ms_page1(flag) || scsi_ms_page2(flag) ||
381 scsi_ms_page4(flag) || scsi_ms_page38(flag) ||
382 scsi_ms_page8(flag) || scsi_ms_page3(flag)) {
383 (void) uscsi_reserve_release(cur_file, SCMD_RELEASE);
384 return (-1);
385 }
386
387 /*
388 * If we're debugging the drive, dump every page
389 * the device supports, for thorough analysis.
390 */
391 if (option_msg && diag_msg) {
392 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT);
393 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT);
394 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED);
395 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE);
396 err_print("\n");
397 }
398
399 /*
400 * Determine the FMTPINFO field in format cdb, and the
401 * PROTECTION FIELD USAGE in the long parameter list, via
402 * the protection type input by users.
403 */
404 switch (prot_type) {
405 case PROT_TYPE_0:
406 fmt_prot_info = 0x00;
407 prot_field_usage = 0x00;
408 break;
409 case PROT_TYPE_1:
410 fmt_prot_info = 0x02;
411 prot_field_usage = 0x00;
412 break;
413 case PROT_TYPE_2:
414 fmt_prot_info = 0x03;
415 prot_field_usage = 0x00;
416 break;
417 case PROT_TYPE_3:
418 fmt_prot_info = 0x03;
419 prot_field_usage = 0x01;
420 break;
421 default:
422 fmt_print("invalid protection type\n");
423 return (-1);
424 }
425
426 /*
427 * Construct the uscsi format ioctl. The form depends
428 * upon the defect list the user extracted. If s/he
429 * extracted the "original" list, we format with only
430 * the P (manufacturer's defect) list. Otherwise, we
431 * format with both the P and the G (grown) list.
432 * To format with the P and G list, we set the fmtData
433 * bit, and send an empty list. To format with the
434 * P list only, we also set the cmpLst bit, meaning
435 * that the (empty) list we send down is the complete
436 * G list, thereby discarding the old G list..
437 */
438 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
439 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
440
441 cdb.scc_cmd = SCMD_FORMAT;
442 ucmd.uscsi_cdb = (caddr_t)&cdb;
443 ucmd.uscsi_cdblen = CDB_GROUP0;
444 cdb.cdb_opaque[1] = FPB_DATA;
445
446 /*
447 * Use the long parameter header in format command,
448 * and set the FMTPINFO field., when type 1, 2, 3.
449 */
450 cdb.cdb_opaque[1] |= (param_long_list << 5) | (fmt_prot_info << 6);
451 (void) memset((char *)fmt_long_param_header, 0,
452 sizeof (fmt_long_param_header));
453
454 /*
455 * Set the PROTECTION FIELD USAGE field in the long
456 * parameter list header, which combines with FMTINFO to
457 * determine the protection type.
458 * The PROTECTION INTERVAL EXPONET field is set default 0.
459 * So only one protection information interval is used
460 * in type 1, 2, 3.
461 */
462 fmt_long_param_header[0] = prot_field_usage;
463 fmt_long_param_header[1] = FDH_FOV | FDH_IMMED;
464 ucmd.uscsi_bufaddr = (caddr_t)fmt_long_param_header;
465 ucmd.uscsi_buflen = sizeof (fmt_long_param_header);
466
467 if ((list->list != NULL) && ((list->flags & LIST_PGLIST) == 0)) {
468 /*
469 * No G list. The empty list we send down
470 * is the complete list.
471 */
472 cdb.cdb_opaque[1] |= FPB_CMPLT;
473 }
474
475 /*
476 * Issue the format ioctl
477 */
478 fmt_print("Formatting...\n");
479 (void) fflush(stdout);
480 status = uscsi_cmd(cur_file, &ucmd,
481 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
482
483 /* check if format with immed was successfully accepted */
484 if (status == 0) {
485 /* immed accepted poll to completion */
486 status = test_until_ready(cur_file);
487 } else {
488 /* clear FOV and try again */
489 (void) memset((char *)fmt_long_param_header, 0,
490 sizeof (fmt_long_param_header));
491 fmt_long_param_header[0] = prot_field_usage;
492 fmt_long_param_header[1] = FDH_IMMED;
493 status = uscsi_cmd(cur_file, &ucmd,
494 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
495 if (status == 0) {
496 /* immed accepted, poll for progress */
497 status = test_until_ready(cur_file);
498 } else {
499 /*
500 * clear defect header and try basecase format
501 * command will hang until format complete
502 */
503 (void) memset((char *)fmt_long_param_header, 0,
504 sizeof (fmt_long_param_header));
505 fmt_long_param_header[0] = prot_field_usage;
506 status = uscsi_cmd(cur_file, &ucmd,
507 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
508 }
509 }
510
511 /* format failure check */
512 if (status != 0) {
513 /*
514 * formatting failed with fmtdata = 1.
515 * Check if defects list command is supported, if it
516 * is not supported then use fmtdata = 0.
517 * From SCSI Spec
518 * A FmtData bit of zero indicates, the
519 * source of defect information is not specified.
520 * else
521 * proceed to format using with mode selects.
522 */
523 if (!(check_support_for_defects())) {
524 status = scsi_format_without_defects();
525 }
526
527 if (status != 0) {
528 fmt_print("Format failed\n");
529 status = scsi_raw_format();
530 }
531 }
532 (void) uscsi_reserve_release(cur_file, SCMD_RELEASE);
533 return (status);
534 }
535
536 /*
537 * Format without any of the standard mode selects ignoring Grown defects list.
538 */
539 static int
scsi_raw_format(void)540 scsi_raw_format(void)
541 {
542 struct uscsi_cmd ucmd;
543 union scsi_cdb cdb;
544 struct scsi_defect_hdr defect_hdr;
545 int status;
546
547 fmt_print("\n"
548 "Retry of formatting operation without any of the standard\n"
549 "mode selects and ignoring disk's Grown Defects list. The\n"
550 "disk may be able to be reformatted this way if an earlier\n"
551 "formatting operation was interrupted by a power failure or\n"
552 "SCSI bus reset. The Grown Defects list will be recreated\n"
553 "by format verification and surface analysis.\n\n");
554
555 if (check("Retry format without mode selects and Grown Defects list")
556 != 0) {
557 return (-1);
558 }
559
560 /*
561 * Construct the uscsi format ioctl.
562 * To format with the P and G list, we set the fmtData
563 * and cmpLst bits to zero. To format with just the
564 * P list, we set the fmtData bit (meaning that we will
565 * send down a defect list in the data phase) and the
566 * cmpLst bit (meaning that the list we send is the
567 * complete G list), and a defect list header with
568 * a defect list length of zero.
569 */
570 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
571 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
572 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
573
574 cdb.scc_cmd = SCMD_FORMAT;
575 ucmd.uscsi_cdb = (caddr_t)&cdb;
576 ucmd.uscsi_cdblen = CDB_GROUP0;
577 /* No G list. Send empty defect list to replace it */
578 cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI;
579 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
580 ucmd.uscsi_buflen = sizeof (defect_hdr);
581 defect_hdr.descriptor = FDH_FOV | FDH_IMMED;
582
583 /*
584 * Issue the format ioctl
585 */
586 fmt_print("Formatting...\n");
587 (void) fflush(stdout);
588 status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
589
590 /* check if format with immed was successfully accepted */
591 if (status == 0) {
592 /* immed accepted pool to completion */
593 status = test_until_ready(cur_file);
594 } else {
595 /* clear defect header and try basecase format */
596 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
597 status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
598 }
599
600 /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */
601 return (status);
602 }
603
604 /*
605 * Estimate the time required for format operation (See 1163770).
606 * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm
607 * 5 revolutions (correspond to format_time keyword in format.dat file) are:
608 * 1 rev. for positioning
609 * 2 rev. for writing the track
610 * 1 rev. for positioning
611 * 1 rev. for cerifying the data integrity of the track
612 * The return value is a good estimate on the formatting time in minutes.
613 * Caller should add 50% margin to cover defect management overhead.
614 */
615 int
scsi_format_time()616 scsi_format_time()
617 {
618 struct mode_geometry *page4;
619 struct scsi_ms_header header;
620 int status;
621 int p4_cylinders, p4_heads, p4_rpm;
622 int length;
623 int format_time;
624 union {
625 struct mode_geometry page4;
626 char rawbuf[MAX_MODE_SENSE_SIZE];
627 } u_page4;
628
629
630 page4 = &u_page4.page4;
631 (void) memset(&u_page4, 0, sizeof (u_page4));
632
633 /*
634 * Issue a mode sense to determine the default parameters
635 * If it fail, try to use the saved or current instead.
636 */
637 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
638 MODE_SENSE_PC_DEFAULT, (caddr_t)page4,
639 MAX_MODE_SENSE_SIZE, &header);
640
641 if (status) {
642 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
643 MODE_SENSE_PC_SAVED, (caddr_t)page4,
644 MAX_MODE_SENSE_SIZE, &header);
645 }
646 if (status) {
647 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
648 MODE_SENSE_PC_CURRENT, (caddr_t)page4,
649 MAX_MODE_SENSE_SIZE, &header);
650 }
651 if (status) {
652 return (0);
653 }
654
655 /*
656 * We only need the common subset between the CCS
657 * and SCSI-2 structures, so we can treat both
658 * cases identically.
659 */
660 length = MODESENSE_PAGE_LEN(page4);
661 if (length < MIN_PAGE4_LEN) {
662 return (0);
663 }
664
665 page4->rpm = BE_16(page4->rpm);
666 p4_cylinders = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) +
667 page4->cyl_lb;
668 p4_heads = page4->heads;
669 p4_rpm = page4->rpm;
670
671 /*
672 * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600.
673 */
674 if (p4_rpm < MIN_RPM || p4_rpm > MAX_RPM) {
675 err_print("Mode sense page(4) reports rpm value as %d,"
676 " adjusting it to %d\n", p4_rpm, AVG_RPM);
677 p4_rpm = AVG_RPM;
678 }
679
680 if (p4_cylinders <= 0 || p4_heads <= 0)
681 return (0);
682
683 format_time = ((scsi_format_revolutions * p4_heads *
684 p4_cylinders) + p4_rpm) / p4_rpm;
685
686 if (option_msg && diag_msg) {
687 err_print(" pcyl: %d\n", p4_cylinders);
688 err_print(" heads: %d\n", p4_heads);
689 err_print(" rpm: %d\n", p4_rpm);
690 err_print("format_time: %d minutes\n", format_time);
691 }
692 return (format_time);
693 }
694
695 /*
696 * Check disk error recovery parameters via mode sense.
697 * Issue a mode select if we need to change something.
698 */
699 /*ARGSUSED*/
700 static int
scsi_ms_page1(scsi2_flag)701 scsi_ms_page1(scsi2_flag)
702 int scsi2_flag;
703 {
704 struct mode_err_recov *page1;
705 struct mode_err_recov *fixed;
706 struct scsi_ms_header header;
707 struct scsi_ms_header fixed_hdr;
708 int status;
709 int tmp1, tmp2;
710 int flag;
711 int length;
712 int sp_flags;
713 union {
714 struct mode_err_recov page1;
715 char rawbuf[MAX_MODE_SENSE_SIZE];
716 } u_page1, u_fixed;
717
718
719 page1 = &u_page1.page1;
720 fixed = &u_fixed.page1;
721
722 /*
723 * If debugging, issue mode senses on the default and
724 * current values.
725 */
726 if (option_msg && diag_msg) {
727 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
728 MODE_SENSE_PC_DEFAULT, (caddr_t)page1,
729 MAX_MODE_SENSE_SIZE, &header);
730 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
731 MODE_SENSE_PC_CURRENT, (caddr_t)page1,
732 MAX_MODE_SENSE_SIZE, &header);
733 }
734
735 /*
736 * Issue a mode sense to determine the saved parameters
737 * If the saved values fail, use the current instead.
738 */
739 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
740 MODE_SENSE_PC_SAVED, (caddr_t)page1,
741 MAX_MODE_SENSE_SIZE, &header);
742 if (status) {
743 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
744 MODE_SENSE_PC_CURRENT, (caddr_t)page1,
745 MAX_MODE_SENSE_SIZE, &header);
746 if (status) {
747 return (0);
748 }
749 }
750
751 /*
752 * We only need the common subset between the CCS
753 * and SCSI-2 structures, so we can treat both
754 * cases identically. Whatever the drive gives
755 * us, we return to the drive in the mode select,
756 * delta'ed by whatever we want to change.
757 */
758 length = MODESENSE_PAGE_LEN(page1);
759 if (length < MIN_PAGE1_LEN) {
760 return (0);
761 }
762
763 /*
764 * Ask for changeable parameters.
765 */
766 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
767 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
768 MAX_MODE_SENSE_SIZE, &fixed_hdr);
769 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE1_LEN) {
770 return (0);
771 }
772
773 /*
774 * We need to issue a mode select only if one or more
775 * parameters need to be changed, and those parameters
776 * are flagged by the drive as changeable.
777 */
778 flag = 0;
779 tmp1 = page1->read_retry_count;
780 tmp2 = page1->write_retry_count;
781 if (cur_dtype->dtype_options & SUP_READ_RETRIES &&
782 fixed->read_retry_count != 0) {
783 flag |= (page1->read_retry_count !=
784 cur_dtype->dtype_read_retries);
785 page1->read_retry_count = cur_dtype->dtype_read_retries;
786 }
787 if (length > 8) {
788 if (cur_dtype->dtype_options & SUP_WRITE_RETRIES &&
789 fixed->write_retry_count != 0) {
790 flag |= (page1->write_retry_count !=
791 cur_dtype->dtype_write_retries);
792 page1->write_retry_count =
793 cur_dtype->dtype_write_retries;
794 }
795 }
796 /*
797 * Report any changes so far...
798 */
799 if (flag && option_msg) {
800 fmt_print(
801 "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n",
802 page1->read_retry_count, tmp1,
803 page1->write_retry_count, tmp2);
804 }
805 /*
806 * Apply any changes requested via the change list method
807 */
808 flag |= apply_chg_list(DAD_MODE_ERR_RECOV, length,
809 (uchar_t *)page1, (uchar_t *)fixed,
810 cur_dtype->dtype_chglist);
811 /*
812 * If no changes required, do not issue a mode select
813 */
814 if (flag == 0) {
815 return (0);
816 }
817 /*
818 * We always want to set the Page Format bit for mode
819 * selects. Set the Save Page bit if the drive indicates
820 * that it can save this page via the mode sense.
821 */
822 sp_flags = MODE_SELECT_PF;
823 if (page1->mode_page.ps) {
824 sp_flags |= MODE_SELECT_SP;
825 }
826 page1->mode_page.ps = 0;
827 header.mode_header.length = 0;
828 header.mode_header.device_specific = 0;
829 status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV,
830 sp_flags, (caddr_t)page1, length, &header);
831 if (status && (sp_flags & MODE_SELECT_SP)) {
832 /* If failed, try not saving mode select params. */
833 sp_flags &= ~MODE_SELECT_SP;
834 status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV,
835 sp_flags, (caddr_t)page1, length, &header);
836 }
837 if (status && option_msg) {
838 err_print("\
839 Warning: Using default error recovery parameters.\n\n");
840 }
841
842 /*
843 * If debugging, issue mode senses on the current and
844 * saved values, so we can see the result of the mode
845 * selects.
846 */
847 if (option_msg && diag_msg) {
848 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
849 MODE_SENSE_PC_CURRENT, (caddr_t)page1,
850 MAX_MODE_SENSE_SIZE, &header);
851 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
852 MODE_SENSE_PC_SAVED, (caddr_t)page1,
853 MAX_MODE_SENSE_SIZE, &header);
854 }
855
856 return (0);
857 }
858
859 /*
860 * Check disk disconnect/reconnect parameters via mode sense.
861 * Issue a mode select if we need to change something.
862 */
863 /*ARGSUSED*/
864 static int
scsi_ms_page2(scsi2_flag)865 scsi_ms_page2(scsi2_flag)
866 int scsi2_flag;
867 {
868 struct mode_disco_reco *page2;
869 struct mode_disco_reco *fixed;
870 struct scsi_ms_header header;
871 struct scsi_ms_header fixed_hdr;
872 int status;
873 int flag;
874 int length;
875 int sp_flags;
876 union {
877 struct mode_disco_reco page2;
878 char rawbuf[MAX_MODE_SENSE_SIZE];
879 } u_page2, u_fixed;
880
881 page2 = &u_page2.page2;
882 fixed = &u_fixed.page2;
883
884 /*
885 * If debugging, issue mode senses on the default and
886 * current values.
887 */
888 if (option_msg && diag_msg) {
889 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
890 MODE_SENSE_PC_DEFAULT, (caddr_t)page2,
891 MAX_MODE_SENSE_SIZE, &header);
892 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
893 MODE_SENSE_PC_CURRENT, (caddr_t)page2,
894 MAX_MODE_SENSE_SIZE, &header);
895 }
896
897 /*
898 * Issue a mode sense to determine the saved parameters
899 * If the saved values fail, use the current instead.
900 */
901 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
902 MODE_SENSE_PC_SAVED, (caddr_t)page2,
903 MAX_MODE_SENSE_SIZE, &header);
904 if (status) {
905 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
906 MODE_SENSE_PC_CURRENT, (caddr_t)page2,
907 MAX_MODE_SENSE_SIZE, &header);
908 if (status) {
909 return (0);
910 }
911 }
912
913 /*
914 * We only need the common subset between the CCS
915 * and SCSI-2 structures, so we can treat both
916 * cases identically. Whatever the drive gives
917 * us, we return to the drive in the mode select,
918 * delta'ed by whatever we want to change.
919 */
920 length = MODESENSE_PAGE_LEN(page2);
921 if (length < MIN_PAGE2_LEN) {
922 return (0);
923 }
924
925 /*
926 * Ask for changeable parameters.
927 */
928 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
929 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
930 MAX_MODE_SENSE_SIZE, &fixed_hdr);
931 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE2_LEN) {
932 return (0);
933 }
934
935 /*
936 * We need to issue a mode select only if one or more
937 * parameters need to be changed, and those parameters
938 * are flagged by the drive as changeable.
939 */
940 flag = 0;
941 /*
942 * Apply any changes requested via the change list method
943 */
944 flag |= apply_chg_list(MODEPAGE_DISCO_RECO, length,
945 (uchar_t *)page2, (uchar_t *)fixed,
946 cur_dtype->dtype_chglist);
947 /*
948 * If no changes required, do not issue a mode select
949 */
950 if (flag == 0) {
951 return (0);
952 }
953 /*
954 * We always want to set the Page Format bit for mode
955 * selects. Set the Save Page bit if the drive indicates
956 * that it can save this page via the mode sense.
957 */
958 sp_flags = MODE_SELECT_PF;
959 if (page2->mode_page.ps) {
960 sp_flags |= MODE_SELECT_SP;
961 }
962 page2->mode_page.ps = 0;
963 header.mode_header.length = 0;
964 header.mode_header.device_specific = 0;
965 status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO,
966 MODE_SELECT_SP, (caddr_t)page2, length, &header);
967 if (status && (sp_flags & MODE_SELECT_SP)) {
968 /* If failed, try not saving mode select params. */
969 sp_flags &= ~MODE_SELECT_SP;
970 status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO,
971 sp_flags, (caddr_t)page2, length, &header);
972 }
973 if (status && option_msg) {
974 err_print("Warning: Using default .\n\n");
975 }
976
977 /*
978 * If debugging, issue mode senses on the current and
979 * saved values, so we can see the result of the mode
980 * selects.
981 */
982 if (option_msg && diag_msg) {
983 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
984 MODE_SENSE_PC_CURRENT, (caddr_t)page2,
985 MAX_MODE_SENSE_SIZE, &header);
986 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
987 MODE_SENSE_PC_SAVED, (caddr_t)page2,
988 MAX_MODE_SENSE_SIZE, &header);
989 }
990
991 return (0);
992 }
993
994 /*
995 * Check disk format parameters via mode sense.
996 * Issue a mode select if we need to change something.
997 */
998 /*ARGSUSED*/
999 static int
scsi_ms_page3(scsi2_flag)1000 scsi_ms_page3(scsi2_flag)
1001 int scsi2_flag;
1002 {
1003 struct mode_format *page3;
1004 struct mode_format *fixed;
1005 struct scsi_ms_header header;
1006 struct scsi_ms_header fixed_hdr;
1007 int status;
1008 int tmp1, tmp2, tmp3;
1009 int tmp4, tmp5, tmp6;
1010 int flag;
1011 int length;
1012 int sp_flags;
1013 union {
1014 struct mode_format page3;
1015 char rawbuf[MAX_MODE_SENSE_SIZE];
1016 } u_page3, u_fixed;
1017
1018
1019 page3 = &u_page3.page3;
1020 fixed = &u_fixed.page3;
1021
1022 /*
1023 * If debugging, issue mode senses on the default and
1024 * current values.
1025 */
1026 if (option_msg && diag_msg) {
1027 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1028 MODE_SENSE_PC_DEFAULT, (caddr_t)page3,
1029 MAX_MODE_SENSE_SIZE, &header);
1030 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1031 MODE_SENSE_PC_CURRENT, (caddr_t)page3,
1032 MAX_MODE_SENSE_SIZE, &header);
1033 }
1034
1035 /*
1036 * Issue a mode sense to determine the saved parameters
1037 * If the saved values fail, use the current instead.
1038 */
1039 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1040 MODE_SENSE_PC_SAVED, (caddr_t)page3,
1041 MAX_MODE_SENSE_SIZE, &header);
1042 if (status) {
1043 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1044 MODE_SENSE_PC_CURRENT, (caddr_t)page3,
1045 MAX_MODE_SENSE_SIZE, &header);
1046 if (status) {
1047 return (0);
1048 }
1049 }
1050
1051 /*
1052 * We only need the common subset between the CCS
1053 * and SCSI-2 structures, so we can treat both
1054 * cases identically. Whatever the drive gives
1055 * us, we return to the drive in the mode select,
1056 * delta'ed by whatever we want to change.
1057 */
1058 length = MODESENSE_PAGE_LEN(page3);
1059 if (length < MIN_PAGE3_LEN) {
1060 return (0);
1061 }
1062
1063 /*
1064 * Ask for changeable parameters.
1065 */
1066 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1067 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
1068 MAX_MODE_SENSE_SIZE, &fixed_hdr);
1069 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE3_LEN) {
1070 return (0);
1071 }
1072
1073 /*
1074 * We need to issue a mode select only if one or more
1075 * parameters need to be changed, and those parameters
1076 * are flagged by the drive as changeable.
1077 */
1078 tmp1 = page3->track_skew;
1079 tmp2 = page3->cylinder_skew;
1080 tmp3 = page3->sect_track;
1081 tmp4 = page3->tracks_per_zone;
1082 tmp5 = page3->alt_tracks_vol;
1083 tmp6 = page3->alt_sect_zone;
1084
1085 flag = (page3->data_bytes_sect != cur_blksz);
1086 page3->data_bytes_sect = cur_blksz;
1087
1088 flag |= (page3->interleave != 1);
1089 page3->interleave = 1;
1090
1091 if (cur_dtype->dtype_options & SUP_CYLSKEW &&
1092 fixed->cylinder_skew != 0) {
1093 flag |= (page3->cylinder_skew != cur_dtype->dtype_cyl_skew);
1094 page3->cylinder_skew = cur_dtype->dtype_cyl_skew;
1095 }
1096 if (cur_dtype->dtype_options & SUP_TRKSKEW &&
1097 fixed->track_skew != 0) {
1098 flag |= (page3->track_skew != cur_dtype->dtype_trk_skew);
1099 page3->track_skew = cur_dtype->dtype_trk_skew;
1100 }
1101 if (cur_dtype->dtype_options & SUP_PSECT &&
1102 fixed->sect_track != 0) {
1103 flag |= (page3->sect_track != psect);
1104 page3->sect_track = (ushort_t)psect;
1105 }
1106 if (cur_dtype->dtype_options & SUP_TRKS_ZONE &&
1107 fixed->tracks_per_zone != 0) {
1108 flag |= (page3->tracks_per_zone != cur_dtype->dtype_trks_zone);
1109 page3->tracks_per_zone = cur_dtype->dtype_trks_zone;
1110 }
1111 if (cur_dtype->dtype_options & SUP_ASECT &&
1112 fixed->alt_sect_zone != 0) {
1113 flag |= (page3->alt_sect_zone != cur_dtype->dtype_asect);
1114 page3->alt_sect_zone = cur_dtype->dtype_asect;
1115 }
1116 if (cur_dtype->dtype_options & SUP_ATRKS &&
1117 fixed->alt_tracks_vol != 0) {
1118 flag |= (page3->alt_tracks_vol != cur_dtype->dtype_atrks);
1119 page3->alt_tracks_vol = cur_dtype->dtype_atrks;
1120 }
1121 /*
1122 * Notify user of any changes so far
1123 */
1124 if (flag && option_msg) {
1125 fmt_print("PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ",
1126 page3->track_skew, tmp1, page3->cylinder_skew, tmp2);
1127 fmt_print("sects/trk= %d (%d)\n", page3->sect_track, tmp3);
1128 fmt_print(" trks/zone= %d (%d) alt trks= %d (%d) ",
1129 page3->tracks_per_zone, tmp4,
1130 page3->alt_tracks_vol, tmp5);
1131 fmt_print("alt sects/zone= %d (%d)\n",
1132 page3->alt_sect_zone, tmp6);
1133 }
1134 /*
1135 * Apply any changes requested via the change list method
1136 */
1137 flag |= apply_chg_list(DAD_MODE_FORMAT, length,
1138 (uchar_t *)page3, (uchar_t *)fixed,
1139 cur_dtype->dtype_chglist);
1140 /*
1141 * If no changes required, do not issue a mode select
1142 */
1143 if (flag == 0) {
1144 return (0);
1145 }
1146 /*
1147 * Issue a mode select
1148 */
1149 /*
1150 * We always want to set the Page Format bit for mode
1151 * selects. Set the Save Page bit if the drive indicates
1152 * that it can save this page via the mode sense.
1153 */
1154 sp_flags = MODE_SELECT_PF;
1155 if (page3->mode_page.ps) {
1156 sp_flags |= MODE_SELECT_SP;
1157 }
1158 page3->mode_page.ps = 0;
1159 header.mode_header.length = 0;
1160 header.mode_header.device_specific = 0;
1161 status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT,
1162 MODE_SELECT_SP, (caddr_t)page3, length, &header);
1163 if (status && (sp_flags & MODE_SELECT_SP)) {
1164 /* If failed, try not saving mode select params. */
1165 sp_flags &= ~MODE_SELECT_SP;
1166 status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT,
1167 sp_flags, (caddr_t)page3, length, &header);
1168 }
1169 if (status && option_msg) {
1170 err_print("Warning: Using default drive format parameters.\n");
1171 err_print("Warning: Drive format may not be correct.\n\n");
1172 }
1173
1174 /*
1175 * If debugging, issue mode senses on the current and
1176 * saved values, so we can see the result of the mode
1177 * selects.
1178 */
1179 if (option_msg && diag_msg) {
1180 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1181 MODE_SENSE_PC_CURRENT, (caddr_t)page3,
1182 MAX_MODE_SENSE_SIZE, &header);
1183 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
1184 MODE_SENSE_PC_SAVED, (caddr_t)page3,
1185 MAX_MODE_SENSE_SIZE, &header);
1186 }
1187
1188 return (0);
1189 }
1190
1191 /*
1192 * Check disk geometry parameters via mode sense.
1193 * Issue a mode select if we need to change something.
1194 */
1195 /*ARGSUSED*/
1196 static int
scsi_ms_page4(scsi2_flag)1197 scsi_ms_page4(scsi2_flag)
1198 int scsi2_flag;
1199 {
1200 struct mode_geometry *page4;
1201 struct mode_geometry *fixed;
1202 struct scsi_ms_header header;
1203 struct scsi_ms_header fixed_hdr;
1204 int status;
1205 int tmp1, tmp2;
1206 int flag;
1207 int length;
1208 int sp_flags;
1209 union {
1210 struct mode_geometry page4;
1211 char rawbuf[MAX_MODE_SENSE_SIZE];
1212 } u_page4, u_fixed;
1213
1214 page4 = &u_page4.page4;
1215 fixed = &u_fixed.page4;
1216
1217 /*
1218 * If debugging, issue mode senses on the default and
1219 * current values.
1220 */
1221 if (option_msg && diag_msg) {
1222 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1223 MODE_SENSE_PC_DEFAULT, (caddr_t)page4,
1224 MAX_MODE_SENSE_SIZE, &header);
1225 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1226 MODE_SENSE_PC_CURRENT, (caddr_t)page4,
1227 MAX_MODE_SENSE_SIZE, &header);
1228 }
1229
1230 /*
1231 * Issue a mode sense to determine the saved parameters
1232 * If the saved values fail, use the current instead.
1233 */
1234 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1235 MODE_SENSE_PC_SAVED, (caddr_t)page4,
1236 MAX_MODE_SENSE_SIZE, &header);
1237 if (status) {
1238 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1239 MODE_SENSE_PC_CURRENT, (caddr_t)page4,
1240 MAX_MODE_SENSE_SIZE, &header);
1241 if (status) {
1242 return (0);
1243 }
1244 }
1245
1246 /*
1247 * We only need the common subset between the CCS
1248 * and SCSI-2 structures, so we can treat both
1249 * cases identically. Whatever the drive gives
1250 * us, we return to the drive in the mode select,
1251 * delta'ed by whatever we want to change.
1252 */
1253 length = MODESENSE_PAGE_LEN(page4);
1254 if (length < MIN_PAGE4_LEN) {
1255 return (0);
1256 }
1257
1258 /*
1259 * Ask for changeable parameters.
1260 */
1261 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1262 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
1263 MAX_MODE_SENSE_SIZE, &fixed_hdr);
1264 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE4_LEN) {
1265 return (0);
1266 }
1267
1268 /*
1269 * We need to issue a mode select only if one or more
1270 * parameters need to be changed, and those parameters
1271 * are flagged by the drive as changeable.
1272 */
1273 tmp1 = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + page4->cyl_lb;
1274 tmp2 = page4->heads;
1275
1276 flag = 0;
1277 if ((cur_dtype->dtype_options & SUP_PHEAD) && fixed->heads != 0) {
1278 flag |= (page4->heads != phead);
1279 page4->heads = phead;
1280 }
1281 /*
1282 * Notify user of changes so far
1283 */
1284 if (flag && option_msg) {
1285 fmt_print("PAGE 4: cylinders= %d heads= %d (%d)\n",
1286 tmp1, page4->heads, tmp2);
1287 }
1288 /*
1289 * Apply any changes requested via the change list method
1290 */
1291 flag |= apply_chg_list(DAD_MODE_GEOMETRY, length,
1292 (uchar_t *)page4, (uchar_t *)fixed,
1293 cur_dtype->dtype_chglist);
1294 /*
1295 * If no changes required, do not issue a mode select
1296 */
1297 if (flag == 0) {
1298 return (0);
1299 }
1300 /*
1301 * Issue a mode select
1302 */
1303 /*
1304 * We always want to set the Page Format bit for mode
1305 * selects. Set the Save Page bit if the drive indicates
1306 * that it can save this page via the mode sense.
1307 */
1308 sp_flags = MODE_SELECT_PF;
1309 if (page4->mode_page.ps) {
1310 sp_flags |= MODE_SELECT_SP;
1311 }
1312 page4->mode_page.ps = 0;
1313 header.mode_header.length = 0;
1314 header.mode_header.device_specific = 0;
1315 status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY,
1316 MODE_SELECT_SP, (caddr_t)page4, length, &header);
1317 if (status && (sp_flags & MODE_SELECT_SP)) {
1318 /* If failed, try not saving mode select params. */
1319 sp_flags &= ~MODE_SELECT_SP;
1320 status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY,
1321 sp_flags, (caddr_t)page4, length, &header);
1322 }
1323 if (status && option_msg) {
1324 err_print("Warning: Using default drive geometry.\n\n");
1325 }
1326
1327 /*
1328 * If debugging, issue mode senses on the current and
1329 * saved values, so we can see the result of the mode
1330 * selects.
1331 */
1332 if (option_msg && diag_msg) {
1333 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1334 MODE_SENSE_PC_CURRENT, (caddr_t)page4,
1335 MAX_MODE_SENSE_SIZE, &header);
1336 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
1337 MODE_SENSE_PC_SAVED, (caddr_t)page4,
1338 MAX_MODE_SENSE_SIZE, &header);
1339 }
1340
1341 return (0);
1342 }
1343
1344 /*
1345 * Check SCSI-2 disk cache parameters via mode sense.
1346 * Issue a mode select if we need to change something.
1347 */
1348 /*ARGSUSED*/
1349 static int
scsi_ms_page8(scsi2_flag)1350 scsi_ms_page8(scsi2_flag)
1351 int scsi2_flag;
1352 {
1353 struct mode_cache *page8;
1354 struct mode_cache *fixed;
1355 struct scsi_ms_header header;
1356 struct scsi_ms_header fixed_hdr;
1357 int status;
1358 int flag;
1359 int length;
1360 int sp_flags;
1361 union {
1362 struct mode_cache page8;
1363 char rawbuf[MAX_MODE_SENSE_SIZE];
1364 } u_page8, u_fixed;
1365
1366 page8 = &u_page8.page8;
1367 fixed = &u_fixed.page8;
1368
1369 /*
1370 * Only SCSI-2 devices support this page
1371 */
1372 if (!scsi2_flag) {
1373 return (0);
1374 }
1375
1376 /*
1377 * If debugging, issue mode senses on the default and
1378 * current values.
1379 */
1380 if (option_msg && diag_msg) {
1381 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1382 MODE_SENSE_PC_DEFAULT, (caddr_t)page8,
1383 MAX_MODE_SENSE_SIZE, &header);
1384 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1385 MODE_SENSE_PC_CURRENT, (caddr_t)page8,
1386 MAX_MODE_SENSE_SIZE, &header);
1387 }
1388
1389 /*
1390 * Issue a mode sense to determine the saved parameters
1391 * If the saved values fail, use the current instead.
1392 */
1393 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1394 MODE_SENSE_PC_SAVED, (caddr_t)page8,
1395 MAX_MODE_SENSE_SIZE, &header);
1396 if (status) {
1397 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1398 MODE_SENSE_PC_CURRENT, (caddr_t)page8,
1399 MAX_MODE_SENSE_SIZE, &header);
1400 if (status) {
1401 return (0);
1402 }
1403 }
1404
1405 /*
1406 * We only need the common subset between the CCS
1407 * and SCSI-2 structures, so we can treat both
1408 * cases identically. Whatever the drive gives
1409 * us, we return to the drive in the mode select,
1410 * delta'ed by whatever we want to change.
1411 */
1412 length = MODESENSE_PAGE_LEN(page8);
1413 if (length < MIN_PAGE8_LEN) {
1414 return (0);
1415 }
1416
1417 /*
1418 * Ask for changeable parameters.
1419 */
1420 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1421 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
1422 MAX_MODE_SENSE_SIZE, &fixed_hdr);
1423 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE8_LEN) {
1424 return (0);
1425 }
1426
1427 /*
1428 * We need to issue a mode select only if one or more
1429 * parameters need to be changed, and those parameters
1430 * are flagged by the drive as changeable.
1431 */
1432 flag = 0;
1433 /*
1434 * Apply any changes requested via the change list method
1435 */
1436 flag |= apply_chg_list(DAD_MODE_CACHE, length,
1437 (uchar_t *)page8, (uchar_t *)fixed,
1438 cur_dtype->dtype_chglist);
1439 /*
1440 * If no changes required, do not issue a mode select
1441 */
1442 if (flag == 0) {
1443 return (0);
1444 }
1445 /*
1446 * Issue a mode select
1447 */
1448 /*
1449 * We always want to set the Page Format bit for mode
1450 * selects. Set the Save Page bit if the drive indicates
1451 * that it can save this page via the mode sense.
1452 */
1453 sp_flags = MODE_SELECT_PF;
1454 if (page8->mode_page.ps) {
1455 sp_flags |= MODE_SELECT_SP;
1456 }
1457 page8->mode_page.ps = 0;
1458 header.mode_header.length = 0;
1459 header.mode_header.device_specific = 0;
1460 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE,
1461 sp_flags, (caddr_t)page8, length, &header);
1462 if (status && (sp_flags & MODE_SELECT_SP)) {
1463 /* If failed, try not saving mode select params. */
1464 sp_flags &= ~MODE_SELECT_SP;
1465 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE,
1466 sp_flags, (caddr_t)page8, length, &header);
1467 }
1468 if (status && option_msg) {
1469 err_print("\
1470 Warning: Using default SCSI-2 cache parameters.\n\n");
1471 }
1472
1473 /*
1474 * If debugging, issue mode senses on the current and
1475 * saved values, so we can see the result of the mode
1476 * selects.
1477 */
1478 if (option_msg && diag_msg) {
1479 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1480 MODE_SENSE_PC_CURRENT, (caddr_t)page8,
1481 MAX_MODE_SENSE_SIZE, &header);
1482 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
1483 MODE_SENSE_PC_SAVED, (caddr_t)page8,
1484 MAX_MODE_SENSE_SIZE, &header);
1485 }
1486
1487 return (0);
1488 }
1489
1490 /*
1491 * Check CCS disk cache parameters via mode sense.
1492 * Issue a mode select if we need to change something.
1493 */
1494 /*ARGSUSED*/
1495 static int
scsi_ms_page38(scsi2_flag)1496 scsi_ms_page38(scsi2_flag)
1497 int scsi2_flag;
1498 {
1499 struct mode_cache_ccs *page38;
1500 struct mode_cache_ccs *fixed;
1501 struct scsi_ms_header header;
1502 struct scsi_ms_header fixed_hdr;
1503 int status;
1504 int tmp1, tmp2, tmp3, tmp4;
1505 int flag;
1506 int length;
1507 int sp_flags;
1508 union {
1509 struct mode_cache_ccs page38;
1510 char rawbuf[MAX_MODE_SENSE_SIZE];
1511 } u_page38, u_fixed;
1512
1513 /*
1514 * First, determine if we need to look at page 38 at all.
1515 * Not all devices support it.
1516 */
1517 if (((cur_dtype->dtype_options & (SUP_CACHE | SUP_PREFETCH |
1518 SUP_CACHE_MIN | SUP_CACHE_MAX)) == 0) &&
1519 (!chg_list_affects_page(cur_dtype->dtype_chglist,
1520 0x38))) {
1521 return (0);
1522 }
1523
1524 page38 = &u_page38.page38;
1525 fixed = &u_fixed.page38;
1526
1527 /*
1528 * If debugging, issue mode senses on the default and
1529 * current values.
1530 */
1531 if (option_msg && diag_msg) {
1532 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1533 MODE_SENSE_PC_DEFAULT, (caddr_t)page38,
1534 MAX_MODE_SENSE_SIZE, &header);
1535 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1536 MODE_SENSE_PC_CURRENT, (caddr_t)page38,
1537 MAX_MODE_SENSE_SIZE, &header);
1538 }
1539
1540 /*
1541 * Issue a mode sense to determine the saved parameters
1542 * If the saved values fail, use the current instead.
1543 */
1544 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1545 MODE_SENSE_PC_SAVED, (caddr_t)page38,
1546 MAX_MODE_SENSE_SIZE, &header);
1547 if (status) {
1548 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1549 MODE_SENSE_PC_CURRENT, (caddr_t)page38,
1550 MAX_MODE_SENSE_SIZE, &header);
1551 if (status) {
1552 return (0);
1553 }
1554 }
1555
1556 /*
1557 * We only need the common subset between the CCS
1558 * and SCSI-2 structures, so we can treat both
1559 * cases identically. Whatever the drive gives
1560 * us, we return to the drive in the mode select,
1561 * delta'ed by whatever we want to change.
1562 */
1563 length = MODESENSE_PAGE_LEN(page38);
1564 if (length < MIN_PAGE38_LEN) {
1565 return (0);
1566 }
1567
1568 /*
1569 * Ask for changeable parameters.
1570 */
1571 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1572 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
1573 MAX_MODE_SENSE_SIZE, &fixed_hdr);
1574 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE38_LEN) {
1575 return (0);
1576 }
1577
1578 /*
1579 * We need to issue a mode select only if one or more
1580 * parameters need to be changed, and those parameters
1581 * are flagged by the drive as changeable.
1582 */
1583 tmp1 = page38->mode;
1584 tmp2 = page38->threshold;
1585 tmp3 = page38->min_prefetch;
1586 tmp4 = page38->max_prefetch;
1587
1588 flag = 0;
1589 if ((cur_dtype->dtype_options & SUP_CACHE) &&
1590 (fixed->mode & cur_dtype->dtype_cache) ==
1591 cur_dtype->dtype_cache) {
1592 flag |= (page38->mode != cur_dtype->dtype_cache);
1593 page38->mode = cur_dtype->dtype_cache;
1594 }
1595 if ((cur_dtype->dtype_options & SUP_PREFETCH) &&
1596 (fixed->threshold & cur_dtype->dtype_threshold) ==
1597 cur_dtype->dtype_threshold) {
1598 flag |= (page38->threshold != cur_dtype->dtype_threshold);
1599 page38->threshold = cur_dtype->dtype_threshold;
1600 }
1601 if ((cur_dtype->dtype_options & SUP_CACHE_MIN) &&
1602 (fixed->min_prefetch & cur_dtype->dtype_prefetch_min) ==
1603 cur_dtype->dtype_prefetch_min) {
1604 flag |= (page38->min_prefetch != cur_dtype->dtype_prefetch_min);
1605 page38->min_prefetch = cur_dtype->dtype_prefetch_min;
1606 }
1607 if ((cur_dtype->dtype_options & SUP_CACHE_MAX) &&
1608 (fixed->max_prefetch & cur_dtype->dtype_prefetch_max) ==
1609 cur_dtype->dtype_prefetch_max) {
1610 flag |= (page38->max_prefetch != cur_dtype->dtype_prefetch_max);
1611 page38->max_prefetch = cur_dtype->dtype_prefetch_max;
1612 }
1613 /*
1614 * Notify the user of changes up to this point
1615 */
1616 if (flag && option_msg) {
1617 fmt_print("PAGE 38: cache mode= 0x%x (0x%x)\n",
1618 page38->mode, tmp1);
1619 fmt_print(" min. prefetch multiplier= %d ",
1620 page38->min_multiplier);
1621 fmt_print("max. prefetch multiplier= %d\n",
1622 page38->max_multiplier);
1623 fmt_print(" threshold= %d (%d) ",
1624 page38->threshold, tmp2);
1625 fmt_print("min. prefetch= %d (%d) ",
1626 page38->min_prefetch, tmp3);
1627 fmt_print("max. prefetch= %d (%d)\n",
1628 page38->max_prefetch, tmp4);
1629 }
1630 /*
1631 * Apply any changes requested via the change list method
1632 */
1633 flag |= apply_chg_list(DAD_MODE_CACHE_CCS, length,
1634 (uchar_t *)page38, (uchar_t *)fixed,
1635 cur_dtype->dtype_chglist);
1636 /*
1637 * If no changes required, do not issue a mode select
1638 */
1639 if (flag == 0) {
1640 return (0);
1641 }
1642 /*
1643 * Issue a mode select
1644 *
1645 * We always want to set the Page Format bit for mode
1646 * selects. Set the Save Page bit if the drive indicates
1647 * that it can save this page via the mode sense.
1648 */
1649 sp_flags = MODE_SELECT_PF;
1650 if (page38->mode_page.ps) {
1651 sp_flags |= MODE_SELECT_SP;
1652 }
1653 page38->mode_page.ps = 0;
1654 header.mode_header.length = 0;
1655 header.mode_header.device_specific = 0;
1656 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS,
1657 sp_flags, (caddr_t)page38, length, &header);
1658 if (status && (sp_flags & MODE_SELECT_SP)) {
1659 /* If failed, try not saving mode select params. */
1660 sp_flags &= ~MODE_SELECT_SP;
1661 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS,
1662 sp_flags, (caddr_t)page38, length, &header);
1663 }
1664 if (status && option_msg) {
1665 err_print("Warning: Using default CCS cache parameters.\n\n");
1666 }
1667
1668 /*
1669 * If debugging, issue mode senses on the current and
1670 * saved values, so we can see the result of the mode
1671 * selects.
1672 */
1673 if (option_msg && diag_msg) {
1674 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1675 MODE_SENSE_PC_CURRENT, (caddr_t)page38,
1676 MAX_MODE_SENSE_SIZE, &header);
1677 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
1678 MODE_SENSE_PC_SAVED, (caddr_t)page38,
1679 MAX_MODE_SENSE_SIZE, &header);
1680 }
1681
1682 return (0);
1683 }
1684
1685
1686 /*
1687 * Extract the manufacturer's defect list.
1688 */
1689 int
scsi_ex_man(list)1690 scsi_ex_man(list)
1691 struct defect_list *list;
1692 {
1693 int i;
1694
1695 i = scsi_read_defect_data(list, DLD_MAN_DEF_LIST);
1696 if (i != 0)
1697 return (i);
1698 list->flags &= ~LIST_PGLIST;
1699 return (0);
1700 }
1701
1702 /*
1703 * Extract the current defect list.
1704 * For embedded scsi drives, this means both the manufacturer's (P)
1705 * and the grown (G) lists.
1706 */
1707 int
scsi_ex_cur(list)1708 scsi_ex_cur(list)
1709 struct defect_list *list;
1710 {
1711 int i;
1712
1713 i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST|DLD_MAN_DEF_LIST);
1714 if (i != 0)
1715 return (i);
1716 list->flags |= LIST_PGLIST;
1717 return (0);
1718 }
1719
1720
1721 /*
1722 * Extract the grown list only
1723 */
1724 int
scsi_ex_grown(list)1725 scsi_ex_grown(list)
1726 struct defect_list *list;
1727 {
1728 int i;
1729
1730 i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST);
1731 if (i != 0)
1732 return (i);
1733 list->flags |= LIST_PGLIST;
1734 return (0);
1735 }
1736
1737
1738 static int
scsi_read_defect_data(list,pglist_flags)1739 scsi_read_defect_data(list, pglist_flags)
1740 struct defect_list *list;
1741 int pglist_flags;
1742 {
1743 struct uscsi_cmd ucmd;
1744 char rqbuf[255];
1745 union scsi_cdb cdb;
1746 struct scsi_defect_list *defects;
1747 struct scsi_defect_list def_list;
1748 struct scsi_defect_hdr *hdr;
1749 int status;
1750 int nbytes;
1751 int len; /* returned defect list length */
1752 struct scsi_extended_sense *rq;
1753
1754 hdr = (struct scsi_defect_hdr *)&def_list;
1755
1756 /*
1757 * First get length of list by asking for the header only.
1758 */
1759 (void) memset((char *)&def_list, 0, sizeof (def_list));
1760
1761 /*
1762 * Build and execute the uscsi ioctl
1763 */
1764 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1765 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1766 (void) memset((char *)rqbuf, 0, 255);
1767 cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
1768 FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr));
1769 cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT;
1770 ucmd.uscsi_cdb = (caddr_t)&cdb;
1771 ucmd.uscsi_cdblen = CDB_GROUP1;
1772 ucmd.uscsi_bufaddr = (caddr_t)hdr;
1773 ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr);
1774 ucmd.uscsi_rqbuf = rqbuf;
1775 ucmd.uscsi_rqlen = sizeof (rqbuf);
1776 ucmd.uscsi_rqresid = sizeof (rqbuf);
1777 rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf;
1778
1779 status = uscsi_cmd(cur_file, &ucmd,
1780 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
1781
1782 if (status != 0) {
1783 /*
1784 * check if read_defect_list_is_supported.
1785 */
1786 if (ucmd.uscsi_rqstatus == STATUS_GOOD &&
1787 rq->es_key == KEY_ILLEGAL_REQUEST &&
1788 rq->es_add_code == INVALID_OPCODE) {
1789 err_print("\nWARNING: Current Disk does not support"
1790 " defect lists. \n");
1791 } else
1792 if (option_msg) {
1793 err_print("No %s defect list.\n",
1794 pglist_flags & DLD_GROWN_DEF_LIST ?
1795 "grown" : "manufacturer's");
1796 }
1797 return (-1);
1798 }
1799
1800 /*
1801 * Read the full list the second time
1802 */
1803 hdr->length = BE_16(hdr->length);
1804 len = hdr->length;
1805 nbytes = len + sizeof (struct scsi_defect_hdr);
1806
1807 defects = zalloc(nbytes);
1808 *(struct scsi_defect_hdr *)defects = *(struct scsi_defect_hdr *)hdr;
1809
1810 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1811 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1812 cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
1813 FORMG1COUNT(&cdb, nbytes);
1814 cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT;
1815 ucmd.uscsi_cdb = (caddr_t)&cdb;
1816 ucmd.uscsi_cdblen = CDB_GROUP1;
1817 ucmd.uscsi_bufaddr = (caddr_t)defects;
1818 ucmd.uscsi_buflen = nbytes;
1819 status = uscsi_cmd(cur_file, &ucmd,
1820 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
1821
1822 if (status) {
1823 err_print("can't read defect list 2nd time");
1824 destroy_data((char *)defects);
1825 return (-1);
1826 }
1827
1828 defects->length = BE_16(defects->length);
1829
1830 if (len != hdr->length) {
1831 err_print("not enough defects");
1832 destroy_data((char *)defects);
1833 return (-1);
1834 }
1835 scsi_convert_list_to_new(list, (struct scsi_defect_list *)defects,
1836 DLD_BFI_FORMAT);
1837 destroy_data((char *)defects);
1838 return (0);
1839 }
1840
1841
1842 /*
1843 * Map a block.
1844 */
1845 /*ARGSUSED*/
1846 static int
scsi_repair(bn,flag)1847 scsi_repair(bn, flag)
1848 uint64_t bn;
1849 int flag;
1850 {
1851 struct uscsi_cmd ucmd;
1852 union scsi_cdb cdb;
1853 struct scsi_reassign_blk defect_list;
1854
1855 /*
1856 * Build and execute the uscsi ioctl
1857 */
1858 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1859 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1860 (void) memset((char *)&defect_list, 0,
1861 sizeof (struct scsi_reassign_blk));
1862 cdb.scc_cmd = SCMD_REASSIGN_BLOCK;
1863 ucmd.uscsi_cdb = (caddr_t)&cdb;
1864 ucmd.uscsi_cdblen = CDB_GROUP0;
1865 ucmd.uscsi_bufaddr = (caddr_t)&defect_list;
1866 ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk);
1867 defect_list.length = sizeof (defect_list.defect);
1868 defect_list.length = BE_16(defect_list.length);
1869 defect_list.defect = bn;
1870 defect_list.defect = BE_32(defect_list.defect);
1871 return (uscsi_cmd(cur_file, &ucmd,
1872 (option_msg && diag_msg) ? F_NORMAL : F_SILENT));
1873 }
1874
1875 /*
1876 * Convert a SCSI-style defect list to our generic format.
1877 * We can handle different format lists.
1878 */
1879 static void
scsi_convert_list_to_new(list,def_list,list_format)1880 scsi_convert_list_to_new(list, def_list, list_format)
1881 struct defect_list *list;
1882 struct scsi_defect_list *def_list;
1883 int list_format;
1884 {
1885 register struct scsi_bfi_defect *old_defect, *old_defect1;
1886 register struct defect_entry *new_defect;
1887 register int len, new_len, obfi, nbfi;
1888 register int i;
1889 int old_cyl, new_cyl;
1890 unsigned char *cp;
1891
1892
1893 switch (list_format) {
1894
1895 case DLD_BFI_FORMAT:
1896 /*
1897 * Allocate space for the rest of the list.
1898 */
1899 len = def_list->length / sizeof (struct scsi_bfi_defect);
1900 old_defect = def_list->list;
1901 new_defect = (struct defect_entry *)
1902 zalloc(deflist_size(cur_blksz, len) *
1903 cur_blksz);
1904
1905 list->header.magicno = (uint_t)DEFECT_MAGIC;
1906 list->list = new_defect;
1907
1908 for (i = 0, new_len = 0; i < len; new_defect++, new_len++) {
1909 cp = (unsigned char *)old_defect;
1910 new_defect->cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
1911 new_defect->head = old_defect->head;
1912 new_defect->bfi = (int)old_defect->bytes_from_index;
1913 new_defect->bfi = BE_32(new_defect->bfi);
1914 new_defect->nbits = 0; /* size of defect */
1915 old_defect1 = old_defect++;
1916 i++;
1917 /*
1918 * Since we reached the end of the list, old_defect
1919 * now points to an invalid reference, since it got
1920 * incremented in the above operation. So we don't
1921 * need to proceed further. new_len needs to be
1922 * incremented to account for the last element.
1923 */
1924 if (i == len) {
1925 new_len++;
1926 break;
1927 }
1928 obfi = new_defect->bfi;
1929 nbfi = (int)old_defect->bytes_from_index;
1930 nbfi = BE_32(nbfi);
1931
1932 old_cyl = new_defect->cyl;
1933 cp = (unsigned char *)old_defect;
1934 new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
1935
1936
1937 /*
1938 * Merge adjacent contiguous defect entries into one
1939 * and update the length of the defect
1940 */
1941 while ((i < len) &&
1942 (old_cyl == new_cyl) &&
1943 (old_defect->head == old_defect1->head) &&
1944 (nbfi == (obfi + BITSPERBYTE))) {
1945 old_defect1 = old_defect++;
1946 cp = (unsigned char *)old_defect;
1947 new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
1948 obfi = (int)old_defect1->bytes_from_index;
1949 obfi = BE_32(obfi);
1950 nbfi = (int)old_defect->bytes_from_index;
1951 nbfi = BE_32(nbfi);
1952 new_defect->nbits += (8*BITSPERBYTE);
1953 i++;
1954 }
1955 }
1956
1957 list->header.count = new_len;
1958 break;
1959
1960 default:
1961 err_print("scsi_convert_list_to_new: can't deal with it\n");
1962 exit(0);
1963 /*NOTREACHED*/
1964 }
1965
1966 (void) checkdefsum(list, CK_MAKESUM);
1967 }
1968
1969
1970
1971 /*
1972 * Execute a command and determine the result.
1973 * Uses the "uscsi" ioctl interface, which is
1974 * fully supported.
1975 *
1976 * If the user wants request sense data to be returned
1977 * in case of error then , the "uscsi_cmd" structure
1978 * should have the request sense buffer allocated in
1979 * uscsi_rqbuf.
1980 *
1981 */
1982 int
uscsi_cmd(fd,ucmd,flags)1983 uscsi_cmd(fd, ucmd, flags)
1984 int fd;
1985 struct uscsi_cmd *ucmd;
1986 int flags;
1987 {
1988 struct scsi_extended_sense *rq;
1989 char rqbuf[255];
1990 int status;
1991 int rqlen;
1992 int timeout = 0;
1993
1994 /*
1995 * Set function flags for driver.
1996 */
1997 ucmd->uscsi_flags = USCSI_ISOLATE;
1998 if (flags & F_SILENT) {
1999 ucmd->uscsi_flags |= USCSI_SILENT;
2000 }
2001 if (flags & F_RQENABLE) {
2002 ucmd->uscsi_flags |= USCSI_RQENABLE;
2003 }
2004
2005 /*
2006 * If this command will perform a read, set the USCSI_READ flag
2007 */
2008 if (ucmd->uscsi_buflen > 0) {
2009 /*
2010 * uscsi_cdb is declared as a caddr_t, so any CDB
2011 * command byte with the MSB set will result in a
2012 * compiler error unless we cast to an unsigned value.
2013 */
2014 switch ((uint8_t)ucmd->uscsi_cdb[0]) {
2015 case SCMD_READ:
2016 case SCMD_READ|SCMD_GROUP1:
2017 case SCMD_READ|SCMD_GROUP4:
2018 case SCMD_MODE_SENSE:
2019 case SCMD_INQUIRY:
2020 case SCMD_READ_DEFECT_LIST:
2021 case SCMD_READ_CAPACITY:
2022 case SCMD_SVC_ACTION_IN_G4:
2023 ucmd->uscsi_flags |= USCSI_READ;
2024 break;
2025 }
2026 }
2027
2028 /*
2029 * Set timeout: 30 seconds for all commands except format
2030 */
2031 switch (ucmd->uscsi_cdb[0]) {
2032 case SCMD_FORMAT:
2033 if (ucmd->uscsi_timeout == 0) {
2034 ucmd->uscsi_timeout = scsi_format_timeout;
2035 /*
2036 * Get the timeout value computed using page4 geometry.
2037 * add 50% margin to cover defect management overhead.
2038 * add another 50% margin to have a safe timeout.
2039 * If it exceeds 2 hours then use this value.
2040 */
2041 if ((timeout = scsi_format_time()) > 0) {
2042 timeout *= 60; /* convert to seconds */
2043 timeout += timeout;
2044 /*
2045 * formatting drives with huge capacity
2046 * will cause these heuristics to come
2047 * up with times that overflow ~9 hours
2048 */
2049 if (timeout > SHRT_MAX)
2050 timeout = SHRT_MAX;
2051 if (timeout > scsi_format_timeout)
2052 ucmd->uscsi_timeout = timeout;
2053 }
2054 }
2055 if (option_msg && diag_msg) {
2056 err_print("format_timeout set to %d seconds, %d"
2057 " required\n", ucmd->uscsi_timeout, timeout);
2058 }
2059 break;
2060
2061 default:
2062 ucmd->uscsi_timeout = 30; /* 30 seconds */
2063 break;
2064 }
2065
2066 /*
2067 * Set up Request Sense buffer
2068 */
2069 ucmd->uscsi_flags |= USCSI_RQENABLE;
2070
2071 if (ucmd->uscsi_rqbuf == NULL) {
2072 ucmd->uscsi_rqbuf = rqbuf;
2073 ucmd->uscsi_rqlen = sizeof (rqbuf);
2074 ucmd->uscsi_rqresid = sizeof (rqbuf);
2075 }
2076 ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
2077
2078 /*
2079 * Clear global error state
2080 */
2081 media_error = 0;
2082
2083 /*
2084 * Execute the ioctl
2085 */
2086 status = ioctl(fd, USCSICMD, ucmd);
2087 if (status == 0 && ucmd->uscsi_status == 0) {
2088 return (status);
2089 }
2090
2091 /*
2092 * Check the status and return appropriate errors if the disk is
2093 * unavailable (could be formatting) or reserved (by other host).
2094 * In either case we can not talk to the disk now.
2095 */
2096 if (status == -1 && errno == EAGAIN) {
2097 disk_error = DISK_STAT_UNAVAILABLE;
2098 return (DSK_UNAVAILABLE);
2099 }
2100 if ((ucmd->uscsi_status & STATUS_MASK) == STATUS_RESERVATION_CONFLICT) {
2101 disk_error = DISK_STAT_RESERVED;
2102 return (DSK_RESERVED);
2103 }
2104 /*
2105 * Check for physically removed or completely unresponsive drive
2106 */
2107 if (status == -1 && !ucmd->uscsi_status && errno == EIO) {
2108 disk_error = DISK_STAT_UNAVAILABLE;
2109 return (DSK_UNAVAILABLE);
2110 }
2111
2112 /*
2113 * If an automatic Request Sense gave us valid
2114 * info about the error, we may be able to use
2115 * that to print a reasonable error msg.
2116 */
2117 if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) {
2118 if (option_msg && diag_msg) {
2119 err_print("No request sense for command %s\n",
2120 scsi_find_command_name(ucmd->uscsi_cdb[0]));
2121 }
2122 return (-1);
2123 }
2124 if (ucmd->uscsi_rqstatus != STATUS_GOOD) {
2125 if (option_msg && diag_msg) {
2126 err_print("Request sense status for command %s: 0x%x\n",
2127 scsi_find_command_name(ucmd->uscsi_cdb[0]),
2128 ucmd->uscsi_rqstatus);
2129 }
2130 return (-1);
2131 }
2132 rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf;
2133 rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid;
2134 if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN ||
2135 rq->es_class != CLASS_EXTENDED_SENSE ||
2136 rqlen < MIN_REQUEST_SENSE_LEN) {
2137 if (option_msg) {
2138 err_print("Request sense for command %s failed\n",
2139 scsi_find_command_name(ucmd->uscsi_cdb[0]));
2140 }
2141 if (option_msg && diag_msg) {
2142 err_print("Sense data:\n");
2143 dump("", (caddr_t)rqbuf, rqlen, HEX_ONLY);
2144 }
2145 if (errno == EIO) {
2146 disk_error = DISK_STAT_UNAVAILABLE;
2147 return (DSK_UNAVAILABLE);
2148 } else {
2149 return (-1);
2150 }
2151 }
2152
2153 /*
2154 * If the failed command is a Mode Select, and the
2155 * target is indicating that it has rounded one of
2156 * the mode select parameters, as defined in the SCSI-2
2157 * specification, then we should accept the command
2158 * as successful.
2159 */
2160 if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT) {
2161 if (rq->es_key == KEY_RECOVERABLE_ERROR &&
2162 rq->es_add_code == ROUNDED_PARAMETER &&
2163 rq->es_qual_code == 0) {
2164 return (0);
2165 }
2166 }
2167
2168 switch (rq->es_key) {
2169 case KEY_NOT_READY:
2170 disk_error = DISK_STAT_NOTREADY;
2171 break;
2172 case KEY_DATA_PROTECT:
2173 disk_error = DISK_STAT_DATA_PROTECT;
2174 break;
2175 }
2176
2177 if (flags & F_ALLERRS) {
2178 media_error = (rq->es_key == KEY_MEDIUM_ERROR);
2179 }
2180 if (!(flags & F_SILENT) || option_msg) {
2181 scsi_printerr(ucmd, rq, rqlen);
2182 }
2183 if ((rq->es_key != KEY_RECOVERABLE_ERROR) || (flags & F_ALLERRS)) {
2184 return (-1);
2185 }
2186
2187 if (status == -1 && errno == EIO) {
2188 disk_error = DISK_STAT_UNAVAILABLE;
2189 return (DSK_UNAVAILABLE);
2190 }
2191
2192 return (0);
2193 }
2194
2195
2196 /*
2197 * Execute a uscsi mode sense command.
2198 * This can only be used to return one page at a time.
2199 * Return the mode header/block descriptor and the actual
2200 * page data separately - this allows us to support
2201 * devices which return either 0 or 1 block descriptors.
2202 * Whatever a device gives us in the mode header/block descriptor
2203 * will be returned to it upon subsequent mode selects.
2204 */
2205 int
uscsi_mode_sense(fd,page_code,page_control,page_data,page_size,header)2206 uscsi_mode_sense(fd, page_code, page_control, page_data, page_size, header)
2207 int fd; /* file descriptor */
2208 int page_code; /* requested page number */
2209 int page_control; /* current, changeable, etc. */
2210 caddr_t page_data; /* place received data here */
2211 int page_size; /* size of page_data */
2212 struct scsi_ms_header *header; /* mode header/block descriptor */
2213 {
2214 caddr_t mode_sense_buf;
2215 struct mode_header *hdr;
2216 struct mode_page *pg;
2217 int nbytes;
2218 struct uscsi_cmd ucmd;
2219 union scsi_cdb cdb;
2220 int status;
2221 int maximum;
2222
2223 assert(page_size >= 0 && page_size < 256);
2224 assert(page_control == MODE_SENSE_PC_CURRENT ||
2225 page_control == MODE_SENSE_PC_CHANGEABLE ||
2226 page_control == MODE_SENSE_PC_DEFAULT ||
2227 page_control == MODE_SENSE_PC_SAVED);
2228 /*
2229 * Allocate a buffer for the mode sense headers
2230 * and mode sense data itself.
2231 */
2232 nbytes = sizeof (struct block_descriptor) +
2233 sizeof (struct mode_header) + page_size;
2234 nbytes = page_size;
2235 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
2236 err_print("cannot malloc %d bytes\n", nbytes);
2237 return (-1);
2238 }
2239
2240 /*
2241 * Build and execute the uscsi ioctl
2242 */
2243 (void) memset(mode_sense_buf, 0, nbytes);
2244 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2245 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2246 cdb.scc_cmd = SCMD_MODE_SENSE;
2247 FORMG0COUNT(&cdb, (uchar_t)nbytes);
2248 cdb.cdb_opaque[2] = page_control | page_code;
2249 ucmd.uscsi_cdb = (caddr_t)&cdb;
2250 ucmd.uscsi_cdblen = CDB_GROUP0;
2251 ucmd.uscsi_bufaddr = mode_sense_buf;
2252 ucmd.uscsi_buflen = nbytes;
2253 status = uscsi_cmd(fd, &ucmd,
2254 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2255 if (status) {
2256 if (option_msg) {
2257 err_print("Mode sense page 0x%x failed\n",
2258 page_code);
2259 }
2260 free(mode_sense_buf);
2261 return (-1);
2262 }
2263
2264 /*
2265 * Verify that the returned data looks reasonabled,
2266 * find the actual page data, and copy it into the
2267 * user's buffer. Copy the mode_header and block_descriptor
2268 * into the header structure, which can then be used to
2269 * return the same data to the drive when issuing a mode select.
2270 */
2271 hdr = (struct mode_header *)mode_sense_buf;
2272 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
2273 if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
2274 hdr->bdesc_length != 0) {
2275 if (option_msg) {
2276 err_print("\
2277 \nMode sense page 0x%x: block descriptor length %d incorrect\n",
2278 page_code, hdr->bdesc_length);
2279 if (diag_msg)
2280 dump("Mode sense: ", mode_sense_buf,
2281 nbytes, HEX_ONLY);
2282 }
2283 free(mode_sense_buf);
2284 return (-1);
2285 }
2286 (void) memcpy((caddr_t)header, mode_sense_buf,
2287 (int) (sizeof (struct mode_header) + hdr->bdesc_length));
2288 pg = (struct mode_page *)((ulong_t)mode_sense_buf +
2289 sizeof (struct mode_header) + hdr->bdesc_length);
2290 if (pg->code != page_code) {
2291 if (option_msg) {
2292 err_print("\
2293 \nMode sense page 0x%x: incorrect page code 0x%x\n",
2294 page_code, pg->code);
2295 if (diag_msg)
2296 dump("Mode sense: ", mode_sense_buf,
2297 nbytes, HEX_ONLY);
2298 }
2299 free(mode_sense_buf);
2300 return (-1);
2301 }
2302 /*
2303 * Accept up to "page_size" bytes of mode sense data.
2304 * This allows us to accept both CCS and SCSI-2
2305 * structures, as long as we request the greater
2306 * of the two.
2307 */
2308 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
2309 if (((int)pg->length) > maximum) {
2310 if (option_msg) {
2311 err_print("\
2312 Mode sense page 0x%x: incorrect page length %d - expected max %d\n",
2313 page_code, pg->length, maximum);
2314 if (diag_msg)
2315 dump("Mode sense: ", mode_sense_buf,
2316 nbytes, HEX_ONLY);
2317 }
2318 free(mode_sense_buf);
2319 return (-1);
2320 }
2321
2322 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
2323
2324 if (option_msg && diag_msg) {
2325 char *pc = find_string(page_control_strings, page_control);
2326 err_print("\nMode sense page 0x%x (%s):\n", page_code,
2327 pc != NULL ? pc : "");
2328 dump("header: ", (caddr_t)header,
2329 sizeof (struct scsi_ms_header), HEX_ONLY);
2330 dump("data: ", page_data,
2331 MODESENSE_PAGE_LEN(pg), HEX_ONLY);
2332 }
2333
2334 free(mode_sense_buf);
2335 return (0);
2336 }
2337
2338
2339 /*
2340 * Execute a uscsi mode select command.
2341 */
2342 int
uscsi_mode_select(fd,page_code,options,page_data,page_size,header)2343 uscsi_mode_select(fd, page_code, options, page_data, page_size, header)
2344 int fd; /* file descriptor */
2345 int page_code; /* mode select page */
2346 int options; /* save page/page format */
2347 caddr_t page_data; /* place received data here */
2348 int page_size; /* size of page_data */
2349 struct scsi_ms_header *header; /* mode header/block descriptor */
2350 {
2351 caddr_t mode_select_buf;
2352 int nbytes;
2353 struct uscsi_cmd ucmd;
2354 union scsi_cdb cdb;
2355 int status;
2356
2357 assert(((struct mode_page *)page_data)->ps == 0);
2358 assert(header->mode_header.length == 0);
2359 assert(header->mode_header.device_specific == 0);
2360 assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
2361
2362 /*
2363 * Allocate a buffer for the mode select header and data
2364 */
2365 nbytes = sizeof (struct block_descriptor) +
2366 sizeof (struct mode_header) + page_size;
2367 if ((mode_select_buf = malloc((uint_t)nbytes)) == NULL) {
2368 err_print("cannot malloc %d bytes\n", nbytes);
2369 return (-1);
2370 }
2371
2372 /*
2373 * Build the mode select data out of the header and page data
2374 * This allows us to support devices which return either
2375 * 0 or 1 block descriptors.
2376 */
2377 (void) memset(mode_select_buf, 0, nbytes);
2378 nbytes = sizeof (struct mode_header);
2379 if (header->mode_header.bdesc_length ==
2380 sizeof (struct block_descriptor)) {
2381 nbytes += sizeof (struct block_descriptor);
2382 }
2383
2384 /*
2385 * Dump the structures if anyone's interested
2386 */
2387 if (option_msg && diag_msg) {
2388 char *s;
2389 s = find_string(mode_select_strings,
2390 options & (MODE_SELECT_SP|MODE_SELECT_PF));
2391 err_print("\nMode select page 0x%x%s:\n", page_code,
2392 s != NULL ? s : "");
2393 dump("header: ", (caddr_t)header,
2394 nbytes, HEX_ONLY);
2395 dump("data: ", (caddr_t)page_data,
2396 page_size, HEX_ONLY);
2397 }
2398
2399 /*
2400 * Fix the code for byte ordering
2401 */
2402
2403 switch (page_code) {
2404 case DAD_MODE_ERR_RECOV:
2405 {
2406 struct mode_err_recov *pd;
2407 pd = (struct mode_err_recov *)(void *)page_data;
2408 pd->recovery_time_limit = BE_16(pd->recovery_time_limit);
2409 break;
2410 }
2411 case MODEPAGE_DISCO_RECO:
2412 {
2413 struct mode_disco_reco *pd;
2414 pd = (struct mode_disco_reco *)(void *)page_data;
2415 pd->bus_inactivity_limit = BE_16(pd->bus_inactivity_limit);
2416 pd->disconect_time_limit = BE_16(pd->disconect_time_limit);
2417 pd->connect_time_limit = BE_16(pd->connect_time_limit);
2418 pd->max_burst_size = BE_16(pd->max_burst_size);
2419 break;
2420 }
2421 case DAD_MODE_FORMAT:
2422 {
2423 struct mode_format *pd;
2424 pd = (struct mode_format *)(void *)page_data;
2425 pd->tracks_per_zone = BE_16(pd->tracks_per_zone);
2426 pd->alt_sect_zone = BE_16(pd->alt_sect_zone);
2427 pd->alt_tracks_zone = BE_16(pd->alt_tracks_zone);
2428 pd->alt_tracks_vol = BE_16(pd->alt_tracks_vol);
2429 pd->sect_track = BE_16(pd->sect_track);
2430 pd->data_bytes_sect = BE_16(pd->data_bytes_sect);
2431 pd->interleave = BE_16(pd->interleave);
2432 pd->track_skew = BE_16(pd->track_skew);
2433 pd->cylinder_skew = BE_16(pd->cylinder_skew);
2434 break;
2435 }
2436 case DAD_MODE_GEOMETRY:
2437 {
2438 struct mode_geometry *pd;
2439 pd = (struct mode_geometry *)(void *)page_data;
2440 pd->step_rate = BE_16(pd->step_rate);
2441 pd->rpm = BE_16(pd->rpm);
2442 break;
2443 }
2444 case DAD_MODE_CACHE:
2445 {
2446 struct mode_cache *pd;
2447 pd = (struct mode_cache *)(void *)page_data;
2448 pd->dis_prefetch_len = BE_16(pd->dis_prefetch_len);
2449 pd->min_prefetch = BE_16(pd->min_prefetch);
2450 pd->max_prefetch = BE_16(pd->max_prefetch);
2451 pd->prefetch_ceiling = BE_16(pd->prefetch_ceiling);
2452 break;
2453 }
2454 case MODEPAGE_PDEVICE:
2455 {
2456 struct mode_pdevice *pd;
2457 pd = (struct mode_pdevice *)(void *)page_data;
2458 pd->if_ident = BE_16(pd->if_ident);
2459 break;
2460 }
2461 case MODEPAGE_CTRL_MODE:
2462 {
2463 struct mode_control *pd;
2464 pd = (struct mode_control *)(void *)page_data;
2465 pd->ready_aen_holdoff = BE_16(pd->ready_aen_holdoff);
2466 break;
2467 }
2468 }
2469
2470 /*
2471 * Put the header and data together
2472 */
2473 (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
2474 (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
2475 nbytes += page_size;
2476
2477 /*
2478 * Build and execute the uscsi ioctl
2479 */
2480 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2481 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2482 cdb.scc_cmd = SCMD_MODE_SELECT;
2483 FORMG0COUNT(&cdb, (uchar_t)nbytes);
2484 cdb.cdb_opaque[1] = (uchar_t)options;
2485 ucmd.uscsi_cdb = (caddr_t)&cdb;
2486 ucmd.uscsi_cdblen = CDB_GROUP0;
2487 ucmd.uscsi_bufaddr = mode_select_buf;
2488 ucmd.uscsi_buflen = nbytes;
2489 status = uscsi_cmd(fd, &ucmd,
2490 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2491
2492 if (status && option_msg) {
2493 err_print("Mode select page 0x%x failed\n", page_code);
2494 }
2495
2496 free(mode_select_buf);
2497 return (status);
2498 }
2499
2500
2501 /*
2502 * Execute a uscsi inquiry command and return the
2503 * resulting data.
2504 */
2505 int
uscsi_inquiry(fd,inqbuf,inqbufsiz)2506 uscsi_inquiry(fd, inqbuf, inqbufsiz)
2507 int fd;
2508 caddr_t inqbuf;
2509 int inqbufsiz;
2510 {
2511 struct uscsi_cmd ucmd;
2512 union scsi_cdb cdb;
2513 struct scsi_inquiry *inq;
2514 int n;
2515 int status;
2516
2517 assert(inqbufsiz >= sizeof (struct scsi_inquiry) &&
2518 inqbufsiz < 256);
2519
2520 /*
2521 * Build and execute the uscsi ioctl
2522 */
2523 (void) memset((char *)inqbuf, 0, inqbufsiz);
2524 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2525 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2526 cdb.scc_cmd = SCMD_INQUIRY;
2527 FORMG0COUNT(&cdb, (uchar_t)inqbufsiz);
2528 ucmd.uscsi_cdb = (caddr_t)&cdb;
2529 ucmd.uscsi_cdblen = CDB_GROUP0;
2530 ucmd.uscsi_bufaddr = (caddr_t)inqbuf;
2531 ucmd.uscsi_buflen = inqbufsiz;
2532 status = uscsi_cmd(fd, &ucmd,
2533 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2534 if (status) {
2535 if (option_msg) {
2536 err_print("Inquiry failed\n");
2537 }
2538 } else if (option_msg && diag_msg) {
2539 /*
2540 * Dump the inquiry data if anyone's interested
2541 */
2542 inq = (struct scsi_inquiry *)inqbuf;
2543 n = (int)inq->inq_len + 4;
2544 n = min(n, inqbufsiz);
2545 err_print("Inquiry:\n");
2546 dump("", (caddr_t)inqbuf, n, HEX_ASCII);
2547 }
2548 return (status);
2549 }
2550
2551 /*
2552 * Execute a uscsi inquiry command with page code 86h
2553 */
2554 int
uscsi_inquiry_page_86h(fd,inqbuf,inqbufsiz)2555 uscsi_inquiry_page_86h(fd, inqbuf, inqbufsiz)
2556 int fd;
2557 caddr_t inqbuf;
2558 int inqbufsiz;
2559 {
2560 struct uscsi_cmd ucmd;
2561 union scsi_cdb cdb;
2562 int status;
2563
2564 assert(inqbuf);
2565 assert(inqbufsiz >= sizeof (struct scsi_inquiry) &&
2566 inqbufsiz < 256);
2567 /*
2568 * Build and execute uscsi ioctl
2569 */
2570 (void) memset((char *)inqbuf, 0, inqbufsiz);
2571 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2572 (void) memset((char *)&cdb, 0, sizeof (cdb));
2573 cdb.scc_cmd = SCMD_INQUIRY;
2574 FORMG0COUNT(&cdb, (uchar_t)inqbufsiz);
2575 cdb.cdb_opaque[1] |= 0x01;
2576 cdb.cdb_opaque[2] = 0x86;
2577 ucmd.uscsi_cdb = (caddr_t)&cdb;
2578 ucmd.uscsi_cdblen = CDB_GROUP0;
2579 ucmd.uscsi_bufaddr = (caddr_t)inqbuf;
2580 ucmd.uscsi_buflen = inqbufsiz;
2581
2582 status = uscsi_cmd(fd, &ucmd,
2583 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2584
2585 if (status) {
2586 if (option_msg) {
2587 err_print("Inquriy with page_86h failed\n");
2588 }
2589 }
2590 return (status);
2591 }
2592
2593 /*
2594 * Return the Read Capacity information
2595 */
2596 int
uscsi_read_capacity_16(fd,capacity)2597 uscsi_read_capacity_16(fd, capacity)
2598 int fd;
2599 struct scsi_capacity_16 *capacity;
2600 {
2601 struct uscsi_cmd ucmd;
2602 union scsi_cdb cdb;
2603 int status;
2604
2605 (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16));
2606 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2607 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2608
2609 ucmd.uscsi_cdb = (caddr_t)&cdb;
2610 ucmd.uscsi_cdblen = CDB_GROUP4;
2611 ucmd.uscsi_bufaddr = (caddr_t)capacity;
2612 ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16);
2613
2614 /*
2615 * Read Capacity (16) is a Service Action In command. One
2616 * command byte (0x9E) is overloaded for multiple operations,
2617 * with the second CDB byte specifying the desired operation
2618 */
2619 cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4;
2620 cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4;
2621
2622 /*
2623 * Fill in allocation length field
2624 */
2625 cdb.cdb_opaque[10] =
2626 (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24);
2627 cdb.cdb_opaque[11] =
2628 (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16);
2629 cdb.cdb_opaque[12] =
2630 (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8);
2631 cdb.cdb_opaque[13] =
2632 (uchar_t)(ucmd.uscsi_buflen & 0x000000ff);
2633
2634 status = uscsi_cmd(fd, &ucmd,
2635 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2636
2637 if (status) {
2638 if (option_msg) {
2639 err_print("Read capacity 16 failed\n");
2640 }
2641 } else if (option_msg && diag_msg) {
2642 /*
2643 * Dump the capacity data if anyone's interested
2644 */
2645 dump("Capacity: ", (caddr_t)capacity,
2646 sizeof (struct scsi_capacity_16), HEX_ONLY);
2647 }
2648
2649 capacity->sc_capacity = BE_64(capacity->sc_capacity);
2650 capacity->sc_lbasize = BE_32(capacity->sc_lbasize);
2651
2652 return (status);
2653 }
2654
2655 int
uscsi_read_capacity(fd,capacity)2656 uscsi_read_capacity(fd, capacity)
2657 int fd;
2658 struct scsi_capacity_16 *capacity;
2659 {
2660 struct uscsi_cmd ucmd;
2661 union scsi_cdb cdb;
2662 int status;
2663 struct scsi_capacity cap_old;
2664
2665 /*
2666 * Build and execute the uscsi ioctl
2667 */
2668 (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16));
2669 (void) memset((char *)&cap_old, 0, sizeof (struct scsi_capacity));
2670 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2671 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2672 cdb.scc_cmd = SCMD_READ_CAPACITY;
2673 ucmd.uscsi_cdb = (caddr_t)&cdb;
2674 ucmd.uscsi_cdblen = CDB_GROUP1;
2675 ucmd.uscsi_bufaddr = (caddr_t)&cap_old;
2676 ucmd.uscsi_buflen = sizeof (struct scsi_capacity);
2677 status = uscsi_cmd(fd, &ucmd,
2678 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2679
2680 if (cap_old.capacity == UINT_MAX32) {
2681 /*
2682 * A capacity of 0xffffffff in response to a
2683 * READ CAPACITY 10 indicates that the lun
2684 * is too large to report the size in a 32 bit
2685 * value, and a READ CAPACITY 16 is required
2686 * to get the correct size.
2687 */
2688 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2689 (void) memset((char *)&cdb, 0,
2690 sizeof (union scsi_cdb));
2691
2692 ucmd.uscsi_cdb = (caddr_t)&cdb;
2693 ucmd.uscsi_cdblen = CDB_GROUP4;
2694 ucmd.uscsi_bufaddr = (caddr_t)capacity;
2695 ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16);
2696
2697 /*
2698 * Read Capacity (16) is a Service Action In command. One
2699 * command byte (0x9E) is overloaded for multiple operations,
2700 * with the second CDB byte specifying the desired operation
2701 */
2702 cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4;
2703 cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4;
2704
2705 /*
2706 * Fill in allocation length field
2707 */
2708 cdb.cdb_opaque[10] =
2709 (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24);
2710 cdb.cdb_opaque[11] =
2711 (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16);
2712 cdb.cdb_opaque[12] =
2713 (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8);
2714 cdb.cdb_opaque[13] =
2715 (uchar_t)(ucmd.uscsi_buflen & 0x000000ff);
2716
2717 status = uscsi_cmd(fd, &ucmd,
2718 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2719 }
2720
2721 if (status) {
2722 if (option_msg) {
2723 /*
2724 * Indicate which of the commands failed
2725 */
2726 if (cdb.scc_cmd == SCMD_READ_CAPACITY) {
2727 err_print("Read capacity failed\n");
2728 } else {
2729 err_print("Read capacity 16 failed\n");
2730 }
2731 }
2732 } else if (option_msg && diag_msg) {
2733 /*
2734 * Dump the capacity data if anyone's interested
2735 */
2736 if (cap_old.capacity == UINT_MAX32) {
2737 dump("Capacity: ", (caddr_t)capacity,
2738 sizeof (struct scsi_capacity_16), HEX_ONLY);
2739 } else {
2740 dump("Capacity: ", (caddr_t)&cap_old,
2741 sizeof (struct scsi_capacity), HEX_ONLY);
2742 }
2743 }
2744
2745 if (cap_old.capacity == UINT_MAX32) {
2746 capacity->sc_capacity = BE_64(capacity->sc_capacity);
2747 capacity->sc_lbasize = BE_32(capacity->sc_lbasize);
2748 } else {
2749 capacity->sc_capacity = (uint64_t)BE_32(cap_old.capacity);
2750 capacity->sc_lbasize = BE_32(cap_old.lbasize);
2751 }
2752
2753 return (status);
2754 }
2755
2756
2757 /*
2758 * Reserve the current disk
2759 */
2760 static int
uscsi_reserve_release(int fd,int cmd)2761 uscsi_reserve_release(int fd, int cmd)
2762 {
2763 int status = 0;
2764 #ifdef sparc
2765 struct uscsi_cmd ucmd;
2766 union scsi_cdb cdb;
2767
2768 /*
2769 * Build and execute the uscsi ioctl
2770 */
2771 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2772 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2773 cdb.scc_cmd = (cmd == SCMD_RESERVE) ? SCMD_RESERVE : SCMD_RELEASE;
2774 ucmd.uscsi_cdb = (caddr_t)&cdb;
2775 ucmd.uscsi_cdblen = CDB_GROUP0;
2776 status = uscsi_cmd(fd, &ucmd,
2777 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2778
2779 if (status) {
2780 /*
2781 * Reserve/Release(6) failed.
2782 * Try Reserve/Release(10) , if it succeeds then
2783 * return success.
2784 */
2785 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2786 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2787 ucmd.uscsi_cdb = (caddr_t)&cdb;
2788 cdb.scc_cmd = (cmd == SCMD_RESERVE) ?
2789 SCMD_RESERVE_G1 : SCMD_RELEASE_G1;
2790 ucmd.uscsi_cdblen = CDB_GROUP1;
2791 status = uscsi_cmd(fd, &ucmd,
2792 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2793 if (status) {
2794 if (option_msg) {
2795 err_print("%s failed\n", (cmd == SCMD_RESERVE) ?
2796 "Reserve" : "Release");
2797 }
2798 }
2799 }
2800 #else /* not sparc */
2801
2802 #ifdef lint
2803 fd = fd;
2804 cmd = cmd;
2805 #endif /* lint */
2806
2807 #endif /* not sparc */
2808
2809 return (status);
2810 }
2811
2812 int
scsi_dump_mode_sense_pages(page_control)2813 scsi_dump_mode_sense_pages(page_control)
2814 int page_control;
2815 {
2816 struct uscsi_cmd ucmd;
2817 union scsi_cdb cdb;
2818 char *msbuf;
2819 int nbytes;
2820 char *pc_str;
2821 int status;
2822 struct mode_header *mh;
2823 char *p;
2824 struct mode_page *mp;
2825 int n;
2826 char s[16];
2827 int result = 0;
2828
2829 pc_str = find_string(page_control_strings, page_control);
2830
2831 /*
2832 * Allocate memory for the mode sense buffer.
2833 */
2834 nbytes = 255;
2835 msbuf = (char *)zalloc(nbytes);
2836
2837 /*
2838 * Build and execute the uscsi ioctl
2839 */
2840 (void) memset(msbuf, 0, nbytes);
2841 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2842 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2843 cdb.scc_cmd = SCMD_MODE_SENSE;
2844 FORMG0COUNT(&cdb, (uchar_t)nbytes);
2845 cdb.cdb_opaque[2] = page_control | 0x3f;
2846 ucmd.uscsi_cdb = (caddr_t)&cdb;
2847 ucmd.uscsi_cdblen = CDB_GROUP0;
2848 ucmd.uscsi_bufaddr = msbuf;
2849 ucmd.uscsi_buflen = nbytes;
2850 status = uscsi_cmd(cur_file, &ucmd,
2851 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
2852 if (status) {
2853 err_print("\nMode sense page 0x3f (%s) failed\n",
2854 pc_str);
2855 result = 1;
2856 } else {
2857 err_print("\nMode sense pages (%s):\n", pc_str);
2858 mh = (struct mode_header *)msbuf;
2859 nbytes = mh->length - sizeof (struct mode_header) -
2860 mh->bdesc_length + 1;
2861 p = msbuf + sizeof (struct mode_header) +
2862 mh->bdesc_length;
2863 dump(" ", msbuf, sizeof (struct mode_header) +
2864 (int)mh->bdesc_length, HEX_ONLY);
2865 while (nbytes > 0) {
2866 mp = (struct mode_page *)p;
2867 n = mp->length + sizeof (struct mode_page);
2868 nbytes -= n;
2869 if (nbytes < 0)
2870 break;
2871 (void) sprintf(s, " %3x: ", mp->code);
2872 dump(s, p, n, HEX_ONLY);
2873 p += n;
2874 }
2875 if (nbytes < 0) {
2876 err_print(" Sense data formatted incorrectly:\n");
2877 dump(" ", msbuf, (int)mh->length+1, HEX_ONLY);
2878 result = 1;
2879 }
2880 err_print("\n");
2881 }
2882
2883 free(msbuf);
2884 return (result);
2885 }
2886
2887
2888 static void
scsi_printerr(ucmd,rq,rqlen)2889 scsi_printerr(ucmd, rq, rqlen)
2890 struct uscsi_cmd *ucmd;
2891 struct scsi_extended_sense *rq;
2892 int rqlen;
2893 {
2894 diskaddr_t blkno;
2895 struct scsi_descr_sense_hdr *sdsp =
2896 (struct scsi_descr_sense_hdr *)rq;
2897
2898 switch (rq->es_key) {
2899 case KEY_NO_SENSE:
2900 err_print("No sense error");
2901 break;
2902 case KEY_RECOVERABLE_ERROR:
2903 err_print("Recoverable error");
2904 break;
2905 case KEY_NOT_READY:
2906 err_print("Not ready error");
2907 break;
2908 case KEY_MEDIUM_ERROR:
2909 err_print("Medium error");
2910 break;
2911 case KEY_HARDWARE_ERROR:
2912 err_print("Hardware error");
2913 break;
2914 case KEY_ILLEGAL_REQUEST:
2915 err_print("Illegal request");
2916 break;
2917 case KEY_UNIT_ATTENTION:
2918 err_print("Unit attention error");
2919 break;
2920 case KEY_WRITE_PROTECT:
2921 err_print("Write protect error");
2922 break;
2923 case KEY_BLANK_CHECK:
2924 err_print("Blank check error");
2925 break;
2926 case KEY_VENDOR_UNIQUE:
2927 err_print("Vendor unique error");
2928 break;
2929 case KEY_COPY_ABORTED:
2930 err_print("Copy aborted error");
2931 break;
2932 case KEY_ABORTED_COMMAND:
2933 err_print("Aborted command");
2934 break;
2935 case KEY_EQUAL:
2936 err_print("Equal error");
2937 break;
2938 case KEY_VOLUME_OVERFLOW:
2939 err_print("Volume overflow");
2940 break;
2941 case KEY_MISCOMPARE:
2942 err_print("Miscompare error");
2943 break;
2944 case KEY_RESERVED:
2945 err_print("Reserved error");
2946 break;
2947 default:
2948 err_print("Unknown error");
2949 break;
2950 }
2951
2952 err_print(" during %s", scsi_find_command_name(ucmd->uscsi_cdb[0]));
2953
2954 /*
2955 * Get asc, ascq and info field from sense data. There are two
2956 * possible formats (fixed sense data and descriptor sense data)
2957 * depending on the value of es_code.
2958 */
2959 switch (rq->es_code) {
2960 case CODE_FMT_DESCR_CURRENT:
2961 case CODE_FMT_DESCR_DEFERRED:
2962 blkno =
2963 (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen);
2964 if (blkno != (diskaddr_t)-1) {
2965 err_print(": block %lld (0x%llx) (", blkno, blkno);
2966 pr_dblock(err_print, blkno);
2967 err_print(")");
2968 }
2969
2970 err_print("\n");
2971
2972 err_print("ASC: 0x%x ASCQ: 0x%x\n",
2973 sdsp->ds_add_code, sdsp->ds_qual_code);
2974 break;
2975 case CODE_FMT_FIXED_CURRENT:
2976 case CODE_FMT_FIXED_DEFERRED:
2977 default:
2978 if (rq->es_valid) {
2979 blkno = (rq->es_info_1 << 24) |
2980 (rq->es_info_2 << 16) |
2981 (rq->es_info_3 << 8) | rq->es_info_4;
2982 err_print(": block %lld (0x%llx) (", blkno, blkno);
2983 pr_dblock(err_print, blkno);
2984 err_print(")");
2985 }
2986
2987 err_print("\n");
2988
2989 if (rq->es_add_len >= 6) {
2990 err_print("ASC: 0x%x ASCQ: 0x%x\n",
2991 rq->es_add_code, rq->es_qual_code);
2992 }
2993 break;
2994 }
2995
2996 if (option_msg && diag_msg) {
2997 if (rq->es_key == KEY_ILLEGAL_REQUEST) {
2998 dump("cmd: ", (caddr_t)ucmd,
2999 sizeof (struct uscsi_cmd), HEX_ONLY);
3000 dump("cdb: ", (caddr_t)ucmd->uscsi_cdb,
3001 ucmd->uscsi_cdblen, HEX_ONLY);
3002 }
3003 dump("sense: ", (caddr_t)rq, rqlen, HEX_ONLY);
3004 }
3005
3006 if (option_msg) {
3007 switch (rq->es_code) {
3008 case CODE_FMT_DESCR_CURRENT:
3009 case CODE_FMT_DESCR_DEFERRED:
3010 scsi_print_descr_sense(sdsp, rqlen);
3011 break;
3012 case CODE_FMT_FIXED_CURRENT:
3013 case CODE_FMT_FIXED_DEFERRED:
3014 default:
3015 scsi_print_extended_sense(rq, rqlen);
3016 break;
3017 }
3018 }
3019 }
3020
3021 /*
3022 * Retrieve "information" field from descriptor format
3023 * sense data. Iterates through each sense descriptor
3024 * looking for the information descriptor and returns
3025 * the information field from that descriptor.
3026 */
3027 static diskaddr_t
scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr * sdsp,int rqlen)3028 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen)
3029 {
3030 diskaddr_t result;
3031 uint8_t *descr_offset;
3032 int valid_sense_length;
3033 struct scsi_information_sense_descr *isd;
3034
3035 /*
3036 * Initialize result to -1 indicating there is no information
3037 * descriptor
3038 */
3039 result = (diskaddr_t)-1;
3040
3041 /*
3042 * The first descriptor will immediately follow the header
3043 */
3044 descr_offset = (uint8_t *)(sdsp+1); /* Pointer arithmetic */
3045
3046 /*
3047 * Calculate the amount of valid sense data
3048 */
3049 valid_sense_length =
3050 min((sizeof (struct scsi_descr_sense_hdr) +
3051 sdsp->ds_addl_sense_length),
3052 rqlen);
3053
3054 /*
3055 * Iterate through the list of descriptors, stopping when we
3056 * run out of sense data
3057 */
3058 while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <=
3059 (uint8_t *)sdsp + valid_sense_length) {
3060 /*
3061 * Check if this is an information descriptor. We can
3062 * use the scsi_information_sense_descr structure as a
3063 * template sense the first two fields are always the
3064 * same
3065 */
3066 isd = (struct scsi_information_sense_descr *)descr_offset;
3067 if (isd->isd_descr_type == DESCR_INFORMATION) {
3068 /*
3069 * Found an information descriptor. Copy the
3070 * information field. There will only be one
3071 * information descriptor so we can stop looking.
3072 */
3073 result =
3074 (((diskaddr_t)isd->isd_information[0] << 56) |
3075 ((diskaddr_t)isd->isd_information[1] << 48) |
3076 ((diskaddr_t)isd->isd_information[2] << 40) |
3077 ((diskaddr_t)isd->isd_information[3] << 32) |
3078 ((diskaddr_t)isd->isd_information[4] << 24) |
3079 ((diskaddr_t)isd->isd_information[5] << 16) |
3080 ((diskaddr_t)isd->isd_information[6] << 8) |
3081 ((diskaddr_t)isd->isd_information[7]));
3082 break;
3083 }
3084
3085 /*
3086 * Get pointer to the next descriptor. The "additional
3087 * length" field holds the length of the descriptor except
3088 * for the "type" and "additional length" fields, so
3089 * we need to add 2 to get the total length.
3090 */
3091 descr_offset += (isd->isd_addl_length + 2);
3092 }
3093
3094 return (result);
3095 }
3096
3097 /*
3098 * Return a pointer to a string telling us the name of the command.
3099 */
3100 static char *
scsi_find_command_name(uint_t cmd)3101 scsi_find_command_name(uint_t cmd)
3102 {
3103 struct scsi_command_name *c;
3104
3105 for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++)
3106 if (c->command == cmd)
3107 break;
3108 return (c->name);
3109 }
3110
3111
3112 /*
3113 * Return true if we support a particular mode page
3114 */
3115 int
scsi_supported_page(int page)3116 scsi_supported_page(int page) {
3117 return (page == 1 || page == 2 || page == 3 || page == 4 ||
3118 page == 8 || page == 0x38);
3119 }
3120
3121
3122 int
apply_chg_list(int pageno,int pagsiz,uchar_t * curbits,uchar_t * chgbits,struct chg_list * chglist)3123 apply_chg_list(int pageno, int pagsiz, uchar_t *curbits,
3124 uchar_t *chgbits, struct chg_list *chglist)
3125 {
3126 uchar_t c;
3127 int i;
3128 int m;
3129 int delta;
3130 int changed = 0;
3131
3132 while (chglist != NULL) {
3133 if (chglist->pageno == pageno &&
3134 chglist->byteno < pagsiz) {
3135 i = chglist->byteno;
3136 c = curbits[i];
3137 switch (chglist->mode) {
3138 case CHG_MODE_SET:
3139 c |= (uchar_t)chglist->value;
3140 break;
3141 case CHG_MODE_CLR:
3142 c &= (uchar_t)chglist->value;
3143 break;
3144 case CHG_MODE_ABS:
3145 c = (uchar_t)chglist->value;
3146 break;
3147 }
3148 /*
3149 * Figure out which bits changed, and
3150 * are marked as changeable. If this
3151 * result actually differs from the
3152 * current value, update the current
3153 * value, and note that a mode select
3154 * should be done.
3155 */
3156 delta = c ^ curbits[i];
3157 for (m = 0x01; m < 0x100; m <<= 1) {
3158 if ((delta & m) && (chgbits[i] & m)) {
3159 curbits[i] ^= m;
3160 changed = 1;
3161 }
3162 }
3163 }
3164 chglist = chglist->next;
3165 }
3166
3167 return (changed);
3168 }
3169
3170
3171 /*
3172 * Return whether a given page is affected by an item on
3173 * the change list.
3174 */
3175 static int
chg_list_affects_page(chglist,pageno)3176 chg_list_affects_page(chglist, pageno)
3177 struct chg_list *chglist;
3178 int pageno;
3179 {
3180 while (chglist != NULL) {
3181 if (chglist->pageno == pageno) {
3182 return (1);
3183 }
3184 chglist = chglist->next;
3185 }
3186
3187 return (0);
3188 }
3189
3190
3191 /*
3192 * Labels for the various fields of the scsi_extended_sense structure
3193 */
3194 static char *scsi_extended_sense_labels[] = {
3195 "Request sense valid: ",
3196 "Error class and code: ",
3197 "Segment number: ",
3198 "Filemark: ",
3199 "End-of-medium: ",
3200 "Incorrect length indicator: ",
3201 "Sense key: ",
3202 "Information field: ",
3203 "Additional sense length: ",
3204 "Command-specific information: ",
3205 "Additional sense code: ",
3206 "Additional sense code qualifier: ",
3207 "Field replaceable unit code: ",
3208 "Sense-key specific: ",
3209 "Additional sense bytes: "
3210 };
3211
3212
3213 /*
3214 * Display the full scsi_extended_sense as returned by the device
3215 */
3216 static void
scsi_print_extended_sense(rq,rqlen)3217 scsi_print_extended_sense(rq, rqlen)
3218 struct scsi_extended_sense *rq;
3219 int rqlen;
3220 {
3221 char **p;
3222
3223 p = scsi_extended_sense_labels;
3224 if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) {
3225 /*
3226 * target should be capable of returning at least 18
3227 * bytes of data, i.e upto rq->es_skey_specific field.
3228 * The additional sense bytes (2 or more ...) are optional.
3229 */
3230 return;
3231 }
3232
3233 fmt_print("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no");
3234 fmt_print("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code);
3235 fmt_print("%s%d\n", *p++, rq->es_segnum);
3236 fmt_print("%s%s\n", *p++, rq->es_filmk ? "yes" : "no");
3237 fmt_print("%s%s\n", *p++, rq->es_eom ? "yes" : "no");
3238 fmt_print("%s%s\n", *p++, rq->es_ili ? "yes" : "no");
3239 fmt_print("%s%d\n", *p++, rq->es_key);
3240
3241 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1,
3242 rq->es_info_2, rq->es_info_3, rq->es_info_4);
3243 fmt_print("%s%d\n", *p++, rq->es_add_len);
3244 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_cmd_info[0],
3245 rq->es_cmd_info[1], rq->es_cmd_info[2], rq->es_cmd_info[3]);
3246 fmt_print("%s0x%02x = %d\n", *p++, rq->es_add_code, rq->es_add_code);
3247 fmt_print("%s0x%02x = %d\n", *p++, rq->es_qual_code, rq->es_qual_code);
3248 fmt_print("%s%d\n", *p++, rq->es_fru_code);
3249 fmt_print("%s0x%02x 0x%02x 0x%02x\n", *p++, rq->es_skey_specific[0],
3250 rq->es_skey_specific[1], rq->es_skey_specific[2]);
3251 if (rqlen >= sizeof (*rq)) {
3252 fmt_print("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0],
3253 rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : "");
3254 }
3255
3256 fmt_print("\n");
3257 }
3258
3259 /*
3260 * Labels for the various fields of the scsi_descr_sense_hdr structure
3261 */
3262 static char *scsi_descr_sense_labels[] = {
3263 "Error class and code: ",
3264 "Sense key: ",
3265 "Additional sense length: ",
3266 "Additional sense code: ",
3267 "Additional sense code qualifier: ",
3268 "Additional sense bytes: "
3269 };
3270
3271
3272 /*
3273 * Display the full descriptor sense data as returned by the device
3274 */
3275
3276 static void
scsi_print_descr_sense(rq,rqlen)3277 scsi_print_descr_sense(rq, rqlen)
3278 struct scsi_descr_sense_hdr *rq;
3279 int rqlen;
3280 {
3281 char **p;
3282 uint8_t *descr_offset;
3283 int valid_sense_length;
3284 struct scsi_information_sense_descr *isd;
3285
3286 p = scsi_descr_sense_labels;
3287 if (rqlen < sizeof (struct scsi_descr_sense_hdr)) {
3288 /*
3289 * target must return at least 8 bytes of data
3290 */
3291 return;
3292 }
3293
3294 /* Print descriptor sense header */
3295 fmt_print("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code);
3296 fmt_print("%s%d\n", *p++, rq->ds_key);
3297
3298 fmt_print("%s%d\n", *p++, rq->ds_addl_sense_length);
3299 fmt_print("%s0x%02x = %d\n", *p++, rq->ds_add_code, rq->ds_add_code);
3300 fmt_print("%s0x%02x = %d\n", *p++, rq->ds_qual_code, rq->ds_qual_code);
3301 fmt_print("\n");
3302
3303 /*
3304 * Now print any sense descriptors. The first descriptor will
3305 * immediately follow the header
3306 */
3307 descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */
3308
3309 /*
3310 * Calculate the amount of valid sense data
3311 */
3312 valid_sense_length =
3313 min((sizeof (struct scsi_descr_sense_hdr) +
3314 rq->ds_addl_sense_length), rqlen);
3315
3316 /*
3317 * Iterate through the list of descriptors, stopping when we
3318 * run out of sense data. Descriptor format is:
3319 *
3320 * <Descriptor type> <Descriptor length> <Descriptor data> ...
3321 */
3322 while ((descr_offset + *(descr_offset + 1)) <=
3323 (uint8_t *)rq + valid_sense_length) {
3324 /*
3325 * Determine descriptor type. We can use the
3326 * scsi_information_sense_descr structure as a
3327 * template since the first two fields are always the
3328 * same.
3329 */
3330 isd = (struct scsi_information_sense_descr *)descr_offset;
3331 switch (isd->isd_descr_type) {
3332 case DESCR_INFORMATION: {
3333 uint64_t information;
3334
3335 information =
3336 (((uint64_t)isd->isd_information[0] << 56) |
3337 ((uint64_t)isd->isd_information[1] << 48) |
3338 ((uint64_t)isd->isd_information[2] << 40) |
3339 ((uint64_t)isd->isd_information[3] << 32) |
3340 ((uint64_t)isd->isd_information[4] << 24) |
3341 ((uint64_t)isd->isd_information[5] << 16) |
3342 ((uint64_t)isd->isd_information[6] << 8) |
3343 ((uint64_t)isd->isd_information[7]));
3344 fmt_print("Information field: "
3345 "%0llx\n", information);
3346 break;
3347 }
3348 case DESCR_COMMAND_SPECIFIC: {
3349 struct scsi_cmd_specific_sense_descr *c =
3350 (struct scsi_cmd_specific_sense_descr *)isd;
3351 uint64_t cmd_specific;
3352
3353 cmd_specific =
3354 (((uint64_t)c->css_cmd_specific_info[0] << 56) |
3355 ((uint64_t)c->css_cmd_specific_info[1] << 48) |
3356 ((uint64_t)c->css_cmd_specific_info[2] << 40) |
3357 ((uint64_t)c->css_cmd_specific_info[3] << 32) |
3358 ((uint64_t)c->css_cmd_specific_info[4] << 24) |
3359 ((uint64_t)c->css_cmd_specific_info[5] << 16) |
3360 ((uint64_t)c->css_cmd_specific_info[6] << 8) |
3361 ((uint64_t)c->css_cmd_specific_info[7]));
3362 fmt_print("Command-specific information: "
3363 "%0llx\n", cmd_specific);
3364 break;
3365 }
3366 case DESCR_SENSE_KEY_SPECIFIC: {
3367 struct scsi_sk_specific_sense_descr *ssd =
3368 (struct scsi_sk_specific_sense_descr *)isd;
3369 uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data;
3370 fmt_print("Sense-key specific: "
3371 "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0],
3372 sk_spec_ptr[1], sk_spec_ptr[2]);
3373 break;
3374 }
3375 case DESCR_FRU: {
3376 struct scsi_fru_sense_descr *fsd =
3377 (struct scsi_fru_sense_descr *)isd;
3378 fmt_print("Field replaceable unit code: "
3379 "%d\n", fsd->fs_fru_code);
3380 break;
3381 }
3382 case DESCR_BLOCK_COMMANDS: {
3383 struct scsi_block_cmd_sense_descr *bsd =
3384 (struct scsi_block_cmd_sense_descr *)isd;
3385 fmt_print("Incorrect length indicator: "
3386 "%s\n", bsd->bcs_ili ? "yes" : "no");
3387 break;
3388 }
3389 default:
3390 /* Ignore */
3391 break;
3392 }
3393
3394 /*
3395 * Get pointer to the next descriptor. The "additional
3396 * length" field holds the length of the descriptor except
3397 * for the "type" and "additional length" fields, so
3398 * we need to add 2 to get the total length.
3399 */
3400 descr_offset += (isd->isd_addl_length + 2);
3401 }
3402
3403 fmt_print("\n");
3404 }
3405
3406 /*
3407 * Function checks if READ DEFECT DATA command is supported
3408 * on the current disk.
3409 */
3410 static int
check_support_for_defects()3411 check_support_for_defects()
3412 {
3413 struct uscsi_cmd ucmd;
3414 union scsi_cdb cdb;
3415 struct scsi_defect_list def_list;
3416 struct scsi_defect_hdr *hdr;
3417 int status;
3418 char rqbuf[255];
3419 struct scsi_extended_sense *rq;
3420
3421 hdr = (struct scsi_defect_hdr *)&def_list;
3422
3423 /*
3424 * First get length of list by asking for the header only.
3425 */
3426 (void) memset((char *)&def_list, 0, sizeof (def_list));
3427
3428 /*
3429 * Build and execute the uscsi ioctl
3430 */
3431 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
3432 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
3433 (void) memset((char *)rqbuf, 0, 255);
3434 cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
3435 FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr));
3436 cdb.cdb_opaque[2] = DLD_MAN_DEF_LIST | DLD_BFI_FORMAT;
3437 ucmd.uscsi_cdb = (caddr_t)&cdb;
3438 ucmd.uscsi_cdblen = CDB_GROUP1;
3439 ucmd.uscsi_bufaddr = (caddr_t)hdr;
3440 ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr);
3441 ucmd.uscsi_rqbuf = rqbuf;
3442 ucmd.uscsi_rqlen = sizeof (rqbuf);
3443 ucmd.uscsi_rqresid = sizeof (rqbuf);
3444 rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf;
3445
3446 status = uscsi_cmd(cur_file, &ucmd,
3447 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
3448
3449 if (status != 0) {
3450 /*
3451 * check if read_defect_list_is_supported.
3452 */
3453 if (ucmd.uscsi_rqstatus == STATUS_GOOD &&
3454 rq->es_key == KEY_ILLEGAL_REQUEST &&
3455 rq->es_add_code == INVALID_OPCODE)
3456 return (0);
3457 }
3458 return (1);
3459 }
3460
3461 /*
3462 * Format the disk, the whole disk, and nothing but the disk.
3463 * Function will be called only for disks
3464 * which do not support read defect list command.
3465 */
3466 static int
scsi_format_without_defects()3467 scsi_format_without_defects()
3468 {
3469 struct uscsi_cmd ucmd;
3470 union scsi_cdb cdb;
3471 struct scsi_defect_hdr defect_hdr;
3472 int status;
3473
3474 /*
3475 * Construct the uscsi format ioctl.
3476 * Use fmtdata = 0 , indicating the no source of
3477 * defects information is provided .
3478 * Function will be called only for disks
3479 * which do not support read defect list command.
3480 */
3481 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
3482 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
3483 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
3484 cdb.scc_cmd = SCMD_FORMAT;
3485 ucmd.uscsi_cdb = (caddr_t)&cdb;
3486 ucmd.uscsi_cdblen = CDB_GROUP0;
3487 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
3488 ucmd.uscsi_buflen = sizeof (defect_hdr);
3489 cdb.cdb_opaque[1] = 0;
3490 /*
3491 * Issue the format ioctl
3492 */
3493 status = uscsi_cmd(cur_file, &ucmd,
3494 (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
3495 return (status);
3496 }
3497
3498 /*
3499 * Name: test_until_ready
3500 *
3501 * Description: This function is used by scsi_format and
3502 * scsi_format_raw to poll the device while the FORMAT
3503 * UNIT cdb in in progress.
3504 *
3505 * Parameters:
3506 * file descriptor to poll
3507 *
3508 * Returns:
3509 * 0 - good status
3510 * !0 - bad status
3511 */
test_until_ready(int fd)3512 static int test_until_ready(int fd) {
3513 int status = 1;
3514 struct uscsi_cmd ucmd;
3515 union scsi_cdb cdb;
3516 struct scsi_extended_sense sense;
3517 time_t start, check, time_left;
3518 uint16_t progress;
3519 int hour, min, sec;
3520
3521 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
3522 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
3523
3524 ucmd.uscsi_cdb = (caddr_t)&cdb;
3525 ucmd.uscsi_cdblen = CDB_GROUP0;
3526 ucmd.uscsi_rqbuf = (caddr_t)&sense;
3527 ucmd.uscsi_rqlen = SENSE_LEN;
3528
3529 start = check = time((time_t *)0);
3530
3531 /* Loop sending TEST UNIT READY until format is complete */
3532 while (status) {
3533 /* clear last request sense data */
3534 ucmd.uscsi_rqstatus = 0;
3535 ucmd.uscsi_rqresid = 0;
3536 (void) memset((char *)&sense, 0, SENSE_LEN);
3537
3538 /* issue test unit ready */
3539 status = uscsi_cmd(fd, &ucmd, F_SILENT
3540 | F_RQENABLE);
3541
3542 check = time((time_t *)0);
3543
3544 /* If device returns not ready we get EIO */
3545 if (status != 0 && errno == EIO) {
3546 /* Check SKSV if progress indication is avail */
3547 if (sense.es_skey_specific[0] == 0x80) {
3548 /* Store progress indication */
3549 progress = ((uint16_t)sense.
3550 es_skey_specific[1]) << 8;
3551 progress |= (uint16_t)sense.
3552 es_skey_specific[2];
3553 progress = (uint16_t)(((float)progress /
3554 (float)PROGRESS_INDICATION_BASE)*100);
3555
3556 fmt_print("\015");
3557
3558 /*
3559 * check to see if we can estimate
3560 * time remaining - wait until the format
3561 * is at least 5 percent complete to avoid
3562 * wildly-fluctuating time estimates
3563 */
3564 if ((check - start) <= 0 || progress <= 5) {
3565 /* unable to estimate */
3566 fmt_print(" %02d%% complete ",
3567 progress);
3568 } else {
3569 /* display with estimated time */
3570 time_left = (time_t)(((float)(check
3571 - start) / (float)progress) *
3572 (float)(100 - progress));
3573 sec = time_left % 60;
3574 min = (time_left / 60) % 60;
3575 hour = time_left / 3600;
3576
3577 fmt_print(" %02d%% complete "
3578 "(%02d:%02d:%02d remaining) ",
3579 progress, hour, min, sec);
3580 }
3581 /* flush or the screen will not update */
3582 (void) fflush(stdout);
3583 }
3584 } else {
3585 /* format not in progress */
3586 if (option_msg) {
3587 fmt_print("\nRequest Sense ASC=0x%x ASCQ=0x%x",
3588 sense.es_add_code, sense.es_qual_code);
3589 }
3590 break;
3591 }
3592
3593 /* delay so we don't waste cpu time */
3594 (void) sleep(RETRY_DELAY);
3595 }
3596 return (status);
3597 }
3598
3599 /*
3600 * Get the current protection type from the PROT_EN and P_TYPE
3601 */
3602 uint8_t
get_cur_protection_type(struct scsi_capacity_16 * capacity)3603 get_cur_protection_type(struct scsi_capacity_16 *capacity)
3604 {
3605 uint8_t cp13;
3606 uint8_t prot_en;
3607 uint8_t p_type;
3608
3609 cp13 = ((capacity->sc_rsvd0 & 0x3f) << 2)
3610 | ((capacity->sc_prot_en & 0x01) << 1)
3611 | (capacity->sc_rto_en & 0x01);
3612 prot_en = cp13 & 0x01;
3613 if (prot_en == 0) {
3614 p_type = 0;
3615 } else {
3616 p_type = (cp13 << 4) >> 5;
3617 p_type += 1;
3618 }
3619 return (p_type);
3620 }
3621