atapi_base.c revision 1.18 1 /* $NetBSD: atapi_base.c,v 1.18 2001/11/15 09:48:16 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: atapi_base.c,v 1.18 2001/11/15 09:48:16 lukem Exp $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/buf.h>
47 #include <sys/uio.h>
48 #include <sys/malloc.h>
49 #include <sys/errno.h>
50 #include <sys/device.h>
51 #include <sys/proc.h>
52
53 #include <dev/scsipi/scsipi_all.h>
54 #include <dev/scsipi/scsipiconf.h>
55 #include <dev/scsipi/atapiconf.h>
56 #include <dev/scsipi/scsipi_base.h>
57
58 /*
59 * Look at the returned sense and act on the error, determining
60 * the unix error number to pass back. (0 = report no error)
61 *
62 * THIS IS THE DEFAULT ERROR HANDLER
63 */
64 int
65 atapi_interpret_sense(xs)
66 struct scsipi_xfer *xs;
67 {
68 struct scsipi_periph *periph = xs->xs_periph;
69 int key, error;
70 char *msg = NULL;
71
72 /*
73 * If the device has it's own error handler, call it first.
74 * If it returns a legit error value, return that, otherwise
75 * it wants us to continue with normal error processing.
76 */
77 if (periph->periph_switch->psw_error != NULL) {
78 SC_DEBUG(periph, SCSIPI_DB2,
79 ("calling private err_handler()\n"));
80 error = (*periph->periph_switch->psw_error)(xs);
81 if (error != EJUSTRETURN)
82 return (error);
83 }
84 /*
85 * otherwise use the default, call the generic sense handler if we have
86 * more than the sense key
87 */
88 if (xs->error == XS_SENSE)
89 return (scsipi_interpret_sense(xs));
90
91 key = (xs->sense.atapi_sense & 0xf0) >> 4;
92 switch (key) {
93 case SKEY_RECOVERED_ERROR:
94 msg = "soft error (corrected)";
95 case SKEY_NO_SENSE:
96 if (xs->resid == xs->datalen)
97 xs->resid = 0; /* not short read */
98 error = 0;
99 break;
100 case SKEY_NOT_READY:
101 if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
102 periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
103 if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
104 return (0);
105 if ((xs->xs_control & XS_CTL_SILENT) != 0)
106 return (EIO);
107 msg = "not ready";
108 error = EIO;
109 break;
110 case SKEY_MEDIUM_ERROR: /* MEDIUM ERROR */
111 msg = "medium error";
112 error = EIO;
113 break;
114 case SKEY_HARDWARE_ERROR:
115 msg = "non-media hardware failure";
116 error = EIO;
117 break;
118 case SKEY_ILLEGAL_REQUEST:
119 if ((xs->xs_control &
120 XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
121 return (0);
122 if ((xs->xs_control & XS_CTL_SILENT) != 0)
123 return (EIO);
124 msg = "illegal request";
125 error = EINVAL;
126 break;
127 case SKEY_UNIT_ATTENTION:
128 if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
129 periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
130 if ((xs->xs_control &
131 XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
132 /* XXX Should reupload any transient state. */
133 (periph->periph_flags & PERIPH_REMOVABLE) == 0)
134 return (ERESTART);
135 if ((xs->xs_control & XS_CTL_SILENT) != 0)
136 return (EIO);
137 msg = "unit attention";
138 error = EIO;
139 break;
140 case SKEY_WRITE_PROTECT:
141 msg = "readonly device";
142 error = EROFS;
143 break;
144 case SKEY_ABORTED_COMMAND:
145 msg = "command aborted";
146 error = ERESTART;
147 break;
148 default:
149 error = EIO;
150 break;
151 }
152
153 if (!key) {
154 if (xs->sense.atapi_sense & 0x01) {
155 /* Illegal length indication */
156 msg = "ATA illegal length indication";
157 error = EIO;
158 }
159 if (xs->sense.atapi_sense & 0x02) { /* vol overflow */
160 msg = "ATA volume overflow";
161 error = ENOSPC;
162 }
163 if (xs->sense.atapi_sense & 0x04) { /* Aborted command */
164 msg = "ATA command aborted";
165 error = ERESTART;
166 }
167 }
168 if (msg) {
169 scsipi_printaddr(periph);
170 printf("%s\n", msg);
171 } else {
172 if (error) {
173 scsipi_printaddr(periph);
174 printf("unknown error code %d\n",
175 xs->sense.atapi_sense);
176 }
177 }
178
179 return (error);
180 }
181
182 /*
183 * Utility routines often used in SCSI stuff
184 */
185
186
187 /*
188 * Print out the scsi_link structure's address info.
189 */
190 void
191 atapi_print_addr(periph)
192 struct scsipi_periph *periph;
193 {
194 struct scsipi_channel *chan = periph->periph_channel;
195 struct scsipi_adapter *adapt = chan->chan_adapter;
196
197 printf("%s(%s:%d:%d): ", periph->periph_dev != NULL ?
198 periph->periph_dev->dv_xname : "probe",
199 adapt->adapt_dev->dv_xname,
200 chan->chan_channel, periph->periph_target);
201 }
202
203 /*
204 * ask the atapi driver to perform a command for us.
205 * tell it where to read/write the data, and how
206 * long the data is supposed to be. If we have a buf
207 * to associate with the transfer, we need that too.
208 */
209 int
210 atapi_scsipi_cmd(periph, scsipi_cmd, cmdlen, data, datalen,
211 retries, timeout, bp, flags)
212 struct scsipi_periph *periph;
213 struct scsipi_generic *scsipi_cmd;
214 int cmdlen;
215 void *data;
216 size_t datalen;
217 int retries;
218 int timeout;
219 struct buf *bp;
220 int flags;
221 {
222 struct scsipi_xfer *xs;
223 int error, s;
224
225 SC_DEBUG(periph, SCSIPI_DB2, ("atapi_cmd\n"));
226
227 #ifdef DIAGNOSTIC
228 if (bp != NULL && (flags & XS_CTL_ASYNC) == 0)
229 panic("atapi_scsipi_cmd: buffer without async");
230 #endif
231
232 if ((xs = scsipi_make_xs(periph, scsipi_cmd, cmdlen, data,
233 datalen, retries, timeout, bp, flags)) == NULL) {
234 if (bp != NULL) {
235 s = splbio();
236 bp->b_flags |= B_ERROR;
237 bp->b_error = ENOMEM;
238 biodone(bp);
239 splx(s);
240 }
241 return (ENOMEM);
242 }
243
244 xs->cmdlen = (periph->periph_cap & PERIPH_CAP_CMD16) ? 16 : 12;
245
246 if ((error = scsipi_execute_xs(xs)) == EJUSTRETURN)
247 return (0);
248 return (error);
249 }
250