xref: /netbsd-src/sys/dev/scsipi/scsi_base.c (revision 93f9db1b75d415b78f73ed629beeb86235153473)
1 /*	$NetBSD: scsi_base.c,v 1.65 1998/08/15 10:10:56 mycroft Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include "opt_scsi.h"
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/buf.h>
46 #include <sys/uio.h>
47 #include <sys/malloc.h>
48 #include <sys/errno.h>
49 #include <sys/device.h>
50 #include <sys/proc.h>
51 
52 #include <dev/scsipi/scsipi_all.h>
53 #include <dev/scsipi/scsi_all.h>
54 #include <dev/scsipi/scsi_disk.h>
55 #include <dev/scsipi/scsiconf.h>
56 #include <dev/scsipi/scsipi_base.h>
57 
58 /*
59  * Do a scsi operation, asking a device to run as SCSI-II if it can.
60  */
61 int
62 scsi_change_def(sc_link, flags)
63 	struct scsipi_link *sc_link;
64 	int flags;
65 {
66 	struct scsi_changedef scsipi_cmd;
67 
68 	bzero(&scsipi_cmd, sizeof(scsipi_cmd));
69 	scsipi_cmd.opcode = SCSI_CHANGE_DEFINITION;
70 	scsipi_cmd.how = SC_SCSI_2;
71 
72 	return (scsipi_command(sc_link,
73 	    (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
74 	    0, 0, 2, 100000, NULL, flags));
75 }
76 
77 /*
78  * ask the scsi driver to perform a command for us.
79  * tell it where to read/write the data, and how
80  * long the data is supposed to be. If we have  a buf
81  * to associate with the transfer, we need that too.
82  */
83 int
84 scsi_scsipi_cmd(sc_link, scsipi_cmd, cmdlen, data_addr, datalen,
85 	retries, timeout, bp, flags)
86 	struct scsipi_link *sc_link;
87 	struct scsipi_generic *scsipi_cmd;
88 	int cmdlen;
89 	u_char *data_addr;
90 	int datalen;
91 	int retries;
92 	int timeout;
93 	struct buf *bp;
94 	int flags;
95 {
96 	struct scsipi_xfer *xs;
97 	int error;
98 
99 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_scsipi_cmd\n"));
100 
101 #ifdef DIAGNOSTIC
102 	if (bp != 0 && (flags & SCSI_NOSLEEP) == 0)
103 		panic("scsi_scsipi_cmd: buffer without nosleep");
104 #endif
105 
106 	if ((xs = scsipi_make_xs(sc_link, scsipi_cmd, cmdlen, data_addr,
107 	    datalen, retries, timeout, bp, flags)) == NULL)
108 		return (ENOMEM);
109 
110 	/*
111 	 * Set the LUN in the CDB if we have an older device.  We also
112 	 * set it for more modern SCSI-II devices "just in case".
113 	 */
114 	if ((sc_link->scsipi_scsi.scsi_version & SID_ANSII) <= 2)
115 		xs->cmd->bytes[0] |=
116 		    ((sc_link->scsipi_scsi.lun << SCSI_CMD_LUN_SHIFT) &
117 			SCSI_CMD_LUN_MASK);
118 
119 	if ((error = scsipi_execute_xs(xs)) == EJUSTRETURN)
120 		return (0);
121 
122 	/*
123 	 * we have finished with the xfer stuct, free it and
124 	 * check if anyone else needs to be started up.
125 	 */
126 	scsipi_free_xs(xs, flags);
127 	return (error);
128 }
129 
130 /*
131  * Look at the returned sense and act on the error, determining
132  * the unix error number to pass back.  (0 = report no error)
133  *
134  * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES
135  */
136 int
137 scsi_interpret_sense(xs)
138 	struct scsipi_xfer *xs;
139 {
140 	struct scsipi_sense_data *sense;
141 	struct scsipi_link *sc_link = xs->sc_link;
142 	u_int8_t key;
143 	u_int32_t info;
144 	int error;
145 #ifndef	SCSIVERBOSE
146 	static char *error_mes[] = {
147 		"soft error (corrected)",
148 		"not ready", "medium error",
149 		"non-media hardware failure", "illegal request",
150 		"unit attention", "readonly device",
151 		"no data found", "vendor unique",
152 		"copy aborted", "command aborted",
153 		"search returned equal", "volume overflow",
154 		"verify miscompare", "unknown error key"
155 	};
156 #endif
157 
158 	sense = &xs->sense.scsi_sense;
159 #ifdef	SCSIDEBUG
160 	if ((sc_link->flags & SDEV_DB1) != 0) {
161 		int count;
162 		printf("code 0x%x valid 0x%x ",
163 			sense->error_code & SSD_ERRCODE,
164 			sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
165 		printf("seg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
166 			sense->segment,
167 			sense->flags & SSD_KEY,
168 			sense->flags & SSD_ILI ? 1 : 0,
169 			sense->flags & SSD_EOM ? 1 : 0,
170 			sense->flags & SSD_FILEMARK ? 1 : 0);
171 		printf("info: 0x%x 0x%x 0x%x 0x%x followed by %d extra bytes\n",
172 			sense->info[0],
173 			sense->info[1],
174 			sense->info[2],
175 			sense->info[3],
176 			sense->extra_len);
177 		printf("extra: ");
178 		for (count = 0; count < ADD_BYTES_LIM(sense); count++)
179 			printf("0x%x ", sense->cmd_spec_info[count]);
180 		printf("\n");
181 	}
182 #endif	/* SCSIDEBUG */
183 	/*
184 	 * If the device has it's own error handler, call it first.
185 	 * If it returns a legit error value, return that, otherwise
186 	 * it wants us to continue with normal error processing.
187 	 */
188 	if (sc_link->device->err_handler) {
189 		SC_DEBUG(sc_link, SDEV_DB2,
190 		    ("calling private err_handler()\n"));
191 		error = (*sc_link->device->err_handler)(xs);
192 		if (error != SCSIRET_CONTINUE)
193 			return (error);		/* error >= 0  better ? */
194 	}
195 	/* otherwise use the default */
196 	switch (sense->error_code & SSD_ERRCODE) {
197 		/*
198 		 * If it's code 70, use the extended stuff and
199 		 * interpret the key
200 		 */
201 	case 0x71:		/* delayed error */
202 		sc_link->sc_print_addr(sc_link);
203 		key = sense->flags & SSD_KEY;
204 		printf(" DEFERRED ERROR, key = 0x%x\n", key);
205 		/* FALLTHROUGH */
206 	case 0x70:
207 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0)
208 			info = _4btol(sense->info);
209 		else
210 			info = 0;
211 		key = sense->flags & SSD_KEY;
212 
213 		switch (key) {
214 		case SKEY_NO_SENSE:
215 		case SKEY_RECOVERED_ERROR:
216 			if (xs->resid == xs->datalen && xs->datalen) {
217 				/*
218 				 * Why is this here?
219 				 */
220 				xs->resid = 0;	/* not short read */
221 			}
222 		case SKEY_EQUAL:
223 			error = 0;
224 			break;
225 		case SKEY_NOT_READY:
226 			if ((sc_link->flags & SDEV_REMOVABLE) != 0)
227 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
228 			if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
229 				return (0);
230 			if ((xs->flags & SCSI_SILENT) != 0)
231 				return (EIO);
232 			error = EIO;
233 			break;
234 		case SKEY_ILLEGAL_REQUEST:
235 			if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0)
236 				return (0);
237 			if ((xs->flags & SCSI_SILENT) != 0)
238 				return (EIO);
239 			error = EINVAL;
240 			break;
241 		case SKEY_UNIT_ATTENTION:
242 			if ((sc_link->flags & SDEV_REMOVABLE) != 0)
243 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
244 			if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 ||
245 				/* XXX Should reupload any transient state. */
246 				(sc_link->flags & SDEV_REMOVABLE) == 0)
247 				return (ERESTART);
248 			if ((xs->flags & SCSI_SILENT) != 0)
249 				return (EIO);
250 			error = EIO;
251 			break;
252 		case SKEY_WRITE_PROTECT:
253 			error = EROFS;
254 			break;
255 		case SKEY_BLANK_CHECK:
256 			error = 0;
257 			break;
258 		case SKEY_ABORTED_COMMAND:
259 			error = ERESTART;
260 			break;
261 		case SKEY_VOLUME_OVERFLOW:
262 			error = ENOSPC;
263 			break;
264 		default:
265 			error = EIO;
266 			break;
267 		}
268 
269 #ifdef SCSIVERBOSE
270 		if ((xs->flags & SCSI_SILENT) == 0)
271 			scsi_print_sense(xs, 0);
272 #else
273 		if (key) {
274 			sc_link->sc_print_addr(sc_link);
275 			printf("%s", error_mes[key - 1]);
276 			if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
277 				switch (key) {
278 				case SKEY_NOT_READY:
279 				case SKEY_ILLEGAL_REQUEST:
280 				case SKEY_UNIT_ATTENTION:
281 				case SKEY_WRITE_PROTECT:
282 					break;
283 				case SKEY_BLANK_CHECK:
284 					printf(", requested size: %d (decimal)",
285 					    info);
286 					break;
287 				case SKEY_ABORTED_COMMAND:
288 					if (xs->retries)
289 						printf(", retrying");
290 					printf(", cmd 0x%x, info 0x%x",
291 					    xs->cmd->opcode, info);
292 					break;
293 				default:
294 					printf(", info = %d (decimal)", info);
295 				}
296 			}
297 			if (sense->extra_len != 0) {
298 				int n;
299 				printf(", data =");
300 				for (n = 0; n < sense->extra_len; n++)
301 					printf(" %02x",
302 					    sense->cmd_spec_info[n]);
303 			}
304 			printf("\n");
305 		}
306 #endif
307 		return (error);
308 
309 	/*
310 	 * Not code 70, just report it
311 	 */
312 	default:
313 		sc_link->sc_print_addr(sc_link);
314 		printf("error code %d", sense->error_code & SSD_ERRCODE);
315 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
316 			struct scsipi_sense_data_unextended *usense =
317 			    (struct scsipi_sense_data_unextended *)sense;
318 			printf(" at block no. %d (decimal)",
319 			    _3btol(usense->block));
320 		}
321 		printf("\n");
322 		return (EIO);
323 	}
324 }
325 
326 /*
327  * Utility routines often used in SCSI stuff
328  */
329 
330 
331 /*
332  * Print out the scsi_link structure's address info.
333  */
334 void
335 scsi_print_addr(sc_link)
336 	struct scsipi_link *sc_link;
337 {
338 
339 	printf("%s(%s:%d:%d): ",
340 	    sc_link->device_softc ?
341 	    ((struct device *)sc_link->device_softc)->dv_xname : "probe",
342 	    ((struct device *)sc_link->adapter_softc)->dv_xname,
343 	    sc_link->scsipi_scsi.target, sc_link->scsipi_scsi.lun);
344 }
345