1/*	$NetBSD: atapi_base.c,v 1.27 2008/04/05 15:47:00 cegger Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 1999, 2004 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 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: atapi_base.c,v 1.27 2008/04/05 15:47:00 cegger Exp $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/buf.h>
40#include <sys/uio.h>
41#include <sys/malloc.h>
42#include <sys/errno.h>
43#include <sys/device.h>
44#include <sys/proc.h>
45
46#include <dev/scsipi/scsipi_all.h>
47#include <dev/scsipi/scsipiconf.h>
48#include <dev/scsipi/atapiconf.h>
49#include <dev/scsipi/scsipi_base.h>
50
51/*
52 * Look at the returned sense and act on the error, determining
53 * the unix error number to pass back.  (0 = report no error)
54 *
55 * THIS IS THE DEFAULT ERROR HANDLER
56 */
57int
58atapi_interpret_sense(struct scsipi_xfer *xs)
59{
60	struct scsipi_periph *periph = xs->xs_periph;
61	int key, error;
62	const char *msg = NULL;
63
64	/*
65	 * If the device has it's own error handler, call it first.
66	 * If it returns a legit error value, return that, otherwise
67	 * it wants us to continue with normal error processing.
68	 */
69	if (periph->periph_switch->psw_error != NULL) {
70		SC_DEBUG(periph, SCSIPI_DB2,
71		    ("calling private err_handler()\n"));
72		error = (*periph->periph_switch->psw_error)(xs);
73		if (error != EJUSTRETURN)
74			return (error);
75	}
76	/*
77	 * otherwise use the default, call the generic sense handler if we have
78	 * more than the sense key
79	 */
80	if (xs->error == XS_SENSE)
81		return (scsipi_interpret_sense(xs));
82
83	key = (xs->sense.atapi_sense & 0xf0) >> 4;
84	switch (key) {
85		case SKEY_RECOVERED_ERROR:
86			msg = "soft error (corrected)";
87		case SKEY_NO_SENSE:
88			if (xs->resid == xs->datalen)
89				xs->resid = 0;  /* not short read */
90			error = 0;
91			break;
92		case SKEY_NOT_READY:
93			if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
94				periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
95			if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
96				return (0);
97			if ((xs->xs_control & XS_CTL_SILENT) != 0)
98				return (EIO);
99			msg = "not ready";
100			error = EIO;
101			break;
102		case SKEY_MEDIUM_ERROR: /* MEDIUM ERROR */
103			msg = "medium error";
104			error = EIO;
105			break;
106		case SKEY_HARDWARE_ERROR:
107			msg = "non-media hardware failure";
108			error = EIO;
109			break;
110		case SKEY_ILLEGAL_REQUEST:
111			if ((xs->xs_control &
112			     XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
113				return (0);
114			if ((xs->xs_control & XS_CTL_SILENT) != 0)
115				return (EIO);
116			msg = "illegal request";
117			error = EINVAL;
118			break;
119		case SKEY_UNIT_ATTENTION:
120			if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
121				periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
122			if ((xs->xs_control &
123			     XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
124			    /* XXX Should reupload any transient state. */
125			    (periph->periph_flags & PERIPH_REMOVABLE) == 0)
126				return (ERESTART);
127			if ((xs->xs_control & XS_CTL_SILENT) != 0)
128				return (EIO);
129			msg = "unit attention";
130			error = EIO;
131			break;
132		case SKEY_DATA_PROTECT:
133			msg = "readonly device";
134			error = EROFS;
135			break;
136		case SKEY_ABORTED_COMMAND:
137			msg = "command aborted";
138			if (xs->xs_retries != 0) {
139				xs->xs_retries--;
140				error = ERESTART;
141			} else
142				error = EIO;
143			break;
144		default:
145			error = EIO;
146			break;
147	}
148
149	if (!key) {
150		if (xs->sense.atapi_sense & 0x01) {
151			/* Illegal length indication */
152			msg = "ATA illegal length indication";
153			error = EIO;
154		}
155		if (xs->sense.atapi_sense & 0x02) { /* vol overflow */
156			msg = "ATA volume overflow";
157			error = ENOSPC;
158		}
159		if (xs->sense.atapi_sense & 0x04) { /* Aborted command */
160			msg = "ATA command aborted";
161			if (xs->xs_retries != 0) {
162				xs->xs_retries--;
163				error = ERESTART;
164			} else
165				error = EIO;
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 */
190void
191atapi_print_addr(struct scsipi_periph *periph)
192{
193	struct scsipi_channel *chan = periph->periph_channel;
194	struct scsipi_adapter *adapt = chan->chan_adapter;
195
196	printf("%s(%s:%d:%d): ", periph->periph_dev != NULL ?
197	    device_xname(periph->periph_dev) : "probe",
198	    device_xname(adapt->adapt_dev),
199	    chan->chan_channel, periph->periph_target);
200}
201
202/*
203 * ask the atapi driver to perform a command for us.
204 * tell it where to read/write the data, and how
205 * long the data is supposed to be. If we have  a buf
206 * to associate with the transfer, we need that too.
207 */
208void
209atapi_scsipi_cmd(struct scsipi_xfer *xs)
210{
211	struct scsipi_periph *periph = xs->xs_periph;
212
213	SC_DEBUG(periph, SCSIPI_DB2, ("atapi_cmd\n"));
214
215	xs->cmdlen = (periph->periph_cap & PERIPH_CAP_CMD16) ? 16 : 12;
216}
217