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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/scsi/impl/uscsi.h>
36 #include "transport.h"
42 uchar_t uscsi_status
, rqstatus
, rqresid
;
43 static struct uscsi_cmd uscmd
;
45 static uint_t total_retries
;
50 (void) memset(&uscmd
, 0, sizeof (uscmd
));
51 (void) memset(ucdb
, 0, 16);
52 uscmd
.uscsi_cdb
= ucdb
;
57 uscsi(int fd
, struct uscsi_cmd
*scmd
)
59 int ret
, global_rqsense
;
60 int retries
, max_retries
;
62 /* set up for request sense extensions */
63 if (!(scmd
->uscsi_flags
& USCSI_RQENABLE
)) {
64 scmd
->uscsi_flags
|= USCSI_RQENABLE
;
65 scmd
->uscsi_rqlen
= RQBUFLEN
;
66 scmd
->uscsi_rqbuf
= rqbuf
;
73 * Some DVD drives may have a delay for writing or sync cache, and
74 * read media info (done after syncing cache). This can take a
75 * significant number of time. Such as the Pioneer A0X which will
76 * generate TOC after the cache is full in the middle of writing.
79 if ((device_type
!= CD_RW
) && ((scmd
->uscsi_cdb
[0] == WRITE_10_CMD
) ||
80 (scmd
->uscsi_cdb
[0] == READ_INFO_CMD
) || (scmd
->uscsi_cdb
[0] ==
81 SYNC_CACHE_CMD
) || (scmd
->uscsi_cdb
[0] == CLOSE_TRACK_CMD
))) {
86 * Pioneer A08/A09 retries approx 30 times.
92 * The device may be busy or slow and fail with a not ready status.
93 * we'll allow a limited number of retries to give the drive time
96 for (retries
= 0; retries
< max_retries
; retries
++) {
98 scmd
->uscsi_status
= 0;
101 (void) memset(rqbuf
, 0, RQBUFLEN
);
103 if (debug
&& verbose
) {
106 (void) printf("cmd:[");
107 for (i
= 0; i
< scmd
->uscsi_cdblen
; i
++)
108 (void) printf("0x%02x ",
109 (uchar_t
)scmd
->uscsi_cdb
[i
]);
110 (void) printf("]\n");
114 * We need to have root privledges in order to use
115 * uscsi commands on the device.
119 ret
= ioctl(fd
, USCSICMD
, scmd
);
122 /* maintain consistency in case of sgen */
123 if ((ret
== 0) && (scmd
->uscsi_status
== 2)) {
128 /* if error and extended request sense, retrieve errors */
129 if (global_rqsense
&& (ret
< 0) && (scmd
->uscsi_status
== 2)) {
131 * The drive is not ready to recieve commands but
132 * may be in the process of becoming ready.
133 * sleep for a short time then retry command.
134 * SENSE/ASC = 2/4 : not ready
135 * ASCQ = 0 Not Reportable.
136 * ASCQ = 1 Becoming ready.
137 * ASCQ = 4 FORMAT in progress.
138 * ASCQ = 7 Operation in progress.
139 * ASCQ = 8 Long write in progress.
141 if ((SENSE_KEY(rqbuf
) == 2) && (ASC(rqbuf
) == 4) &&
142 ((ASCQ(rqbuf
) == 0) || (ASCQ(rqbuf
) == 1) ||
143 (ASCQ(rqbuf
) == 4)) || (ASCQ(rqbuf
) == 7)) {
150 * we do not print this out under normal circumstances
151 * since we have BUFE enabled and do not want to alarm
152 * users with uneccessary messages.
155 if ((SENSE_KEY(rqbuf
) == 5) && (ASC(rqbuf
) ==
156 0x21) && (ASCQ(rqbuf
) == 2)) {
157 (void) printf(gettext(
158 "Buffer underrun occurred! trying to recover...\n"));
163 * long write operation in progress, ms_delay is
164 * used for some fast drives with a short drive
165 * buffer. Such as Pioneer DVD-RW drives. They will
166 * begin to generate TOC when the buffer is initially
167 * full, then resume operation a few minutes later
168 * with the buffer emptying quickly.
170 if ((SENSE_KEY(rqbuf
) == 2) && (ASC(rqbuf
) == 4) &&
171 (ASCQ(rqbuf
) == 8)) {
174 * In Simulation write mode, we use the
175 * READ_INFO_CMD to check if all the previous
176 * writes completed. Sleeping 500 ms will not
177 * be sufficient in all cases for DVDs.
179 if ((device_type
!= CD_RW
) &&
180 ((scmd
->uscsi_cdb
[0] == CLOSE_TRACK_CMD
) ||
181 ((scmd
->uscsi_cdb
[0] == READ_INFO_CMD
) &&
189 * Device is not ready to transmit or a device reset
190 * has occurred. wait for a short period of time then
193 if ((SENSE_KEY(rqbuf
) == 6) && ((ASC(rqbuf
) == 0x28) ||
194 (ASC(rqbuf
) == 0x29))) {
200 if ((SENSE_KEY(rqbuf
) == 5) &&
201 (device_type
== DVD_PLUS
||
202 device_type
== DVD_PLUS_W
)) {
203 if (scmd
->uscsi_cdb
[0] == MODE_SELECT_10_CMD
&&
204 ASC(rqbuf
) == 0x26) {
209 if (scmd
->uscsi_cdb
[0] == REZERO_UNIT_CMD
&&
210 ASC(rqbuf
) == 0x20) {
217 * Blank Sense, we don't know what the error is or if
218 * the command succeeded, Hope for the best. Some
219 * drives return blank sense periodically and will
220 * fail if this is removed.
222 if ((SENSE_KEY(rqbuf
) == 0) && (ASC(rqbuf
) == 0) &&
223 (ASCQ(rqbuf
) == 0)) {
229 (void) printf("cmd: 0x%02x ret:%i status:%02x "
230 " sense: %02x ASC: %02x ASCQ:%02x\n",
231 (uchar_t
)scmd
->uscsi_cdb
[0], ret
,
233 (uchar_t
)SENSE_KEY(rqbuf
),
234 (uchar_t
)ASC(rqbuf
), (uchar_t
)ASCQ(rqbuf
));
238 /* no errors we'll return */
242 /* store the error status for later debug printing */
243 if ((ret
< 0) && (global_rqsense
)) {
244 uscsi_status
= scmd
->uscsi_status
;
245 rqstatus
= scmd
->uscsi_rqstatus
;
246 rqresid
= scmd
->uscsi_rqresid
;
250 if (debug
&& retries
) {
251 (void) printf("total retries: %d\n", total_retries
);