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.
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.
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]
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * This file contains the routines for embedded scsi disks
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
35 #include <sys/fcntl.h>
42 #include <sys/byteorder.h>
49 #include "ctlr_scsi.h"
55 #ifndef DAD_MODE_CACHE_CCS
56 #define DAD_MODE_CACHE_CCS 0x38
57 #endif /* DAD_MODE_CACHE_CCS */
59 /* format defect header bits */
61 #define FDH_IMMED 0x02
67 #define PROGRESS_INDICATION_BASE 65536
71 * Local prototypes for ANSI C compilers
73 static int scsi_format(uint64_t, uint64_t, struct defect_list
*);
74 static int scsi_raw_format(void);
75 static int scsi_ms_page8(int);
76 static int scsi_ms_page38(int);
77 static void scsi_convert_list_to_new(struct defect_list
*,
78 struct scsi_defect_list
*, int);
79 static char *scsi_find_command_name(uint_t
);
80 static int chg_list_affects_page(struct chg_list
*, int);
81 static void scsi_printerr(struct uscsi_cmd
*,
82 struct scsi_extended_sense
*, int);
84 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr
*sdsp
, int rqlen
);
86 static void scsi_print_extended_sense(struct scsi_extended_sense
*, int);
87 static void scsi_print_descr_sense(struct scsi_descr_sense_hdr
*, int);
89 static int test_until_ready(int fd
);
90 static int uscsi_reserve_release(int, int);
91 static int check_support_for_defects(void);
92 static int scsi_format_without_defects(void);
93 static int scsi_ms_page1(int);
94 static int scsi_ms_page2(int);
95 static int scsi_ms_page3(int);
96 static int scsi_ms_page4(int);
97 static int scsi_repair(uint64_t, int);
98 static int scsi_read_defect_data(struct defect_list
*, int);
99 static int scsi_ck_format(void);
103 static int scsi_format();
104 static int scsi_raw_format();
105 static int scsi_ms_page8();
106 static int scsi_ms_page38();
107 static void scsi_convert_list_to_new();
108 static char *scsi_find_command_name();
109 static int chg_list_affects_page();
110 static void scsi_printerr();
111 static diskaddr_t
scsi_extract_sense_info_descr();
112 static void scsi_print_extended_sense();
113 static void scsi_print_descr_sense();
115 static int test_until_ready();
117 static int uscsi_reserve_release();
118 static int check_support_for_defects();
119 static int scsi_format_without_defects();
120 static int scsi_ms_page1();
121 static int scsi_ms_page2();
122 static int scsi_ms_page3();
123 static int scsi_ms_page4();
124 static int scsi_repair();
125 static int scsi_read_defect_data();
126 static int scsi_ck_format();
128 #endif /* __STDC__ */
132 struct ctlr_ops scsiops
= {
142 #define SCMD_UNKNOWN 0xff
145 * Names of commands. Must have SCMD_UNKNOWN at end of list.
147 static struct scsi_command_name
{
150 } scsi_command_names
[] = {
151 SCMD_FORMAT
, "format",
154 SCMD_READ
|SCMD_GROUP1
, "read",
155 SCMD_WRITE
|SCMD_GROUP1
, "write",
156 SCMD_INQUIRY
, "inquiry",
157 SCMD_MODE_SELECT
, "mode select",
158 SCMD_MODE_SENSE
, "mode sense",
159 SCMD_REASSIGN_BLOCK
, "reassign block",
160 SCMD_READ_DEFECT_LIST
, "read defect list",
161 SCMD_UNKNOWN
, "unknown"
166 * Strings for printing mode sense page control values
168 static slist_t page_control_strings
[] = {
169 { "current", "", MODE_SENSE_PC_CURRENT
},
170 { "changeable", "", MODE_SENSE_PC_CHANGEABLE
},
171 { "default", "", MODE_SENSE_PC_DEFAULT
},
172 { "saved", "", MODE_SENSE_PC_SAVED
}
176 * Strings for printing the mode select options
178 static slist_t mode_select_strings
[] = {
180 { " (pf)", "", MODE_SELECT_PF
},
181 { " (sp)", "", MODE_SELECT_SP
},
182 { " (pf,sp)", "", MODE_SELECT_PF
|MODE_SELECT_SP
}
185 static int scsi_format_revolutions
= 5;
186 static int scsi_format_timeout
= 2*60*60; /* two hours */
189 * READ DEFECT DATA commands is optional as per SCSI-2 spec.
190 * Hence check if the read_defect_data command fails with
191 * Invalid Opcode so that we can give a more meaningful message
194 #define INVALID_OPCODE 0x20
197 * Read or write the disk.
200 scsi_rdwr(dir
, fd
, blkno
, secnt
, bufaddr
, flags
, xfercntp
)
209 struct uscsi_cmd ucmd
;
215 * If the max xfercnt hasn't been determined start with BUF_SECTS
216 * (currently 126 == 63K), otherwise use the xfercnt value
217 * my caller saved from the previous invocation.
219 if (xfercntp
== NULL
) {
220 max_sectors
= BUF_SECTS
;
221 } else if (*xfercntp
== 0) {
222 max_sectors
= BUF_SECTS
;
223 *xfercntp
= max_sectors
;
225 max_sectors
= *xfercntp
;
229 * Build and execute the uscsi ioctl. We build a group0
230 * or group1 command as necessary, since some targets
231 * do not support group1 commands.
236 nsectors
= (max_sectors
< secnt
) ? max_sectors
: secnt
;
237 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
238 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
239 cdb
.scc_cmd
= (dir
== DIR_READ
) ? SCMD_READ
: SCMD_WRITE
;
240 if (blkno
< (2<<20) && nsectors
<= 0xff) {
241 FORMG0ADDR(&cdb
, blkno
);
242 FORMG0COUNT(&cdb
, nsectors
);
243 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
245 if (blkno
> 0xffffffff) {
246 FORMG4LONGADDR(&cdb
, blkno
);
247 FORMG4COUNT(&cdb
, nsectors
);
248 ucmd
.uscsi_cdblen
= CDB_GROUP4
;
249 cdb
.scc_cmd
|= SCMD_GROUP4
;
251 FORMG1ADDR(&cdb
, blkno
);
252 FORMG1COUNT(&cdb
, nsectors
);
253 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
254 cdb
.scc_cmd
|= SCMD_GROUP1
;
257 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
258 ucmd
.uscsi_bufaddr
= bufaddr
;
259 ucmd
.uscsi_buflen
= nsectors
* cur_blksz
;
260 rc
= uscsi_cmd(fd
, &ucmd
, flags
);
266 * check if partial DMA breakup required
267 * if so, reduce the request size by half and retry
270 if (ucmd
.uscsi_resid
== ucmd
.uscsi_buflen
) {
272 if (max_sectors
<= 0) {
278 if (ucmd
.uscsi_resid
!= 0) {
285 bufaddr
+= nsectors
* cur_blksz
;
289 * If the xfercnt wasn't previously saved or if the
290 * new value is smaller than the old value, save the
291 * current value in my caller's save area.
293 if (xfercntp
!= NULL
&& max_sectors
< *xfercntp
) {
295 err_print("reducing xfercnt %d %d\n",
296 *xfercntp
, max_sectors
);
297 *xfercntp
= max_sectors
;
304 * Check to see if the disk has been formatted.
305 * If we are able to read the first track, we conclude that
306 * the disk has been formatted.
318 * Try to read the first four blocks.
320 status
= scsi_rdwr(DIR_READ
, cur_file
, (diskaddr_t
)0, 4,
321 (caddr_t
)cur_buf
, F_SILENT
, NULL
);
327 * Format the disk, the whole disk, and nothing but the disk.
331 scsi_format(start
, end
, list
)
332 uint64_t start
; /* irrelevant for us */
334 struct defect_list
*list
;
336 struct uscsi_cmd ucmd
;
340 char rawbuf
[MAX_MODE_SENSE_SIZE
];
341 struct scsi_inquiry
*inq
;
342 uint8_t fmt_prot_info
;
343 uint8_t prot_field_usage
;
344 uint8_t param_long_list
= 1;
345 uint8_t fmt_long_param_header
[8];
348 * Determine if the target appears to be SCSI-2
349 * compliant. We handle mode sense/mode selects
350 * a little differently, depending upon CCS/SCSI-2
352 if (uscsi_inquiry(cur_file
, rawbuf
, sizeof (rawbuf
))) {
353 err_print("Inquiry failed\n");
356 inq
= (struct scsi_inquiry
*)rawbuf
;
357 flag
= (inq
->inq_rdf
== RDF_SCSI2
);
360 * Reserve the scsi disk before performing mode select and
361 * format operations. This will keep other hosts, if any, from
362 * touching the disk while we are here.
364 if (uscsi_reserve_release(cur_file
, SCMD_RESERVE
)) {
365 err_print("Reserve failed\n");
370 * Set up the various SCSI parameters specified before
371 * formatting the disk. Each routine handles the
372 * parameters relevant to a particular page.
373 * If no parameters are specified for a page, there's
374 * no need to do anything. Otherwise, issue a mode
375 * sense for that page. If a specified parameter
376 * differs from the drive's default value, and that
377 * parameter is not fixed, then issue a mode select to
378 * set the default value for the disk as specified
381 if (scsi_ms_page1(flag
) || scsi_ms_page2(flag
) ||
382 scsi_ms_page4(flag
) || scsi_ms_page38(flag
) ||
383 scsi_ms_page8(flag
) || scsi_ms_page3(flag
)) {
384 (void) uscsi_reserve_release(cur_file
, SCMD_RELEASE
);
389 * If we're debugging the drive, dump every page
390 * the device supports, for thorough analysis.
392 if (option_msg
&& diag_msg
) {
393 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT
);
394 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT
);
395 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED
);
396 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE
);
401 * Determine the FMTPINFO field in format cdb, and the
402 * PROTECTION FIELD USAGE in the long parameter list, via
403 * the protection type input by users.
407 fmt_prot_info
= 0x00;
408 prot_field_usage
= 0x00;
411 fmt_prot_info
= 0x02;
412 prot_field_usage
= 0x00;
415 fmt_prot_info
= 0x03;
416 prot_field_usage
= 0x00;
419 fmt_prot_info
= 0x03;
420 prot_field_usage
= 0x01;
423 fmt_print("invalid protection type\n");
428 * Construct the uscsi format ioctl. The form depends
429 * upon the defect list the user extracted. If they
430 * extracted the "original" list, we format with only
431 * the P (manufacturer's defect) list. Otherwise, we
432 * format with both the P and the G (grown) list.
433 * To format with the P and G list, we set the fmtData
434 * bit, and send an empty list. To format with the
435 * P list only, we also set the cmpLst bit, meaning
436 * that the (empty) list we send down is the complete
437 * G list, thereby discarding the old G list..
439 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
440 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
442 cdb
.scc_cmd
= SCMD_FORMAT
;
443 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
444 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
445 cdb
.cdb_opaque
[1] = FPB_DATA
;
448 * Use the long parameter header in format command,
449 * and set the FMTPINFO field., when type 1, 2, 3.
451 cdb
.cdb_opaque
[1] |= (param_long_list
<< 5) | (fmt_prot_info
<< 6);
452 (void) memset((char *)fmt_long_param_header
, 0,
453 sizeof (fmt_long_param_header
));
456 * Set the PROTECTION FIELD USAGE field in the long
457 * parameter list header, which combines with FMTINFO to
458 * determine the protection type.
459 * The PROTECTION INTERVAL EXPONET field is set default 0.
460 * So only one protection information interval is used
463 fmt_long_param_header
[0] = prot_field_usage
;
464 fmt_long_param_header
[1] = FDH_FOV
| FDH_IMMED
;
465 ucmd
.uscsi_bufaddr
= (caddr_t
)fmt_long_param_header
;
466 ucmd
.uscsi_buflen
= sizeof (fmt_long_param_header
);
468 if ((list
->list
!= NULL
) && ((list
->flags
& LIST_PGLIST
) == 0)) {
470 * No G list. The empty list we send down
471 * is the complete list.
473 cdb
.cdb_opaque
[1] |= FPB_CMPLT
;
477 * Issue the format ioctl
479 fmt_print("Formatting...\n");
480 (void) fflush(stdout
);
481 status
= uscsi_cmd(cur_file
, &ucmd
,
482 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
484 /* check if format with immed was successfully accepted */
486 /* immed accepted poll to completion */
487 status
= test_until_ready(cur_file
);
489 /* clear FOV and try again */
490 (void) memset((char *)fmt_long_param_header
, 0,
491 sizeof (fmt_long_param_header
));
492 fmt_long_param_header
[0] = prot_field_usage
;
493 fmt_long_param_header
[1] = FDH_IMMED
;
494 status
= uscsi_cmd(cur_file
, &ucmd
,
495 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
497 /* immed accepted, poll for progress */
498 status
= test_until_ready(cur_file
);
501 * clear defect header and try basecase format
502 * command will hang until format complete
504 (void) memset((char *)fmt_long_param_header
, 0,
505 sizeof (fmt_long_param_header
));
506 fmt_long_param_header
[0] = prot_field_usage
;
507 status
= uscsi_cmd(cur_file
, &ucmd
,
508 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
512 /* format failure check */
515 * formatting failed with fmtdata = 1.
516 * Check if defects list command is supported, if it
517 * is not supported then use fmtdata = 0.
519 * A FmtData bit of zero indicates, the
520 * source of defect information is not specified.
522 * proceed to format using with mode selects.
524 if (!(check_support_for_defects())) {
525 status
= scsi_format_without_defects();
529 fmt_print("Format failed\n");
530 status
= scsi_raw_format();
533 (void) uscsi_reserve_release(cur_file
, SCMD_RELEASE
);
538 * Format without any of the standard mode selects ignoring Grown defects list.
541 scsi_raw_format(void)
543 struct uscsi_cmd ucmd
;
545 struct scsi_defect_hdr defect_hdr
;
549 "Retry of formatting operation without any of the standard\n"
550 "mode selects and ignoring disk's Grown Defects list. The\n"
551 "disk may be able to be reformatted this way if an earlier\n"
552 "formatting operation was interrupted by a power failure or\n"
553 "SCSI bus reset. The Grown Defects list will be recreated\n"
554 "by format verification and surface analysis.\n\n");
556 if (check("Retry format without mode selects and Grown Defects list")
562 * Construct the uscsi format ioctl.
563 * To format with the P and G list, we set the fmtData
564 * and cmpLst bits to zero. To format with just the
565 * P list, we set the fmtData bit (meaning that we will
566 * send down a defect list in the data phase) and the
567 * cmpLst bit (meaning that the list we send is the
568 * complete G list), and a defect list header with
569 * a defect list length of zero.
571 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
572 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
573 (void) memset((char *)&defect_hdr
, 0, sizeof (defect_hdr
));
575 cdb
.scc_cmd
= SCMD_FORMAT
;
576 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
577 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
578 /* No G list. Send empty defect list to replace it */
579 cdb
.cdb_opaque
[1] = FPB_DATA
| FPB_CMPLT
| FPB_BFI
;
580 ucmd
.uscsi_bufaddr
= (caddr_t
)&defect_hdr
;
581 ucmd
.uscsi_buflen
= sizeof (defect_hdr
);
582 defect_hdr
.descriptor
= FDH_FOV
| FDH_IMMED
;
585 * Issue the format ioctl
587 fmt_print("Formatting...\n");
588 (void) fflush(stdout
);
589 status
= uscsi_cmd(cur_file
, &ucmd
, F_NORMAL
);
591 /* check if format with immed was successfully accepted */
593 /* immed accepted pool to completion */
594 status
= test_until_ready(cur_file
);
596 /* clear defect header and try basecase format */
597 (void) memset((char *)&defect_hdr
, 0, sizeof (defect_hdr
));
598 status
= uscsi_cmd(cur_file
, &ucmd
, F_NORMAL
);
601 /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */
606 * Estimate the time required for format operation (See 1163770).
607 * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm
608 * 5 revolutions (correspond to format_time keyword in format.dat file) are:
609 * 1 rev. for positioning
610 * 2 rev. for writing the track
611 * 1 rev. for positioning
612 * 1 rev. for cerifying the data integrity of the track
613 * The return value is a good estimate on the formatting time in minutes.
614 * Caller should add 50% margin to cover defect management overhead.
619 struct mode_geometry
*page4
;
620 struct scsi_ms_header header
;
622 int p4_cylinders
, p4_heads
, p4_rpm
;
626 struct mode_geometry page4
;
627 char rawbuf
[MAX_MODE_SENSE_SIZE
];
631 page4
= &u_page4
.page4
;
632 (void) memset(&u_page4
, 0, sizeof (u_page4
));
635 * Issue a mode sense to determine the default parameters
636 * If it fail, try to use the saved or current instead.
638 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
639 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page4
,
640 MAX_MODE_SENSE_SIZE
, &header
);
643 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
644 MODE_SENSE_PC_SAVED
, (caddr_t
)page4
,
645 MAX_MODE_SENSE_SIZE
, &header
);
648 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
649 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
,
650 MAX_MODE_SENSE_SIZE
, &header
);
657 * We only need the common subset between the CCS
658 * and SCSI-2 structures, so we can treat both
661 length
= MODESENSE_PAGE_LEN(page4
);
662 if (length
< MIN_PAGE4_LEN
) {
666 page4
->rpm
= BE_16(page4
->rpm
);
667 p4_cylinders
= (page4
->cyl_ub
<< 16) + (page4
->cyl_mb
<< 8) +
669 p4_heads
= page4
->heads
;
673 * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600.
675 if (p4_rpm
< MIN_RPM
|| p4_rpm
> MAX_RPM
) {
676 err_print("Mode sense page(4) reports rpm value as %d,"
677 " adjusting it to %d\n", p4_rpm
, AVG_RPM
);
681 if (p4_cylinders
<= 0 || p4_heads
<= 0)
684 format_time
= ((scsi_format_revolutions
* p4_heads
*
685 p4_cylinders
) + p4_rpm
) / p4_rpm
;
687 if (option_msg
&& diag_msg
) {
688 err_print(" pcyl: %d\n", p4_cylinders
);
689 err_print(" heads: %d\n", p4_heads
);
690 err_print(" rpm: %d\n", p4_rpm
);
691 err_print("format_time: %d minutes\n", format_time
);
693 return (format_time
);
697 * Check disk error recovery parameters via mode sense.
698 * Issue a mode select if we need to change something.
702 scsi_ms_page1(scsi2_flag
)
705 struct mode_err_recov
*page1
;
706 struct mode_err_recov
*fixed
;
707 struct scsi_ms_header header
;
708 struct scsi_ms_header fixed_hdr
;
715 struct mode_err_recov page1
;
716 char rawbuf
[MAX_MODE_SENSE_SIZE
];
720 page1
= &u_page1
.page1
;
721 fixed
= &u_fixed
.page1
;
724 * If debugging, issue mode senses on the default and
727 if (option_msg
&& diag_msg
) {
728 (void) uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
729 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page1
,
730 MAX_MODE_SENSE_SIZE
, &header
);
731 (void) uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
732 MODE_SENSE_PC_CURRENT
, (caddr_t
)page1
,
733 MAX_MODE_SENSE_SIZE
, &header
);
737 * Issue a mode sense to determine the saved parameters
738 * If the saved values fail, use the current instead.
740 status
= uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
741 MODE_SENSE_PC_SAVED
, (caddr_t
)page1
,
742 MAX_MODE_SENSE_SIZE
, &header
);
744 status
= uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
745 MODE_SENSE_PC_CURRENT
, (caddr_t
)page1
,
746 MAX_MODE_SENSE_SIZE
, &header
);
753 * We only need the common subset between the CCS
754 * and SCSI-2 structures, so we can treat both
755 * cases identically. Whatever the drive gives
756 * us, we return to the drive in the mode select,
757 * delta'ed by whatever we want to change.
759 length
= MODESENSE_PAGE_LEN(page1
);
760 if (length
< MIN_PAGE1_LEN
) {
765 * Ask for changeable parameters.
767 status
= uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
768 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
769 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
770 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE1_LEN
) {
775 * We need to issue a mode select only if one or more
776 * parameters need to be changed, and those parameters
777 * are flagged by the drive as changeable.
780 tmp1
= page1
->read_retry_count
;
781 tmp2
= page1
->write_retry_count
;
782 if (cur_dtype
->dtype_options
& SUP_READ_RETRIES
&&
783 fixed
->read_retry_count
!= 0) {
784 flag
|= (page1
->read_retry_count
!=
785 cur_dtype
->dtype_read_retries
);
786 page1
->read_retry_count
= cur_dtype
->dtype_read_retries
;
789 if (cur_dtype
->dtype_options
& SUP_WRITE_RETRIES
&&
790 fixed
->write_retry_count
!= 0) {
791 flag
|= (page1
->write_retry_count
!=
792 cur_dtype
->dtype_write_retries
);
793 page1
->write_retry_count
=
794 cur_dtype
->dtype_write_retries
;
798 * Report any changes so far...
800 if (flag
&& option_msg
) {
802 "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n",
803 page1
->read_retry_count
, tmp1
,
804 page1
->write_retry_count
, tmp2
);
807 * Apply any changes requested via the change list method
809 flag
|= apply_chg_list(DAD_MODE_ERR_RECOV
, length
,
810 (uchar_t
*)page1
, (uchar_t
*)fixed
,
811 cur_dtype
->dtype_chglist
);
813 * If no changes required, do not issue a mode select
819 * We always want to set the Page Format bit for mode
820 * selects. Set the Save Page bit if the drive indicates
821 * that it can save this page via the mode sense.
823 sp_flags
= MODE_SELECT_PF
;
824 if (page1
->mode_page
.ps
) {
825 sp_flags
|= MODE_SELECT_SP
;
827 page1
->mode_page
.ps
= 0;
828 header
.mode_header
.length
= 0;
829 header
.mode_header
.device_specific
= 0;
830 status
= uscsi_mode_select(cur_file
, DAD_MODE_ERR_RECOV
,
831 sp_flags
, (caddr_t
)page1
, length
, &header
);
832 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
833 /* If failed, try not saving mode select params. */
834 sp_flags
&= ~MODE_SELECT_SP
;
835 status
= uscsi_mode_select(cur_file
, DAD_MODE_ERR_RECOV
,
836 sp_flags
, (caddr_t
)page1
, length
, &header
);
838 if (status
&& option_msg
) {
840 Warning: Using default error recovery parameters.\n\n");
844 * If debugging, issue mode senses on the current and
845 * saved values, so we can see the result of the mode
848 if (option_msg
&& diag_msg
) {
849 (void) uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
850 MODE_SENSE_PC_CURRENT
, (caddr_t
)page1
,
851 MAX_MODE_SENSE_SIZE
, &header
);
852 (void) uscsi_mode_sense(cur_file
, DAD_MODE_ERR_RECOV
,
853 MODE_SENSE_PC_SAVED
, (caddr_t
)page1
,
854 MAX_MODE_SENSE_SIZE
, &header
);
861 * Check disk disconnect/reconnect parameters via mode sense.
862 * Issue a mode select if we need to change something.
866 scsi_ms_page2(scsi2_flag
)
869 struct mode_disco_reco
*page2
;
870 struct mode_disco_reco
*fixed
;
871 struct scsi_ms_header header
;
872 struct scsi_ms_header fixed_hdr
;
878 struct mode_disco_reco page2
;
879 char rawbuf
[MAX_MODE_SENSE_SIZE
];
882 page2
= &u_page2
.page2
;
883 fixed
= &u_fixed
.page2
;
886 * If debugging, issue mode senses on the default and
889 if (option_msg
&& diag_msg
) {
890 (void) uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
891 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page2
,
892 MAX_MODE_SENSE_SIZE
, &header
);
893 (void) uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
894 MODE_SENSE_PC_CURRENT
, (caddr_t
)page2
,
895 MAX_MODE_SENSE_SIZE
, &header
);
899 * Issue a mode sense to determine the saved parameters
900 * If the saved values fail, use the current instead.
902 status
= uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
903 MODE_SENSE_PC_SAVED
, (caddr_t
)page2
,
904 MAX_MODE_SENSE_SIZE
, &header
);
906 status
= uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
907 MODE_SENSE_PC_CURRENT
, (caddr_t
)page2
,
908 MAX_MODE_SENSE_SIZE
, &header
);
915 * We only need the common subset between the CCS
916 * and SCSI-2 structures, so we can treat both
917 * cases identically. Whatever the drive gives
918 * us, we return to the drive in the mode select,
919 * delta'ed by whatever we want to change.
921 length
= MODESENSE_PAGE_LEN(page2
);
922 if (length
< MIN_PAGE2_LEN
) {
927 * Ask for changeable parameters.
929 status
= uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
930 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
931 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
932 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE2_LEN
) {
937 * We need to issue a mode select only if one or more
938 * parameters need to be changed, and those parameters
939 * are flagged by the drive as changeable.
943 * Apply any changes requested via the change list method
945 flag
|= apply_chg_list(MODEPAGE_DISCO_RECO
, length
,
946 (uchar_t
*)page2
, (uchar_t
*)fixed
,
947 cur_dtype
->dtype_chglist
);
949 * If no changes required, do not issue a mode select
955 * We always want to set the Page Format bit for mode
956 * selects. Set the Save Page bit if the drive indicates
957 * that it can save this page via the mode sense.
959 sp_flags
= MODE_SELECT_PF
;
960 if (page2
->mode_page
.ps
) {
961 sp_flags
|= MODE_SELECT_SP
;
963 page2
->mode_page
.ps
= 0;
964 header
.mode_header
.length
= 0;
965 header
.mode_header
.device_specific
= 0;
966 status
= uscsi_mode_select(cur_file
, MODEPAGE_DISCO_RECO
,
967 MODE_SELECT_SP
, (caddr_t
)page2
, length
, &header
);
968 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
969 /* If failed, try not saving mode select params. */
970 sp_flags
&= ~MODE_SELECT_SP
;
971 status
= uscsi_mode_select(cur_file
, MODEPAGE_DISCO_RECO
,
972 sp_flags
, (caddr_t
)page2
, length
, &header
);
974 if (status
&& option_msg
) {
975 err_print("Warning: Using default .\n\n");
979 * If debugging, issue mode senses on the current and
980 * saved values, so we can see the result of the mode
983 if (option_msg
&& diag_msg
) {
984 (void) uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
985 MODE_SENSE_PC_CURRENT
, (caddr_t
)page2
,
986 MAX_MODE_SENSE_SIZE
, &header
);
987 (void) uscsi_mode_sense(cur_file
, MODEPAGE_DISCO_RECO
,
988 MODE_SENSE_PC_SAVED
, (caddr_t
)page2
,
989 MAX_MODE_SENSE_SIZE
, &header
);
996 * Check disk format parameters via mode sense.
997 * Issue a mode select if we need to change something.
1001 scsi_ms_page3(scsi2_flag
)
1004 struct mode_format
*page3
;
1005 struct mode_format
*fixed
;
1006 struct scsi_ms_header header
;
1007 struct scsi_ms_header fixed_hdr
;
1009 int tmp1
, tmp2
, tmp3
;
1010 int tmp4
, tmp5
, tmp6
;
1015 struct mode_format page3
;
1016 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1020 page3
= &u_page3
.page3
;
1021 fixed
= &u_fixed
.page3
;
1024 * If debugging, issue mode senses on the default and
1027 if (option_msg
&& diag_msg
) {
1028 (void) uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1029 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page3
,
1030 MAX_MODE_SENSE_SIZE
, &header
);
1031 (void) uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1032 MODE_SENSE_PC_CURRENT
, (caddr_t
)page3
,
1033 MAX_MODE_SENSE_SIZE
, &header
);
1037 * Issue a mode sense to determine the saved parameters
1038 * If the saved values fail, use the current instead.
1040 status
= uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1041 MODE_SENSE_PC_SAVED
, (caddr_t
)page3
,
1042 MAX_MODE_SENSE_SIZE
, &header
);
1044 status
= uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1045 MODE_SENSE_PC_CURRENT
, (caddr_t
)page3
,
1046 MAX_MODE_SENSE_SIZE
, &header
);
1053 * We only need the common subset between the CCS
1054 * and SCSI-2 structures, so we can treat both
1055 * cases identically. Whatever the drive gives
1056 * us, we return to the drive in the mode select,
1057 * delta'ed by whatever we want to change.
1059 length
= MODESENSE_PAGE_LEN(page3
);
1060 if (length
< MIN_PAGE3_LEN
) {
1065 * Ask for changeable parameters.
1067 status
= uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1068 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
1069 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
1070 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE3_LEN
) {
1075 * We need to issue a mode select only if one or more
1076 * parameters need to be changed, and those parameters
1077 * are flagged by the drive as changeable.
1079 tmp1
= page3
->track_skew
;
1080 tmp2
= page3
->cylinder_skew
;
1081 tmp3
= page3
->sect_track
;
1082 tmp4
= page3
->tracks_per_zone
;
1083 tmp5
= page3
->alt_tracks_vol
;
1084 tmp6
= page3
->alt_sect_zone
;
1086 flag
= (page3
->data_bytes_sect
!= cur_blksz
);
1087 page3
->data_bytes_sect
= cur_blksz
;
1089 flag
|= (page3
->interleave
!= 1);
1090 page3
->interleave
= 1;
1092 if (cur_dtype
->dtype_options
& SUP_CYLSKEW
&&
1093 fixed
->cylinder_skew
!= 0) {
1094 flag
|= (page3
->cylinder_skew
!= cur_dtype
->dtype_cyl_skew
);
1095 page3
->cylinder_skew
= cur_dtype
->dtype_cyl_skew
;
1097 if (cur_dtype
->dtype_options
& SUP_TRKSKEW
&&
1098 fixed
->track_skew
!= 0) {
1099 flag
|= (page3
->track_skew
!= cur_dtype
->dtype_trk_skew
);
1100 page3
->track_skew
= cur_dtype
->dtype_trk_skew
;
1102 if (cur_dtype
->dtype_options
& SUP_PSECT
&&
1103 fixed
->sect_track
!= 0) {
1104 flag
|= (page3
->sect_track
!= psect
);
1105 page3
->sect_track
= (ushort_t
)psect
;
1107 if (cur_dtype
->dtype_options
& SUP_TRKS_ZONE
&&
1108 fixed
->tracks_per_zone
!= 0) {
1109 flag
|= (page3
->tracks_per_zone
!= cur_dtype
->dtype_trks_zone
);
1110 page3
->tracks_per_zone
= cur_dtype
->dtype_trks_zone
;
1112 if (cur_dtype
->dtype_options
& SUP_ASECT
&&
1113 fixed
->alt_sect_zone
!= 0) {
1114 flag
|= (page3
->alt_sect_zone
!= cur_dtype
->dtype_asect
);
1115 page3
->alt_sect_zone
= cur_dtype
->dtype_asect
;
1117 if (cur_dtype
->dtype_options
& SUP_ATRKS
&&
1118 fixed
->alt_tracks_vol
!= 0) {
1119 flag
|= (page3
->alt_tracks_vol
!= cur_dtype
->dtype_atrks
);
1120 page3
->alt_tracks_vol
= cur_dtype
->dtype_atrks
;
1123 * Notify user of any changes so far
1125 if (flag
&& option_msg
) {
1126 fmt_print("PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ",
1127 page3
->track_skew
, tmp1
, page3
->cylinder_skew
, tmp2
);
1128 fmt_print("sects/trk= %d (%d)\n", page3
->sect_track
, tmp3
);
1129 fmt_print(" trks/zone= %d (%d) alt trks= %d (%d) ",
1130 page3
->tracks_per_zone
, tmp4
,
1131 page3
->alt_tracks_vol
, tmp5
);
1132 fmt_print("alt sects/zone= %d (%d)\n",
1133 page3
->alt_sect_zone
, tmp6
);
1136 * Apply any changes requested via the change list method
1138 flag
|= apply_chg_list(DAD_MODE_FORMAT
, length
,
1139 (uchar_t
*)page3
, (uchar_t
*)fixed
,
1140 cur_dtype
->dtype_chglist
);
1142 * If no changes required, do not issue a mode select
1148 * Issue a mode select
1151 * We always want to set the Page Format bit for mode
1152 * selects. Set the Save Page bit if the drive indicates
1153 * that it can save this page via the mode sense.
1155 sp_flags
= MODE_SELECT_PF
;
1156 if (page3
->mode_page
.ps
) {
1157 sp_flags
|= MODE_SELECT_SP
;
1159 page3
->mode_page
.ps
= 0;
1160 header
.mode_header
.length
= 0;
1161 header
.mode_header
.device_specific
= 0;
1162 status
= uscsi_mode_select(cur_file
, DAD_MODE_FORMAT
,
1163 MODE_SELECT_SP
, (caddr_t
)page3
, length
, &header
);
1164 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
1165 /* If failed, try not saving mode select params. */
1166 sp_flags
&= ~MODE_SELECT_SP
;
1167 status
= uscsi_mode_select(cur_file
, DAD_MODE_FORMAT
,
1168 sp_flags
, (caddr_t
)page3
, length
, &header
);
1170 if (status
&& option_msg
) {
1171 err_print("Warning: Using default drive format parameters.\n");
1172 err_print("Warning: Drive format may not be correct.\n\n");
1176 * If debugging, issue mode senses on the current and
1177 * saved values, so we can see the result of the mode
1180 if (option_msg
&& diag_msg
) {
1181 (void) uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1182 MODE_SENSE_PC_CURRENT
, (caddr_t
)page3
,
1183 MAX_MODE_SENSE_SIZE
, &header
);
1184 (void) uscsi_mode_sense(cur_file
, DAD_MODE_FORMAT
,
1185 MODE_SENSE_PC_SAVED
, (caddr_t
)page3
,
1186 MAX_MODE_SENSE_SIZE
, &header
);
1193 * Check disk geometry parameters via mode sense.
1194 * Issue a mode select if we need to change something.
1198 scsi_ms_page4(scsi2_flag
)
1201 struct mode_geometry
*page4
;
1202 struct mode_geometry
*fixed
;
1203 struct scsi_ms_header header
;
1204 struct scsi_ms_header fixed_hdr
;
1211 struct mode_geometry page4
;
1212 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1215 page4
= &u_page4
.page4
;
1216 fixed
= &u_fixed
.page4
;
1219 * If debugging, issue mode senses on the default and
1222 if (option_msg
&& diag_msg
) {
1223 (void) uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1224 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page4
,
1225 MAX_MODE_SENSE_SIZE
, &header
);
1226 (void) uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1227 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
,
1228 MAX_MODE_SENSE_SIZE
, &header
);
1232 * Issue a mode sense to determine the saved parameters
1233 * If the saved values fail, use the current instead.
1235 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1236 MODE_SENSE_PC_SAVED
, (caddr_t
)page4
,
1237 MAX_MODE_SENSE_SIZE
, &header
);
1239 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1240 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
,
1241 MAX_MODE_SENSE_SIZE
, &header
);
1248 * We only need the common subset between the CCS
1249 * and SCSI-2 structures, so we can treat both
1250 * cases identically. Whatever the drive gives
1251 * us, we return to the drive in the mode select,
1252 * delta'ed by whatever we want to change.
1254 length
= MODESENSE_PAGE_LEN(page4
);
1255 if (length
< MIN_PAGE4_LEN
) {
1260 * Ask for changeable parameters.
1262 status
= uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1263 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
1264 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
1265 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE4_LEN
) {
1270 * We need to issue a mode select only if one or more
1271 * parameters need to be changed, and those parameters
1272 * are flagged by the drive as changeable.
1274 tmp1
= (page4
->cyl_ub
<< 16) + (page4
->cyl_mb
<< 8) + page4
->cyl_lb
;
1275 tmp2
= page4
->heads
;
1278 if ((cur_dtype
->dtype_options
& SUP_PHEAD
) && fixed
->heads
!= 0) {
1279 flag
|= (page4
->heads
!= phead
);
1280 page4
->heads
= phead
;
1283 * Notify user of changes so far
1285 if (flag
&& option_msg
) {
1286 fmt_print("PAGE 4: cylinders= %d heads= %d (%d)\n",
1287 tmp1
, page4
->heads
, tmp2
);
1290 * Apply any changes requested via the change list method
1292 flag
|= apply_chg_list(DAD_MODE_GEOMETRY
, length
,
1293 (uchar_t
*)page4
, (uchar_t
*)fixed
,
1294 cur_dtype
->dtype_chglist
);
1296 * If no changes required, do not issue a mode select
1302 * Issue a mode select
1305 * We always want to set the Page Format bit for mode
1306 * selects. Set the Save Page bit if the drive indicates
1307 * that it can save this page via the mode sense.
1309 sp_flags
= MODE_SELECT_PF
;
1310 if (page4
->mode_page
.ps
) {
1311 sp_flags
|= MODE_SELECT_SP
;
1313 page4
->mode_page
.ps
= 0;
1314 header
.mode_header
.length
= 0;
1315 header
.mode_header
.device_specific
= 0;
1316 status
= uscsi_mode_select(cur_file
, DAD_MODE_GEOMETRY
,
1317 MODE_SELECT_SP
, (caddr_t
)page4
, length
, &header
);
1318 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
1319 /* If failed, try not saving mode select params. */
1320 sp_flags
&= ~MODE_SELECT_SP
;
1321 status
= uscsi_mode_select(cur_file
, DAD_MODE_GEOMETRY
,
1322 sp_flags
, (caddr_t
)page4
, length
, &header
);
1324 if (status
&& option_msg
) {
1325 err_print("Warning: Using default drive geometry.\n\n");
1329 * If debugging, issue mode senses on the current and
1330 * saved values, so we can see the result of the mode
1333 if (option_msg
&& diag_msg
) {
1334 (void) uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1335 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
,
1336 MAX_MODE_SENSE_SIZE
, &header
);
1337 (void) uscsi_mode_sense(cur_file
, DAD_MODE_GEOMETRY
,
1338 MODE_SENSE_PC_SAVED
, (caddr_t
)page4
,
1339 MAX_MODE_SENSE_SIZE
, &header
);
1346 * Check SCSI-2 disk cache parameters via mode sense.
1347 * Issue a mode select if we need to change something.
1351 scsi_ms_page8(scsi2_flag
)
1354 struct mode_cache
*page8
;
1355 struct mode_cache
*fixed
;
1356 struct scsi_ms_header header
;
1357 struct scsi_ms_header fixed_hdr
;
1363 struct mode_cache page8
;
1364 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1367 page8
= &u_page8
.page8
;
1368 fixed
= &u_fixed
.page8
;
1371 * Only SCSI-2 devices support this page
1378 * If debugging, issue mode senses on the default and
1381 if (option_msg
&& diag_msg
) {
1382 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1383 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page8
,
1384 MAX_MODE_SENSE_SIZE
, &header
);
1385 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1386 MODE_SENSE_PC_CURRENT
, (caddr_t
)page8
,
1387 MAX_MODE_SENSE_SIZE
, &header
);
1391 * Issue a mode sense to determine the saved parameters
1392 * If the saved values fail, use the current instead.
1394 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1395 MODE_SENSE_PC_SAVED
, (caddr_t
)page8
,
1396 MAX_MODE_SENSE_SIZE
, &header
);
1398 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1399 MODE_SENSE_PC_CURRENT
, (caddr_t
)page8
,
1400 MAX_MODE_SENSE_SIZE
, &header
);
1407 * We only need the common subset between the CCS
1408 * and SCSI-2 structures, so we can treat both
1409 * cases identically. Whatever the drive gives
1410 * us, we return to the drive in the mode select,
1411 * delta'ed by whatever we want to change.
1413 length
= MODESENSE_PAGE_LEN(page8
);
1414 if (length
< MIN_PAGE8_LEN
) {
1419 * Ask for changeable parameters.
1421 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1422 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
1423 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
1424 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE8_LEN
) {
1429 * We need to issue a mode select only if one or more
1430 * parameters need to be changed, and those parameters
1431 * are flagged by the drive as changeable.
1435 * Apply any changes requested via the change list method
1437 flag
|= apply_chg_list(DAD_MODE_CACHE
, length
,
1438 (uchar_t
*)page8
, (uchar_t
*)fixed
,
1439 cur_dtype
->dtype_chglist
);
1441 * If no changes required, do not issue a mode select
1447 * Issue a mode select
1450 * We always want to set the Page Format bit for mode
1451 * selects. Set the Save Page bit if the drive indicates
1452 * that it can save this page via the mode sense.
1454 sp_flags
= MODE_SELECT_PF
;
1455 if (page8
->mode_page
.ps
) {
1456 sp_flags
|= MODE_SELECT_SP
;
1458 page8
->mode_page
.ps
= 0;
1459 header
.mode_header
.length
= 0;
1460 header
.mode_header
.device_specific
= 0;
1461 status
= uscsi_mode_select(cur_file
, DAD_MODE_CACHE
,
1462 sp_flags
, (caddr_t
)page8
, length
, &header
);
1463 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
1464 /* If failed, try not saving mode select params. */
1465 sp_flags
&= ~MODE_SELECT_SP
;
1466 status
= uscsi_mode_select(cur_file
, DAD_MODE_CACHE
,
1467 sp_flags
, (caddr_t
)page8
, length
, &header
);
1469 if (status
&& option_msg
) {
1471 Warning: Using default SCSI-2 cache parameters.\n\n");
1475 * If debugging, issue mode senses on the current and
1476 * saved values, so we can see the result of the mode
1479 if (option_msg
&& diag_msg
) {
1480 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1481 MODE_SENSE_PC_CURRENT
, (caddr_t
)page8
,
1482 MAX_MODE_SENSE_SIZE
, &header
);
1483 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE
,
1484 MODE_SENSE_PC_SAVED
, (caddr_t
)page8
,
1485 MAX_MODE_SENSE_SIZE
, &header
);
1492 * Check CCS disk cache parameters via mode sense.
1493 * Issue a mode select if we need to change something.
1497 scsi_ms_page38(scsi2_flag
)
1500 struct mode_cache_ccs
*page38
;
1501 struct mode_cache_ccs
*fixed
;
1502 struct scsi_ms_header header
;
1503 struct scsi_ms_header fixed_hdr
;
1505 int tmp1
, tmp2
, tmp3
, tmp4
;
1510 struct mode_cache_ccs page38
;
1511 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1512 } u_page38
, u_fixed
;
1515 * First, determine if we need to look at page 38 at all.
1516 * Not all devices support it.
1518 if (((cur_dtype
->dtype_options
& (SUP_CACHE
| SUP_PREFETCH
|
1519 SUP_CACHE_MIN
| SUP_CACHE_MAX
)) == 0) &&
1520 (!chg_list_affects_page(cur_dtype
->dtype_chglist
,
1525 page38
= &u_page38
.page38
;
1526 fixed
= &u_fixed
.page38
;
1529 * If debugging, issue mode senses on the default and
1532 if (option_msg
&& diag_msg
) {
1533 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1534 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page38
,
1535 MAX_MODE_SENSE_SIZE
, &header
);
1536 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1537 MODE_SENSE_PC_CURRENT
, (caddr_t
)page38
,
1538 MAX_MODE_SENSE_SIZE
, &header
);
1542 * Issue a mode sense to determine the saved parameters
1543 * If the saved values fail, use the current instead.
1545 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1546 MODE_SENSE_PC_SAVED
, (caddr_t
)page38
,
1547 MAX_MODE_SENSE_SIZE
, &header
);
1549 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1550 MODE_SENSE_PC_CURRENT
, (caddr_t
)page38
,
1551 MAX_MODE_SENSE_SIZE
, &header
);
1558 * We only need the common subset between the CCS
1559 * and SCSI-2 structures, so we can treat both
1560 * cases identically. Whatever the drive gives
1561 * us, we return to the drive in the mode select,
1562 * delta'ed by whatever we want to change.
1564 length
= MODESENSE_PAGE_LEN(page38
);
1565 if (length
< MIN_PAGE38_LEN
) {
1570 * Ask for changeable parameters.
1572 status
= uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1573 MODE_SENSE_PC_CHANGEABLE
, (caddr_t
)fixed
,
1574 MAX_MODE_SENSE_SIZE
, &fixed_hdr
);
1575 if (status
|| MODESENSE_PAGE_LEN(fixed
) < MIN_PAGE38_LEN
) {
1580 * We need to issue a mode select only if one or more
1581 * parameters need to be changed, and those parameters
1582 * are flagged by the drive as changeable.
1584 tmp1
= page38
->mode
;
1585 tmp2
= page38
->threshold
;
1586 tmp3
= page38
->min_prefetch
;
1587 tmp4
= page38
->max_prefetch
;
1590 if ((cur_dtype
->dtype_options
& SUP_CACHE
) &&
1591 (fixed
->mode
& cur_dtype
->dtype_cache
) ==
1592 cur_dtype
->dtype_cache
) {
1593 flag
|= (page38
->mode
!= cur_dtype
->dtype_cache
);
1594 page38
->mode
= cur_dtype
->dtype_cache
;
1596 if ((cur_dtype
->dtype_options
& SUP_PREFETCH
) &&
1597 (fixed
->threshold
& cur_dtype
->dtype_threshold
) ==
1598 cur_dtype
->dtype_threshold
) {
1599 flag
|= (page38
->threshold
!= cur_dtype
->dtype_threshold
);
1600 page38
->threshold
= cur_dtype
->dtype_threshold
;
1602 if ((cur_dtype
->dtype_options
& SUP_CACHE_MIN
) &&
1603 (fixed
->min_prefetch
& cur_dtype
->dtype_prefetch_min
) ==
1604 cur_dtype
->dtype_prefetch_min
) {
1605 flag
|= (page38
->min_prefetch
!= cur_dtype
->dtype_prefetch_min
);
1606 page38
->min_prefetch
= cur_dtype
->dtype_prefetch_min
;
1608 if ((cur_dtype
->dtype_options
& SUP_CACHE_MAX
) &&
1609 (fixed
->max_prefetch
& cur_dtype
->dtype_prefetch_max
) ==
1610 cur_dtype
->dtype_prefetch_max
) {
1611 flag
|= (page38
->max_prefetch
!= cur_dtype
->dtype_prefetch_max
);
1612 page38
->max_prefetch
= cur_dtype
->dtype_prefetch_max
;
1615 * Notify the user of changes up to this point
1617 if (flag
&& option_msg
) {
1618 fmt_print("PAGE 38: cache mode= 0x%x (0x%x)\n",
1619 page38
->mode
, tmp1
);
1620 fmt_print(" min. prefetch multiplier= %d ",
1621 page38
->min_multiplier
);
1622 fmt_print("max. prefetch multiplier= %d\n",
1623 page38
->max_multiplier
);
1624 fmt_print(" threshold= %d (%d) ",
1625 page38
->threshold
, tmp2
);
1626 fmt_print("min. prefetch= %d (%d) ",
1627 page38
->min_prefetch
, tmp3
);
1628 fmt_print("max. prefetch= %d (%d)\n",
1629 page38
->max_prefetch
, tmp4
);
1632 * Apply any changes requested via the change list method
1634 flag
|= apply_chg_list(DAD_MODE_CACHE_CCS
, length
,
1635 (uchar_t
*)page38
, (uchar_t
*)fixed
,
1636 cur_dtype
->dtype_chglist
);
1638 * If no changes required, do not issue a mode select
1644 * Issue a mode select
1646 * We always want to set the Page Format bit for mode
1647 * selects. Set the Save Page bit if the drive indicates
1648 * that it can save this page via the mode sense.
1650 sp_flags
= MODE_SELECT_PF
;
1651 if (page38
->mode_page
.ps
) {
1652 sp_flags
|= MODE_SELECT_SP
;
1654 page38
->mode_page
.ps
= 0;
1655 header
.mode_header
.length
= 0;
1656 header
.mode_header
.device_specific
= 0;
1657 status
= uscsi_mode_select(cur_file
, DAD_MODE_CACHE_CCS
,
1658 sp_flags
, (caddr_t
)page38
, length
, &header
);
1659 if (status
&& (sp_flags
& MODE_SELECT_SP
)) {
1660 /* If failed, try not saving mode select params. */
1661 sp_flags
&= ~MODE_SELECT_SP
;
1662 status
= uscsi_mode_select(cur_file
, DAD_MODE_CACHE_CCS
,
1663 sp_flags
, (caddr_t
)page38
, length
, &header
);
1665 if (status
&& option_msg
) {
1666 err_print("Warning: Using default CCS cache parameters.\n\n");
1670 * If debugging, issue mode senses on the current and
1671 * saved values, so we can see the result of the mode
1674 if (option_msg
&& diag_msg
) {
1675 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1676 MODE_SENSE_PC_CURRENT
, (caddr_t
)page38
,
1677 MAX_MODE_SENSE_SIZE
, &header
);
1678 (void) uscsi_mode_sense(cur_file
, DAD_MODE_CACHE_CCS
,
1679 MODE_SENSE_PC_SAVED
, (caddr_t
)page38
,
1680 MAX_MODE_SENSE_SIZE
, &header
);
1688 * Extract the manufacturer's defect list.
1692 struct defect_list
*list
;
1696 i
= scsi_read_defect_data(list
, DLD_MAN_DEF_LIST
);
1699 list
->flags
&= ~LIST_PGLIST
;
1704 * Extract the current defect list.
1705 * For embedded scsi drives, this means both the manufacturer's (P)
1706 * and the grown (G) lists.
1710 struct defect_list
*list
;
1714 i
= scsi_read_defect_data(list
, DLD_GROWN_DEF_LIST
|DLD_MAN_DEF_LIST
);
1717 list
->flags
|= LIST_PGLIST
;
1723 * Extract the grown list only
1727 struct defect_list
*list
;
1731 i
= scsi_read_defect_data(list
, DLD_GROWN_DEF_LIST
);
1734 list
->flags
|= LIST_PGLIST
;
1740 scsi_read_defect_data(list
, pglist_flags
)
1741 struct defect_list
*list
;
1744 struct uscsi_cmd ucmd
;
1747 struct scsi_defect_list
*defects
;
1748 struct scsi_defect_list def_list
;
1749 struct scsi_defect_hdr
*hdr
;
1752 int len
; /* returned defect list length */
1753 struct scsi_extended_sense
*rq
;
1755 hdr
= (struct scsi_defect_hdr
*)&def_list
;
1758 * First get length of list by asking for the header only.
1760 (void) memset((char *)&def_list
, 0, sizeof (def_list
));
1763 * Build and execute the uscsi ioctl
1765 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
1766 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
1767 (void) memset((char *)rqbuf
, 0, 255);
1768 cdb
.scc_cmd
= SCMD_READ_DEFECT_LIST
;
1769 FORMG1COUNT(&cdb
, sizeof (struct scsi_defect_hdr
));
1770 cdb
.cdb_opaque
[2] = pglist_flags
| DLD_BFI_FORMAT
;
1771 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
1772 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
1773 ucmd
.uscsi_bufaddr
= (caddr_t
)hdr
;
1774 ucmd
.uscsi_buflen
= sizeof (struct scsi_defect_hdr
);
1775 ucmd
.uscsi_rqbuf
= rqbuf
;
1776 ucmd
.uscsi_rqlen
= sizeof (rqbuf
);
1777 ucmd
.uscsi_rqresid
= sizeof (rqbuf
);
1778 rq
= (struct scsi_extended_sense
*)ucmd
.uscsi_rqbuf
;
1780 status
= uscsi_cmd(cur_file
, &ucmd
,
1781 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
1785 * check if read_defect_list_is_supported.
1787 if (ucmd
.uscsi_rqstatus
== STATUS_GOOD
&&
1788 rq
->es_key
== KEY_ILLEGAL_REQUEST
&&
1789 rq
->es_add_code
== INVALID_OPCODE
) {
1790 err_print("\nWARNING: Current Disk does not support"
1791 " defect lists. \n");
1794 err_print("No %s defect list.\n",
1795 pglist_flags
& DLD_GROWN_DEF_LIST
?
1796 "grown" : "manufacturer's");
1802 * Read the full list the second time
1804 hdr
->length
= BE_16(hdr
->length
);
1806 nbytes
= len
+ sizeof (struct scsi_defect_hdr
);
1808 defects
= zalloc(nbytes
);
1809 *(struct scsi_defect_hdr
*)defects
= *(struct scsi_defect_hdr
*)hdr
;
1811 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
1812 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
1813 cdb
.scc_cmd
= SCMD_READ_DEFECT_LIST
;
1814 FORMG1COUNT(&cdb
, nbytes
);
1815 cdb
.cdb_opaque
[2] = pglist_flags
| DLD_BFI_FORMAT
;
1816 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
1817 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
1818 ucmd
.uscsi_bufaddr
= (caddr_t
)defects
;
1819 ucmd
.uscsi_buflen
= nbytes
;
1820 status
= uscsi_cmd(cur_file
, &ucmd
,
1821 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
1824 err_print("can't read defect list 2nd time");
1825 destroy_data((char *)defects
);
1829 defects
->length
= BE_16(defects
->length
);
1831 if (len
!= hdr
->length
) {
1832 err_print("not enough defects");
1833 destroy_data((char *)defects
);
1836 scsi_convert_list_to_new(list
, (struct scsi_defect_list
*)defects
,
1838 destroy_data((char *)defects
);
1848 scsi_repair(bn
, flag
)
1852 struct uscsi_cmd ucmd
;
1854 struct scsi_reassign_blk defect_list
;
1857 * Build and execute the uscsi ioctl
1859 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
1860 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
1861 (void) memset((char *)&defect_list
, 0,
1862 sizeof (struct scsi_reassign_blk
));
1863 cdb
.scc_cmd
= SCMD_REASSIGN_BLOCK
;
1864 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
1865 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
1866 ucmd
.uscsi_bufaddr
= (caddr_t
)&defect_list
;
1867 ucmd
.uscsi_buflen
= sizeof (struct scsi_reassign_blk
);
1868 defect_list
.length
= sizeof (defect_list
.defect
);
1869 defect_list
.length
= BE_16(defect_list
.length
);
1870 defect_list
.defect
= bn
;
1871 defect_list
.defect
= BE_32(defect_list
.defect
);
1872 return (uscsi_cmd(cur_file
, &ucmd
,
1873 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
));
1877 * Convert a SCSI-style defect list to our generic format.
1878 * We can handle different format lists.
1881 scsi_convert_list_to_new(list
, def_list
, list_format
)
1882 struct defect_list
*list
;
1883 struct scsi_defect_list
*def_list
;
1886 register struct scsi_bfi_defect
*old_defect
, *old_defect1
;
1887 register struct defect_entry
*new_defect
;
1888 register int len
, new_len
, obfi
, nbfi
;
1890 int old_cyl
, new_cyl
;
1894 switch (list_format
) {
1896 case DLD_BFI_FORMAT
:
1898 * Allocate space for the rest of the list.
1900 len
= def_list
->length
/ sizeof (struct scsi_bfi_defect
);
1901 old_defect
= def_list
->list
;
1902 new_defect
= (struct defect_entry
*)
1903 zalloc(deflist_size(cur_blksz
, len
) *
1906 list
->header
.magicno
= (uint_t
)DEFECT_MAGIC
;
1907 list
->list
= new_defect
;
1909 for (i
= 0, new_len
= 0; i
< len
; new_defect
++, new_len
++) {
1910 cp
= (unsigned char *)old_defect
;
1911 new_defect
->cyl
= (cp
[0] << 16 | cp
[1] << 8) | cp
[2];
1912 new_defect
->head
= old_defect
->head
;
1913 new_defect
->bfi
= (int)old_defect
->bytes_from_index
;
1914 new_defect
->bfi
= BE_32(new_defect
->bfi
);
1915 new_defect
->nbits
= 0; /* size of defect */
1916 old_defect1
= old_defect
++;
1919 * Since we reached the end of the list, old_defect
1920 * now points to an invalid reference, since it got
1921 * incremented in the above operation. So we don't
1922 * need to proceed further. new_len needs to be
1923 * incremented to account for the last element.
1929 obfi
= new_defect
->bfi
;
1930 nbfi
= (int)old_defect
->bytes_from_index
;
1933 old_cyl
= new_defect
->cyl
;
1934 cp
= (unsigned char *)old_defect
;
1935 new_cyl
= (cp
[0] << 16 | cp
[1] << 8) | cp
[2];
1939 * Merge adjacent contiguous defect entries into one
1940 * and update the length of the defect
1943 (old_cyl
== new_cyl
) &&
1944 (old_defect
->head
== old_defect1
->head
) &&
1945 (nbfi
== (obfi
+ BITSPERBYTE
))) {
1946 old_defect1
= old_defect
++;
1947 cp
= (unsigned char *)old_defect
;
1948 new_cyl
= (cp
[0] << 16 | cp
[1] << 8) | cp
[2];
1949 obfi
= (int)old_defect1
->bytes_from_index
;
1951 nbfi
= (int)old_defect
->bytes_from_index
;
1953 new_defect
->nbits
+= (8*BITSPERBYTE
);
1958 list
->header
.count
= new_len
;
1962 err_print("scsi_convert_list_to_new: can't deal with it\n");
1967 (void) checkdefsum(list
, CK_MAKESUM
);
1973 * Execute a command and determine the result.
1974 * Uses the "uscsi" ioctl interface, which is
1977 * If the user wants request sense data to be returned
1978 * in case of error then , the "uscsi_cmd" structure
1979 * should have the request sense buffer allocated in
1984 uscsi_cmd(fd
, ucmd
, flags
)
1986 struct uscsi_cmd
*ucmd
;
1989 struct scsi_extended_sense
*rq
;
1996 * Set function flags for driver.
1998 ucmd
->uscsi_flags
= USCSI_ISOLATE
;
1999 if (flags
& F_SILENT
) {
2000 ucmd
->uscsi_flags
|= USCSI_SILENT
;
2002 if (flags
& F_RQENABLE
) {
2003 ucmd
->uscsi_flags
|= USCSI_RQENABLE
;
2007 * If this command will perform a read, set the USCSI_READ flag
2009 if (ucmd
->uscsi_buflen
> 0) {
2011 * uscsi_cdb is declared as a caddr_t, so any CDB
2012 * command byte with the MSB set will result in a
2013 * compiler error unless we cast to an unsigned value.
2015 switch ((uint8_t)ucmd
->uscsi_cdb
[0]) {
2017 case SCMD_READ
|SCMD_GROUP1
:
2018 case SCMD_READ
|SCMD_GROUP4
:
2019 case SCMD_MODE_SENSE
:
2021 case SCMD_READ_DEFECT_LIST
:
2022 case SCMD_READ_CAPACITY
:
2023 case SCMD_SVC_ACTION_IN_G4
:
2024 ucmd
->uscsi_flags
|= USCSI_READ
;
2030 * Set timeout: 30 seconds for all commands except format
2032 switch (ucmd
->uscsi_cdb
[0]) {
2034 if (ucmd
->uscsi_timeout
== 0) {
2035 ucmd
->uscsi_timeout
= scsi_format_timeout
;
2037 * Get the timeout value computed using page4 geometry.
2038 * add 50% margin to cover defect management overhead.
2039 * add another 50% margin to have a safe timeout.
2040 * If it exceeds 2 hours then use this value.
2042 if ((timeout
= scsi_format_time()) > 0) {
2043 timeout
*= 60; /* convert to seconds */
2046 * formatting drives with huge capacity
2047 * will cause these heuristics to come
2048 * up with times that overflow ~9 hours
2050 if (timeout
> SHRT_MAX
)
2052 if (timeout
> scsi_format_timeout
)
2053 ucmd
->uscsi_timeout
= timeout
;
2056 if (option_msg
&& diag_msg
) {
2057 err_print("format_timeout set to %d seconds, %d"
2058 " required\n", ucmd
->uscsi_timeout
, timeout
);
2063 ucmd
->uscsi_timeout
= 30; /* 30 seconds */
2068 * Set up Request Sense buffer
2070 ucmd
->uscsi_flags
|= USCSI_RQENABLE
;
2072 if (ucmd
->uscsi_rqbuf
== NULL
) {
2073 ucmd
->uscsi_rqbuf
= rqbuf
;
2074 ucmd
->uscsi_rqlen
= sizeof (rqbuf
);
2075 ucmd
->uscsi_rqresid
= sizeof (rqbuf
);
2077 ucmd
->uscsi_rqstatus
= IMPOSSIBLE_SCSI_STATUS
;
2080 * Clear global error state
2087 status
= ioctl(fd
, USCSICMD
, ucmd
);
2088 if (status
== 0 && ucmd
->uscsi_status
== 0) {
2093 * Check the status and return appropriate errors if the disk is
2094 * unavailable (could be formatting) or reserved (by other host).
2095 * In either case we can not talk to the disk now.
2097 if (status
== -1 && errno
== EAGAIN
) {
2098 disk_error
= DISK_STAT_UNAVAILABLE
;
2099 return (DSK_UNAVAILABLE
);
2101 if ((ucmd
->uscsi_status
& STATUS_MASK
) == STATUS_RESERVATION_CONFLICT
) {
2102 disk_error
= DISK_STAT_RESERVED
;
2103 return (DSK_RESERVED
);
2106 * Check for physically removed or completely unresponsive drive
2108 if (status
== -1 && !ucmd
->uscsi_status
&& errno
== EIO
) {
2109 disk_error
= DISK_STAT_UNAVAILABLE
;
2110 return (DSK_UNAVAILABLE
);
2114 * If an automatic Request Sense gave us valid
2115 * info about the error, we may be able to use
2116 * that to print a reasonable error msg.
2118 if (ucmd
->uscsi_rqstatus
== IMPOSSIBLE_SCSI_STATUS
) {
2119 if (option_msg
&& diag_msg
) {
2120 err_print("No request sense for command %s\n",
2121 scsi_find_command_name(ucmd
->uscsi_cdb
[0]));
2125 if (ucmd
->uscsi_rqstatus
!= STATUS_GOOD
) {
2126 if (option_msg
&& diag_msg
) {
2127 err_print("Request sense status for command %s: 0x%x\n",
2128 scsi_find_command_name(ucmd
->uscsi_cdb
[0]),
2129 ucmd
->uscsi_rqstatus
);
2133 rq
= (struct scsi_extended_sense
*)ucmd
->uscsi_rqbuf
;
2134 rqlen
= ucmd
->uscsi_rqlen
- ucmd
->uscsi_rqresid
;
2135 if ((((int)rq
->es_add_len
) + 8) < MIN_REQUEST_SENSE_LEN
||
2136 rq
->es_class
!= CLASS_EXTENDED_SENSE
||
2137 rqlen
< MIN_REQUEST_SENSE_LEN
) {
2139 err_print("Request sense for command %s failed\n",
2140 scsi_find_command_name(ucmd
->uscsi_cdb
[0]));
2142 if (option_msg
&& diag_msg
) {
2143 err_print("Sense data:\n");
2144 dump("", (caddr_t
)rqbuf
, rqlen
, HEX_ONLY
);
2147 disk_error
= DISK_STAT_UNAVAILABLE
;
2148 return (DSK_UNAVAILABLE
);
2155 * If the failed command is a Mode Select, and the
2156 * target is indicating that it has rounded one of
2157 * the mode select parameters, as defined in the SCSI-2
2158 * specification, then we should accept the command
2161 if (ucmd
->uscsi_cdb
[0] == SCMD_MODE_SELECT
) {
2162 if (rq
->es_key
== KEY_RECOVERABLE_ERROR
&&
2163 rq
->es_add_code
== ROUNDED_PARAMETER
&&
2164 rq
->es_qual_code
== 0) {
2169 switch (rq
->es_key
) {
2171 disk_error
= DISK_STAT_NOTREADY
;
2173 case KEY_DATA_PROTECT
:
2174 disk_error
= DISK_STAT_DATA_PROTECT
;
2178 if (flags
& F_ALLERRS
) {
2179 media_error
= (rq
->es_key
== KEY_MEDIUM_ERROR
);
2181 if (!(flags
& F_SILENT
) || option_msg
) {
2182 scsi_printerr(ucmd
, rq
, rqlen
);
2184 if ((rq
->es_key
!= KEY_RECOVERABLE_ERROR
) || (flags
& F_ALLERRS
)) {
2188 if (status
== -1 && errno
== EIO
) {
2189 disk_error
= DISK_STAT_UNAVAILABLE
;
2190 return (DSK_UNAVAILABLE
);
2198 * Execute a uscsi mode sense command.
2199 * This can only be used to return one page at a time.
2200 * Return the mode header/block descriptor and the actual
2201 * page data separately - this allows us to support
2202 * devices which return either 0 or 1 block descriptors.
2203 * Whatever a device gives us in the mode header/block descriptor
2204 * will be returned to it upon subsequent mode selects.
2207 uscsi_mode_sense(fd
, page_code
, page_control
, page_data
, page_size
, header
)
2208 int fd
; /* file descriptor */
2209 int page_code
; /* requested page number */
2210 int page_control
; /* current, changeable, etc. */
2211 caddr_t page_data
; /* place received data here */
2212 int page_size
; /* size of page_data */
2213 struct scsi_ms_header
*header
; /* mode header/block descriptor */
2215 caddr_t mode_sense_buf
;
2216 struct mode_header
*hdr
;
2217 struct mode_page
*pg
;
2219 struct uscsi_cmd ucmd
;
2224 assert(page_size
>= 0 && page_size
< 256);
2225 assert(page_control
== MODE_SENSE_PC_CURRENT
||
2226 page_control
== MODE_SENSE_PC_CHANGEABLE
||
2227 page_control
== MODE_SENSE_PC_DEFAULT
||
2228 page_control
== MODE_SENSE_PC_SAVED
);
2230 * Allocate a buffer for the mode sense headers
2231 * and mode sense data itself.
2233 nbytes
= sizeof (struct block_descriptor
) +
2234 sizeof (struct mode_header
) + page_size
;
2236 if ((mode_sense_buf
= malloc((uint_t
)nbytes
)) == NULL
) {
2237 err_print("cannot malloc %d bytes\n", nbytes
);
2242 * Build and execute the uscsi ioctl
2244 (void) memset(mode_sense_buf
, 0, nbytes
);
2245 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2246 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2247 cdb
.scc_cmd
= SCMD_MODE_SENSE
;
2248 FORMG0COUNT(&cdb
, (uchar_t
)nbytes
);
2249 cdb
.cdb_opaque
[2] = page_control
| page_code
;
2250 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2251 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2252 ucmd
.uscsi_bufaddr
= mode_sense_buf
;
2253 ucmd
.uscsi_buflen
= nbytes
;
2254 status
= uscsi_cmd(fd
, &ucmd
,
2255 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2258 err_print("Mode sense page 0x%x failed\n",
2261 free(mode_sense_buf
);
2266 * Verify that the returned data looks reasonabled,
2267 * find the actual page data, and copy it into the
2268 * user's buffer. Copy the mode_header and block_descriptor
2269 * into the header structure, which can then be used to
2270 * return the same data to the drive when issuing a mode select.
2272 hdr
= (struct mode_header
*)mode_sense_buf
;
2273 (void) memset((caddr_t
)header
, 0, sizeof (struct scsi_ms_header
));
2274 if (hdr
->bdesc_length
!= sizeof (struct block_descriptor
) &&
2275 hdr
->bdesc_length
!= 0) {
2278 \nMode sense page 0x%x: block descriptor length %d incorrect\n",
2279 page_code
, hdr
->bdesc_length
);
2281 dump("Mode sense: ", mode_sense_buf
,
2284 free(mode_sense_buf
);
2287 (void) memcpy((caddr_t
)header
, mode_sense_buf
,
2288 (int) (sizeof (struct mode_header
) + hdr
->bdesc_length
));
2289 pg
= (struct mode_page
*)((ulong_t
)mode_sense_buf
+
2290 sizeof (struct mode_header
) + hdr
->bdesc_length
);
2291 if (pg
->code
!= page_code
) {
2294 \nMode sense page 0x%x: incorrect page code 0x%x\n",
2295 page_code
, pg
->code
);
2297 dump("Mode sense: ", mode_sense_buf
,
2300 free(mode_sense_buf
);
2304 * Accept up to "page_size" bytes of mode sense data.
2305 * This allows us to accept both CCS and SCSI-2
2306 * structures, as long as we request the greater
2309 maximum
= page_size
- sizeof (struct mode_page
) - hdr
->bdesc_length
;
2310 if (((int)pg
->length
) > maximum
) {
2313 Mode sense page 0x%x: incorrect page length %d - expected max %d\n",
2314 page_code
, pg
->length
, maximum
);
2316 dump("Mode sense: ", mode_sense_buf
,
2319 free(mode_sense_buf
);
2323 (void) memcpy(page_data
, (caddr_t
)pg
, MODESENSE_PAGE_LEN(pg
));
2325 if (option_msg
&& diag_msg
) {
2326 char *pc
= find_string(page_control_strings
, page_control
);
2327 err_print("\nMode sense page 0x%x (%s):\n", page_code
,
2328 pc
!= NULL
? pc
: "");
2329 dump("header: ", (caddr_t
)header
,
2330 sizeof (struct scsi_ms_header
), HEX_ONLY
);
2331 dump("data: ", page_data
,
2332 MODESENSE_PAGE_LEN(pg
), HEX_ONLY
);
2335 free(mode_sense_buf
);
2341 * Execute a uscsi mode select command.
2344 uscsi_mode_select(fd
, page_code
, options
, page_data
, page_size
, header
)
2345 int fd
; /* file descriptor */
2346 int page_code
; /* mode select page */
2347 int options
; /* save page/page format */
2348 caddr_t page_data
; /* place received data here */
2349 int page_size
; /* size of page_data */
2350 struct scsi_ms_header
*header
; /* mode header/block descriptor */
2352 caddr_t mode_select_buf
;
2354 struct uscsi_cmd ucmd
;
2358 assert(((struct mode_page
*)page_data
)->ps
== 0);
2359 assert(header
->mode_header
.length
== 0);
2360 assert(header
->mode_header
.device_specific
== 0);
2361 assert((options
& ~(MODE_SELECT_SP
|MODE_SELECT_PF
)) == 0);
2364 * Allocate a buffer for the mode select header and data
2366 nbytes
= sizeof (struct block_descriptor
) +
2367 sizeof (struct mode_header
) + page_size
;
2368 if ((mode_select_buf
= malloc((uint_t
)nbytes
)) == NULL
) {
2369 err_print("cannot malloc %d bytes\n", nbytes
);
2374 * Build the mode select data out of the header and page data
2375 * This allows us to support devices which return either
2376 * 0 or 1 block descriptors.
2378 (void) memset(mode_select_buf
, 0, nbytes
);
2379 nbytes
= sizeof (struct mode_header
);
2380 if (header
->mode_header
.bdesc_length
==
2381 sizeof (struct block_descriptor
)) {
2382 nbytes
+= sizeof (struct block_descriptor
);
2386 * Dump the structures if anyone's interested
2388 if (option_msg
&& diag_msg
) {
2390 s
= find_string(mode_select_strings
,
2391 options
& (MODE_SELECT_SP
|MODE_SELECT_PF
));
2392 err_print("\nMode select page 0x%x%s:\n", page_code
,
2393 s
!= NULL
? s
: "");
2394 dump("header: ", (caddr_t
)header
,
2396 dump("data: ", (caddr_t
)page_data
,
2397 page_size
, HEX_ONLY
);
2401 * Fix the code for byte ordering
2404 switch (page_code
) {
2405 case DAD_MODE_ERR_RECOV
:
2407 struct mode_err_recov
*pd
;
2408 pd
= (struct mode_err_recov
*)(void *)page_data
;
2409 pd
->recovery_time_limit
= BE_16(pd
->recovery_time_limit
);
2412 case MODEPAGE_DISCO_RECO
:
2414 struct mode_disco_reco
*pd
;
2415 pd
= (struct mode_disco_reco
*)(void *)page_data
;
2416 pd
->bus_inactivity_limit
= BE_16(pd
->bus_inactivity_limit
);
2417 pd
->disconect_time_limit
= BE_16(pd
->disconect_time_limit
);
2418 pd
->connect_time_limit
= BE_16(pd
->connect_time_limit
);
2419 pd
->max_burst_size
= BE_16(pd
->max_burst_size
);
2422 case DAD_MODE_FORMAT
:
2424 struct mode_format
*pd
;
2425 pd
= (struct mode_format
*)(void *)page_data
;
2426 pd
->tracks_per_zone
= BE_16(pd
->tracks_per_zone
);
2427 pd
->alt_sect_zone
= BE_16(pd
->alt_sect_zone
);
2428 pd
->alt_tracks_zone
= BE_16(pd
->alt_tracks_zone
);
2429 pd
->alt_tracks_vol
= BE_16(pd
->alt_tracks_vol
);
2430 pd
->sect_track
= BE_16(pd
->sect_track
);
2431 pd
->data_bytes_sect
= BE_16(pd
->data_bytes_sect
);
2432 pd
->interleave
= BE_16(pd
->interleave
);
2433 pd
->track_skew
= BE_16(pd
->track_skew
);
2434 pd
->cylinder_skew
= BE_16(pd
->cylinder_skew
);
2437 case DAD_MODE_GEOMETRY
:
2439 struct mode_geometry
*pd
;
2440 pd
= (struct mode_geometry
*)(void *)page_data
;
2441 pd
->step_rate
= BE_16(pd
->step_rate
);
2442 pd
->rpm
= BE_16(pd
->rpm
);
2445 case DAD_MODE_CACHE
:
2447 struct mode_cache
*pd
;
2448 pd
= (struct mode_cache
*)(void *)page_data
;
2449 pd
->dis_prefetch_len
= BE_16(pd
->dis_prefetch_len
);
2450 pd
->min_prefetch
= BE_16(pd
->min_prefetch
);
2451 pd
->max_prefetch
= BE_16(pd
->max_prefetch
);
2452 pd
->prefetch_ceiling
= BE_16(pd
->prefetch_ceiling
);
2455 case MODEPAGE_PDEVICE
:
2457 struct mode_pdevice
*pd
;
2458 pd
= (struct mode_pdevice
*)(void *)page_data
;
2459 pd
->if_ident
= BE_16(pd
->if_ident
);
2462 case MODEPAGE_CTRL_MODE
:
2464 struct mode_control
*pd
;
2465 pd
= (struct mode_control
*)(void *)page_data
;
2466 pd
->ready_aen_holdoff
= BE_16(pd
->ready_aen_holdoff
);
2472 * Put the header and data together
2474 (void) memcpy(mode_select_buf
, (caddr_t
)header
, nbytes
);
2475 (void) memcpy(mode_select_buf
+ nbytes
, page_data
, page_size
);
2476 nbytes
+= page_size
;
2479 * Build and execute the uscsi ioctl
2481 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2482 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2483 cdb
.scc_cmd
= SCMD_MODE_SELECT
;
2484 FORMG0COUNT(&cdb
, (uchar_t
)nbytes
);
2485 cdb
.cdb_opaque
[1] = (uchar_t
)options
;
2486 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2487 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2488 ucmd
.uscsi_bufaddr
= mode_select_buf
;
2489 ucmd
.uscsi_buflen
= nbytes
;
2490 status
= uscsi_cmd(fd
, &ucmd
,
2491 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2493 if (status
&& option_msg
) {
2494 err_print("Mode select page 0x%x failed\n", page_code
);
2497 free(mode_select_buf
);
2503 * Execute a uscsi inquiry command and return the
2507 uscsi_inquiry(fd
, inqbuf
, inqbufsiz
)
2512 struct uscsi_cmd ucmd
;
2514 struct scsi_inquiry
*inq
;
2518 assert(inqbufsiz
>= sizeof (struct scsi_inquiry
) &&
2522 * Build and execute the uscsi ioctl
2524 (void) memset((char *)inqbuf
, 0, inqbufsiz
);
2525 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2526 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2527 cdb
.scc_cmd
= SCMD_INQUIRY
;
2528 FORMG0COUNT(&cdb
, (uchar_t
)inqbufsiz
);
2529 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2530 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2531 ucmd
.uscsi_bufaddr
= (caddr_t
)inqbuf
;
2532 ucmd
.uscsi_buflen
= inqbufsiz
;
2533 status
= uscsi_cmd(fd
, &ucmd
,
2534 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2537 err_print("Inquiry failed\n");
2539 } else if (option_msg
&& diag_msg
) {
2541 * Dump the inquiry data if anyone's interested
2543 inq
= (struct scsi_inquiry
*)inqbuf
;
2544 n
= (int)inq
->inq_len
+ 4;
2545 n
= min(n
, inqbufsiz
);
2546 err_print("Inquiry:\n");
2547 dump("", (caddr_t
)inqbuf
, n
, HEX_ASCII
);
2553 * Execute a uscsi inquiry command with page code 86h
2556 uscsi_inquiry_page_86h(fd
, inqbuf
, inqbufsiz
)
2561 struct uscsi_cmd ucmd
;
2566 assert(inqbufsiz
>= sizeof (struct scsi_inquiry
) &&
2569 * Build and execute uscsi ioctl
2571 (void) memset((char *)inqbuf
, 0, inqbufsiz
);
2572 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2573 (void) memset((char *)&cdb
, 0, sizeof (cdb
));
2574 cdb
.scc_cmd
= SCMD_INQUIRY
;
2575 FORMG0COUNT(&cdb
, (uchar_t
)inqbufsiz
);
2576 cdb
.cdb_opaque
[1] |= 0x01;
2577 cdb
.cdb_opaque
[2] = 0x86;
2578 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2579 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2580 ucmd
.uscsi_bufaddr
= (caddr_t
)inqbuf
;
2581 ucmd
.uscsi_buflen
= inqbufsiz
;
2583 status
= uscsi_cmd(fd
, &ucmd
,
2584 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2588 err_print("Inquriy with page_86h failed\n");
2595 * Return the Read Capacity information
2598 uscsi_read_capacity_16(fd
, capacity
)
2600 struct scsi_capacity_16
*capacity
;
2602 struct uscsi_cmd ucmd
;
2606 (void) memset((char *)capacity
, 0, sizeof (struct scsi_capacity_16
));
2607 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2608 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2610 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2611 ucmd
.uscsi_cdblen
= CDB_GROUP4
;
2612 ucmd
.uscsi_bufaddr
= (caddr_t
)capacity
;
2613 ucmd
.uscsi_buflen
= sizeof (struct scsi_capacity_16
);
2616 * Read Capacity (16) is a Service Action In command. One
2617 * command byte (0x9E) is overloaded for multiple operations,
2618 * with the second CDB byte specifying the desired operation
2620 cdb
.scc_cmd
= SCMD_SVC_ACTION_IN_G4
;
2621 cdb
.cdb_opaque
[1] = SSVC_ACTION_READ_CAPACITY_G4
;
2624 * Fill in allocation length field
2626 cdb
.cdb_opaque
[10] =
2627 (uchar_t
)((ucmd
.uscsi_buflen
& 0xff000000) >> 24);
2628 cdb
.cdb_opaque
[11] =
2629 (uchar_t
)((ucmd
.uscsi_buflen
& 0x00ff0000) >> 16);
2630 cdb
.cdb_opaque
[12] =
2631 (uchar_t
)((ucmd
.uscsi_buflen
& 0x0000ff00) >> 8);
2632 cdb
.cdb_opaque
[13] =
2633 (uchar_t
)(ucmd
.uscsi_buflen
& 0x000000ff);
2635 status
= uscsi_cmd(fd
, &ucmd
,
2636 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2640 err_print("Read capacity 16 failed\n");
2642 } else if (option_msg
&& diag_msg
) {
2644 * Dump the capacity data if anyone's interested
2646 dump("Capacity: ", (caddr_t
)capacity
,
2647 sizeof (struct scsi_capacity_16
), HEX_ONLY
);
2650 capacity
->sc_capacity
= BE_64(capacity
->sc_capacity
);
2651 capacity
->sc_lbasize
= BE_32(capacity
->sc_lbasize
);
2657 uscsi_read_capacity(fd
, capacity
)
2659 struct scsi_capacity_16
*capacity
;
2661 struct uscsi_cmd ucmd
;
2664 struct scsi_capacity cap_old
;
2667 * Build and execute the uscsi ioctl
2669 (void) memset((char *)capacity
, 0, sizeof (struct scsi_capacity_16
));
2670 (void) memset((char *)&cap_old
, 0, sizeof (struct scsi_capacity
));
2671 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2672 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2673 cdb
.scc_cmd
= SCMD_READ_CAPACITY
;
2674 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2675 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
2676 ucmd
.uscsi_bufaddr
= (caddr_t
)&cap_old
;
2677 ucmd
.uscsi_buflen
= sizeof (struct scsi_capacity
);
2678 status
= uscsi_cmd(fd
, &ucmd
,
2679 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2681 if (cap_old
.capacity
== UINT_MAX32
) {
2683 * A capacity of 0xffffffff in response to a
2684 * READ CAPACITY 10 indicates that the lun
2685 * is too large to report the size in a 32 bit
2686 * value, and a READ CAPACITY 16 is required
2687 * to get the correct size.
2689 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2690 (void) memset((char *)&cdb
, 0,
2691 sizeof (union scsi_cdb
));
2693 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2694 ucmd
.uscsi_cdblen
= CDB_GROUP4
;
2695 ucmd
.uscsi_bufaddr
= (caddr_t
)capacity
;
2696 ucmd
.uscsi_buflen
= sizeof (struct scsi_capacity_16
);
2699 * Read Capacity (16) is a Service Action In command. One
2700 * command byte (0x9E) is overloaded for multiple operations,
2701 * with the second CDB byte specifying the desired operation
2703 cdb
.scc_cmd
= SCMD_SVC_ACTION_IN_G4
;
2704 cdb
.cdb_opaque
[1] = SSVC_ACTION_READ_CAPACITY_G4
;
2707 * Fill in allocation length field
2709 cdb
.cdb_opaque
[10] =
2710 (uchar_t
)((ucmd
.uscsi_buflen
& 0xff000000) >> 24);
2711 cdb
.cdb_opaque
[11] =
2712 (uchar_t
)((ucmd
.uscsi_buflen
& 0x00ff0000) >> 16);
2713 cdb
.cdb_opaque
[12] =
2714 (uchar_t
)((ucmd
.uscsi_buflen
& 0x0000ff00) >> 8);
2715 cdb
.cdb_opaque
[13] =
2716 (uchar_t
)(ucmd
.uscsi_buflen
& 0x000000ff);
2718 status
= uscsi_cmd(fd
, &ucmd
,
2719 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2725 * Indicate which of the commands failed
2727 if (cdb
.scc_cmd
== SCMD_READ_CAPACITY
) {
2728 err_print("Read capacity failed\n");
2730 err_print("Read capacity 16 failed\n");
2733 } else if (option_msg
&& diag_msg
) {
2735 * Dump the capacity data if anyone's interested
2737 if (cap_old
.capacity
== UINT_MAX32
) {
2738 dump("Capacity: ", (caddr_t
)capacity
,
2739 sizeof (struct scsi_capacity_16
), HEX_ONLY
);
2741 dump("Capacity: ", (caddr_t
)&cap_old
,
2742 sizeof (struct scsi_capacity
), HEX_ONLY
);
2746 if (cap_old
.capacity
== UINT_MAX32
) {
2747 capacity
->sc_capacity
= BE_64(capacity
->sc_capacity
);
2748 capacity
->sc_lbasize
= BE_32(capacity
->sc_lbasize
);
2750 capacity
->sc_capacity
= (uint64_t)BE_32(cap_old
.capacity
);
2751 capacity
->sc_lbasize
= BE_32(cap_old
.lbasize
);
2759 * Reserve the current disk
2762 uscsi_reserve_release(int fd
, int cmd
)
2766 struct uscsi_cmd ucmd
;
2770 * Build and execute the uscsi ioctl
2772 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2773 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2774 cdb
.scc_cmd
= (cmd
== SCMD_RESERVE
) ? SCMD_RESERVE
: SCMD_RELEASE
;
2775 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2776 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2777 status
= uscsi_cmd(fd
, &ucmd
,
2778 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2782 * Reserve/Release(6) failed.
2783 * Try Reserve/Release(10) , if it succeeds then
2786 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2787 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2788 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2789 cdb
.scc_cmd
= (cmd
== SCMD_RESERVE
) ?
2790 SCMD_RESERVE_G1
: SCMD_RELEASE_G1
;
2791 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
2792 status
= uscsi_cmd(fd
, &ucmd
,
2793 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2796 err_print("%s failed\n", (cmd
== SCMD_RESERVE
) ?
2797 "Reserve" : "Release");
2801 #else /* not sparc */
2804 #endif /* not sparc */
2810 scsi_dump_mode_sense_pages(page_control
)
2813 struct uscsi_cmd ucmd
;
2819 struct mode_header
*mh
;
2821 struct mode_page
*mp
;
2826 pc_str
= find_string(page_control_strings
, page_control
);
2829 * Allocate memory for the mode sense buffer.
2832 msbuf
= (char *)zalloc(nbytes
);
2835 * Build and execute the uscsi ioctl
2837 (void) memset(msbuf
, 0, nbytes
);
2838 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
2839 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
2840 cdb
.scc_cmd
= SCMD_MODE_SENSE
;
2841 FORMG0COUNT(&cdb
, (uchar_t
)nbytes
);
2842 cdb
.cdb_opaque
[2] = page_control
| 0x3f;
2843 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
2844 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
2845 ucmd
.uscsi_bufaddr
= msbuf
;
2846 ucmd
.uscsi_buflen
= nbytes
;
2847 status
= uscsi_cmd(cur_file
, &ucmd
,
2848 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
2850 err_print("\nMode sense page 0x3f (%s) failed\n",
2854 err_print("\nMode sense pages (%s):\n", pc_str
);
2855 mh
= (struct mode_header
*)msbuf
;
2856 nbytes
= mh
->length
- sizeof (struct mode_header
) -
2857 mh
->bdesc_length
+ 1;
2858 p
= msbuf
+ sizeof (struct mode_header
) +
2860 dump(" ", msbuf
, sizeof (struct mode_header
) +
2861 (int)mh
->bdesc_length
, HEX_ONLY
);
2862 while (nbytes
> 0) {
2863 mp
= (struct mode_page
*)p
;
2864 n
= mp
->length
+ sizeof (struct mode_page
);
2868 (void) sprintf(s
, " %3x: ", mp
->code
);
2869 dump(s
, p
, n
, HEX_ONLY
);
2873 err_print(" Sense data formatted incorrectly:\n");
2874 dump(" ", msbuf
, (int)mh
->length
+1, HEX_ONLY
);
2886 scsi_printerr(ucmd
, rq
, rqlen
)
2887 struct uscsi_cmd
*ucmd
;
2888 struct scsi_extended_sense
*rq
;
2892 struct scsi_descr_sense_hdr
*sdsp
=
2893 (struct scsi_descr_sense_hdr
*)rq
;
2895 switch (rq
->es_key
) {
2897 err_print("No sense error");
2899 case KEY_RECOVERABLE_ERROR
:
2900 err_print("Recoverable error");
2903 err_print("Not ready error");
2905 case KEY_MEDIUM_ERROR
:
2906 err_print("Medium error");
2908 case KEY_HARDWARE_ERROR
:
2909 err_print("Hardware error");
2911 case KEY_ILLEGAL_REQUEST
:
2912 err_print("Illegal request");
2914 case KEY_UNIT_ATTENTION
:
2915 err_print("Unit attention error");
2917 case KEY_WRITE_PROTECT
:
2918 err_print("Write protect error");
2920 case KEY_BLANK_CHECK
:
2921 err_print("Blank check error");
2923 case KEY_VENDOR_UNIQUE
:
2924 err_print("Vendor unique error");
2926 case KEY_COPY_ABORTED
:
2927 err_print("Copy aborted error");
2929 case KEY_ABORTED_COMMAND
:
2930 err_print("Aborted command");
2933 err_print("Equal error");
2935 case KEY_VOLUME_OVERFLOW
:
2936 err_print("Volume overflow");
2938 case KEY_MISCOMPARE
:
2939 err_print("Miscompare error");
2942 err_print("Reserved error");
2945 err_print("Unknown error");
2949 err_print(" during %s", scsi_find_command_name(ucmd
->uscsi_cdb
[0]));
2952 * Get asc, ascq and info field from sense data. There are two
2953 * possible formats (fixed sense data and descriptor sense data)
2954 * depending on the value of es_code.
2956 switch (rq
->es_code
) {
2957 case CODE_FMT_DESCR_CURRENT
:
2958 case CODE_FMT_DESCR_DEFERRED
:
2960 (diskaddr_t
)scsi_extract_sense_info_descr(sdsp
, rqlen
);
2961 if (blkno
!= (diskaddr_t
)-1) {
2962 err_print(": block %lld (0x%llx) (", blkno
, blkno
);
2963 pr_dblock(err_print
, blkno
);
2969 err_print("ASC: 0x%x ASCQ: 0x%x\n",
2970 sdsp
->ds_add_code
, sdsp
->ds_qual_code
);
2972 case CODE_FMT_FIXED_CURRENT
:
2973 case CODE_FMT_FIXED_DEFERRED
:
2976 blkno
= (rq
->es_info_1
<< 24) |
2977 (rq
->es_info_2
<< 16) |
2978 (rq
->es_info_3
<< 8) | rq
->es_info_4
;
2979 err_print(": block %lld (0x%llx) (", blkno
, blkno
);
2980 pr_dblock(err_print
, blkno
);
2986 if (rq
->es_add_len
>= 6) {
2987 err_print("ASC: 0x%x ASCQ: 0x%x\n",
2988 rq
->es_add_code
, rq
->es_qual_code
);
2993 if (option_msg
&& diag_msg
) {
2994 if (rq
->es_key
== KEY_ILLEGAL_REQUEST
) {
2995 dump("cmd: ", (caddr_t
)ucmd
,
2996 sizeof (struct uscsi_cmd
), HEX_ONLY
);
2997 dump("cdb: ", (caddr_t
)ucmd
->uscsi_cdb
,
2998 ucmd
->uscsi_cdblen
, HEX_ONLY
);
3000 dump("sense: ", (caddr_t
)rq
, rqlen
, HEX_ONLY
);
3004 switch (rq
->es_code
) {
3005 case CODE_FMT_DESCR_CURRENT
:
3006 case CODE_FMT_DESCR_DEFERRED
:
3007 scsi_print_descr_sense(sdsp
, rqlen
);
3009 case CODE_FMT_FIXED_CURRENT
:
3010 case CODE_FMT_FIXED_DEFERRED
:
3012 scsi_print_extended_sense(rq
, rqlen
);
3019 * Retrieve "information" field from descriptor format
3020 * sense data. Iterates through each sense descriptor
3021 * looking for the information descriptor and returns
3022 * the information field from that descriptor.
3025 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr
*sdsp
, int rqlen
)
3028 uint8_t *descr_offset
;
3029 int valid_sense_length
;
3030 struct scsi_information_sense_descr
*isd
;
3033 * Initialize result to -1 indicating there is no information
3036 result
= (diskaddr_t
)-1;
3039 * The first descriptor will immediately follow the header
3041 descr_offset
= (uint8_t *)(sdsp
+1); /* Pointer arithmetic */
3044 * Calculate the amount of valid sense data
3046 valid_sense_length
=
3047 min((sizeof (struct scsi_descr_sense_hdr
) +
3048 sdsp
->ds_addl_sense_length
),
3052 * Iterate through the list of descriptors, stopping when we
3053 * run out of sense data
3055 while ((descr_offset
+ sizeof (struct scsi_information_sense_descr
)) <=
3056 (uint8_t *)sdsp
+ valid_sense_length
) {
3058 * Check if this is an information descriptor. We can
3059 * use the scsi_information_sense_descr structure as a
3060 * template sense the first two fields are always the
3063 isd
= (struct scsi_information_sense_descr
*)descr_offset
;
3064 if (isd
->isd_descr_type
== DESCR_INFORMATION
) {
3066 * Found an information descriptor. Copy the
3067 * information field. There will only be one
3068 * information descriptor so we can stop looking.
3071 (((diskaddr_t
)isd
->isd_information
[0] << 56) |
3072 ((diskaddr_t
)isd
->isd_information
[1] << 48) |
3073 ((diskaddr_t
)isd
->isd_information
[2] << 40) |
3074 ((diskaddr_t
)isd
->isd_information
[3] << 32) |
3075 ((diskaddr_t
)isd
->isd_information
[4] << 24) |
3076 ((diskaddr_t
)isd
->isd_information
[5] << 16) |
3077 ((diskaddr_t
)isd
->isd_information
[6] << 8) |
3078 ((diskaddr_t
)isd
->isd_information
[7]));
3083 * Get pointer to the next descriptor. The "additional
3084 * length" field holds the length of the descriptor except
3085 * for the "type" and "additional length" fields, so
3086 * we need to add 2 to get the total length.
3088 descr_offset
+= (isd
->isd_addl_length
+ 2);
3095 * Return a pointer to a string telling us the name of the command.
3098 scsi_find_command_name(uint_t cmd
)
3100 struct scsi_command_name
*c
;
3102 for (c
= scsi_command_names
; c
->command
!= SCMD_UNKNOWN
; c
++)
3103 if (c
->command
== cmd
)
3110 * Return true if we support a particular mode page
3113 scsi_supported_page(int page
) {
3114 return (page
== 1 || page
== 2 || page
== 3 || page
== 4 ||
3115 page
== 8 || page
== 0x38);
3120 apply_chg_list(int pageno
, int pagsiz
, uchar_t
*curbits
,
3121 uchar_t
*chgbits
, struct chg_list
*chglist
)
3129 while (chglist
!= NULL
) {
3130 if (chglist
->pageno
== pageno
&&
3131 chglist
->byteno
< pagsiz
) {
3132 i
= chglist
->byteno
;
3134 switch (chglist
->mode
) {
3136 c
|= (uchar_t
)chglist
->value
;
3139 c
&= (uchar_t
)chglist
->value
;
3142 c
= (uchar_t
)chglist
->value
;
3146 * Figure out which bits changed, and
3147 * are marked as changeable. If this
3148 * result actually differs from the
3149 * current value, update the current
3150 * value, and note that a mode select
3153 delta
= c
^ curbits
[i
];
3154 for (m
= 0x01; m
< 0x100; m
<<= 1) {
3155 if ((delta
& m
) && (chgbits
[i
] & m
)) {
3161 chglist
= chglist
->next
;
3169 * Return whether a given page is affected by an item on
3173 chg_list_affects_page(chglist
, pageno
)
3174 struct chg_list
*chglist
;
3177 while (chglist
!= NULL
) {
3178 if (chglist
->pageno
== pageno
) {
3181 chglist
= chglist
->next
;
3189 * Labels for the various fields of the scsi_extended_sense structure
3191 static char *scsi_extended_sense_labels
[] = {
3192 "Request sense valid: ",
3193 "Error class and code: ",
3197 "Incorrect length indicator: ",
3199 "Information field: ",
3200 "Additional sense length: ",
3201 "Command-specific information: ",
3202 "Additional sense code: ",
3203 "Additional sense code qualifier: ",
3204 "Field replaceable unit code: ",
3205 "Sense-key specific: ",
3206 "Additional sense bytes: "
3211 * Display the full scsi_extended_sense as returned by the device
3214 scsi_print_extended_sense(rq
, rqlen
)
3215 struct scsi_extended_sense
*rq
;
3220 p
= scsi_extended_sense_labels
;
3221 if (rqlen
< (sizeof (*rq
) - 2) || !rq
->es_valid
) {
3223 * target should be capable of returning at least 18
3224 * bytes of data, i.e upto rq->es_skey_specific field.
3225 * The additional sense bytes (2 or more ...) are optional.
3230 fmt_print("\n%s%s\n", *p
++, rq
->es_valid
? "yes" : "no");
3231 fmt_print("%s0x%02x\n", *p
++, (rq
->es_class
<< 4) + rq
->es_code
);
3232 fmt_print("%s%d\n", *p
++, rq
->es_segnum
);
3233 fmt_print("%s%s\n", *p
++, rq
->es_filmk
? "yes" : "no");
3234 fmt_print("%s%s\n", *p
++, rq
->es_eom
? "yes" : "no");
3235 fmt_print("%s%s\n", *p
++, rq
->es_ili
? "yes" : "no");
3236 fmt_print("%s%d\n", *p
++, rq
->es_key
);
3238 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p
++, rq
->es_info_1
,
3239 rq
->es_info_2
, rq
->es_info_3
, rq
->es_info_4
);
3240 fmt_print("%s%d\n", *p
++, rq
->es_add_len
);
3241 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p
++, rq
->es_cmd_info
[0],
3242 rq
->es_cmd_info
[1], rq
->es_cmd_info
[2], rq
->es_cmd_info
[3]);
3243 fmt_print("%s0x%02x = %d\n", *p
++, rq
->es_add_code
, rq
->es_add_code
);
3244 fmt_print("%s0x%02x = %d\n", *p
++, rq
->es_qual_code
, rq
->es_qual_code
);
3245 fmt_print("%s%d\n", *p
++, rq
->es_fru_code
);
3246 fmt_print("%s0x%02x 0x%02x 0x%02x\n", *p
++, rq
->es_skey_specific
[0],
3247 rq
->es_skey_specific
[1], rq
->es_skey_specific
[2]);
3248 if (rqlen
>= sizeof (*rq
)) {
3249 fmt_print("%s0x%02x 0x%02x%s\n", *p
, rq
->es_add_info
[0],
3250 rq
->es_add_info
[1], (rqlen
> sizeof (*rq
)) ? " ..." : "");
3257 * Labels for the various fields of the scsi_descr_sense_hdr structure
3259 static char *scsi_descr_sense_labels
[] = {
3260 "Error class and code: ",
3262 "Additional sense length: ",
3263 "Additional sense code: ",
3264 "Additional sense code qualifier: ",
3265 "Additional sense bytes: "
3270 * Display the full descriptor sense data as returned by the device
3274 scsi_print_descr_sense(rq
, rqlen
)
3275 struct scsi_descr_sense_hdr
*rq
;
3279 uint8_t *descr_offset
;
3280 int valid_sense_length
;
3281 struct scsi_information_sense_descr
*isd
;
3283 p
= scsi_descr_sense_labels
;
3284 if (rqlen
< sizeof (struct scsi_descr_sense_hdr
)) {
3286 * target must return at least 8 bytes of data
3291 /* Print descriptor sense header */
3292 fmt_print("%s0x%02x\n", *p
++, (rq
->ds_class
<< 4) + rq
->ds_code
);
3293 fmt_print("%s%d\n", *p
++, rq
->ds_key
);
3295 fmt_print("%s%d\n", *p
++, rq
->ds_addl_sense_length
);
3296 fmt_print("%s0x%02x = %d\n", *p
++, rq
->ds_add_code
, rq
->ds_add_code
);
3297 fmt_print("%s0x%02x = %d\n", *p
++, rq
->ds_qual_code
, rq
->ds_qual_code
);
3301 * Now print any sense descriptors. The first descriptor will
3302 * immediately follow the header
3304 descr_offset
= (uint8_t *)(rq
+1); /* Pointer arithmetic */
3307 * Calculate the amount of valid sense data
3309 valid_sense_length
=
3310 min((sizeof (struct scsi_descr_sense_hdr
) +
3311 rq
->ds_addl_sense_length
), rqlen
);
3314 * Iterate through the list of descriptors, stopping when we
3315 * run out of sense data. Descriptor format is:
3317 * <Descriptor type> <Descriptor length> <Descriptor data> ...
3319 while ((descr_offset
+ *(descr_offset
+ 1)) <=
3320 (uint8_t *)rq
+ valid_sense_length
) {
3322 * Determine descriptor type. We can use the
3323 * scsi_information_sense_descr structure as a
3324 * template since the first two fields are always the
3327 isd
= (struct scsi_information_sense_descr
*)descr_offset
;
3328 switch (isd
->isd_descr_type
) {
3329 case DESCR_INFORMATION
: {
3330 uint64_t information
;
3333 (((uint64_t)isd
->isd_information
[0] << 56) |
3334 ((uint64_t)isd
->isd_information
[1] << 48) |
3335 ((uint64_t)isd
->isd_information
[2] << 40) |
3336 ((uint64_t)isd
->isd_information
[3] << 32) |
3337 ((uint64_t)isd
->isd_information
[4] << 24) |
3338 ((uint64_t)isd
->isd_information
[5] << 16) |
3339 ((uint64_t)isd
->isd_information
[6] << 8) |
3340 ((uint64_t)isd
->isd_information
[7]));
3341 fmt_print("Information field: "
3342 "%0llx\n", information
);
3345 case DESCR_COMMAND_SPECIFIC
: {
3346 struct scsi_cmd_specific_sense_descr
*c
=
3347 (struct scsi_cmd_specific_sense_descr
*)isd
;
3348 uint64_t cmd_specific
;
3351 (((uint64_t)c
->css_cmd_specific_info
[0] << 56) |
3352 ((uint64_t)c
->css_cmd_specific_info
[1] << 48) |
3353 ((uint64_t)c
->css_cmd_specific_info
[2] << 40) |
3354 ((uint64_t)c
->css_cmd_specific_info
[3] << 32) |
3355 ((uint64_t)c
->css_cmd_specific_info
[4] << 24) |
3356 ((uint64_t)c
->css_cmd_specific_info
[5] << 16) |
3357 ((uint64_t)c
->css_cmd_specific_info
[6] << 8) |
3358 ((uint64_t)c
->css_cmd_specific_info
[7]));
3359 fmt_print("Command-specific information: "
3360 "%0llx\n", cmd_specific
);
3363 case DESCR_SENSE_KEY_SPECIFIC
: {
3364 struct scsi_sk_specific_sense_descr
*ssd
=
3365 (struct scsi_sk_specific_sense_descr
*)isd
;
3366 uint8_t *sk_spec_ptr
= (uint8_t *)&ssd
->sss_data
;
3367 fmt_print("Sense-key specific: "
3368 "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr
[0],
3369 sk_spec_ptr
[1], sk_spec_ptr
[2]);
3373 struct scsi_fru_sense_descr
*fsd
=
3374 (struct scsi_fru_sense_descr
*)isd
;
3375 fmt_print("Field replaceable unit code: "
3376 "%d\n", fsd
->fs_fru_code
);
3379 case DESCR_BLOCK_COMMANDS
: {
3380 struct scsi_block_cmd_sense_descr
*bsd
=
3381 (struct scsi_block_cmd_sense_descr
*)isd
;
3382 fmt_print("Incorrect length indicator: "
3383 "%s\n", bsd
->bcs_ili
? "yes" : "no");
3392 * Get pointer to the next descriptor. The "additional
3393 * length" field holds the length of the descriptor except
3394 * for the "type" and "additional length" fields, so
3395 * we need to add 2 to get the total length.
3397 descr_offset
+= (isd
->isd_addl_length
+ 2);
3404 * Function checks if READ DEFECT DATA command is supported
3405 * on the current disk.
3408 check_support_for_defects()
3410 struct uscsi_cmd ucmd
;
3412 struct scsi_defect_list def_list
;
3413 struct scsi_defect_hdr
*hdr
;
3416 struct scsi_extended_sense
*rq
;
3418 hdr
= (struct scsi_defect_hdr
*)&def_list
;
3421 * First get length of list by asking for the header only.
3423 (void) memset((char *)&def_list
, 0, sizeof (def_list
));
3426 * Build and execute the uscsi ioctl
3428 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
3429 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
3430 (void) memset((char *)rqbuf
, 0, 255);
3431 cdb
.scc_cmd
= SCMD_READ_DEFECT_LIST
;
3432 FORMG1COUNT(&cdb
, sizeof (struct scsi_defect_hdr
));
3433 cdb
.cdb_opaque
[2] = DLD_MAN_DEF_LIST
| DLD_BFI_FORMAT
;
3434 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
3435 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
3436 ucmd
.uscsi_bufaddr
= (caddr_t
)hdr
;
3437 ucmd
.uscsi_buflen
= sizeof (struct scsi_defect_hdr
);
3438 ucmd
.uscsi_rqbuf
= rqbuf
;
3439 ucmd
.uscsi_rqlen
= sizeof (rqbuf
);
3440 ucmd
.uscsi_rqresid
= sizeof (rqbuf
);
3441 rq
= (struct scsi_extended_sense
*)ucmd
.uscsi_rqbuf
;
3443 status
= uscsi_cmd(cur_file
, &ucmd
,
3444 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
3448 * check if read_defect_list_is_supported.
3450 if (ucmd
.uscsi_rqstatus
== STATUS_GOOD
&&
3451 rq
->es_key
== KEY_ILLEGAL_REQUEST
&&
3452 rq
->es_add_code
== INVALID_OPCODE
)
3459 * Format the disk, the whole disk, and nothing but the disk.
3460 * Function will be called only for disks
3461 * which do not support read defect list command.
3464 scsi_format_without_defects()
3466 struct uscsi_cmd ucmd
;
3468 struct scsi_defect_hdr defect_hdr
;
3472 * Construct the uscsi format ioctl.
3473 * Use fmtdata = 0 , indicating the no source of
3474 * defects information is provided .
3475 * Function will be called only for disks
3476 * which do not support read defect list command.
3478 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
3479 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
3480 (void) memset((char *)&defect_hdr
, 0, sizeof (defect_hdr
));
3481 cdb
.scc_cmd
= SCMD_FORMAT
;
3482 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
3483 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
3484 ucmd
.uscsi_bufaddr
= (caddr_t
)&defect_hdr
;
3485 ucmd
.uscsi_buflen
= sizeof (defect_hdr
);
3486 cdb
.cdb_opaque
[1] = 0;
3488 * Issue the format ioctl
3490 status
= uscsi_cmd(cur_file
, &ucmd
,
3491 (option_msg
&& diag_msg
) ? F_NORMAL
: F_SILENT
);
3496 * Name: test_until_ready
3498 * Description: This function is used by scsi_format and
3499 * scsi_format_raw to poll the device while the FORMAT
3500 * UNIT cdb in in progress.
3503 * file descriptor to poll
3509 static int test_until_ready(int fd
) {
3511 struct uscsi_cmd ucmd
;
3513 struct scsi_extended_sense sense
;
3514 time_t start
, check
, time_left
;
3518 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
3519 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
3521 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
3522 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
3523 ucmd
.uscsi_rqbuf
= (caddr_t
)&sense
;
3524 ucmd
.uscsi_rqlen
= SENSE_LEN
;
3526 start
= check
= time((time_t *)0);
3528 /* Loop sending TEST UNIT READY until format is complete */
3530 /* clear last request sense data */
3531 ucmd
.uscsi_rqstatus
= 0;
3532 ucmd
.uscsi_rqresid
= 0;
3533 (void) memset((char *)&sense
, 0, SENSE_LEN
);
3535 /* issue test unit ready */
3536 status
= uscsi_cmd(fd
, &ucmd
, F_SILENT
3539 check
= time((time_t *)0);
3541 /* If device returns not ready we get EIO */
3542 if (status
!= 0 && errno
== EIO
) {
3543 /* Check SKSV if progress indication is avail */
3544 if (sense
.es_skey_specific
[0] == 0x80) {
3545 /* Store progress indication */
3546 progress
= ((uint16_t)sense
.
3547 es_skey_specific
[1]) << 8;
3548 progress
|= (uint16_t)sense
.
3549 es_skey_specific
[2];
3550 progress
= (uint16_t)(((float)progress
/
3551 (float)PROGRESS_INDICATION_BASE
)*100);
3556 * check to see if we can estimate
3557 * time remaining - wait until the format
3558 * is at least 5 percent complete to avoid
3559 * wildly-fluctuating time estimates
3561 if ((check
- start
) <= 0 || progress
<= 5) {
3562 /* unable to estimate */
3563 fmt_print(" %02d%% complete ",
3566 /* display with estimated time */
3567 time_left
= (time_t)(((float)(check
3568 - start
) / (float)progress
) *
3569 (float)(100 - progress
));
3570 sec
= time_left
% 60;
3571 min
= (time_left
/ 60) % 60;
3572 hour
= time_left
/ 3600;
3574 fmt_print(" %02d%% complete "
3575 "(%02d:%02d:%02d remaining) ",
3576 progress
, hour
, min
, sec
);
3578 /* flush or the screen will not update */
3579 (void) fflush(stdout
);
3582 /* format not in progress */
3584 fmt_print("\nRequest Sense ASC=0x%x ASCQ=0x%x",
3585 sense
.es_add_code
, sense
.es_qual_code
);
3590 /* delay so we don't waste cpu time */
3591 (void) sleep(RETRY_DELAY
);
3597 * Get the current protection type from the PROT_EN and P_TYPE
3600 get_cur_protection_type(struct scsi_capacity_16
*capacity
)
3606 cp13
= ((capacity
->sc_rsvd0
& 0x3f) << 2)
3607 | ((capacity
->sc_prot_en
& 0x01) << 1)
3608 | (capacity
->sc_rto_en
& 0x01);
3609 prot_en
= cp13
& 0x01;
3613 p_type
= (cp13
<< 4) >> 5;