1*fbffadb9Smrg /* $NetBSD: atapi_base.c,v 1.30 2019/02/03 03:19:28 mrg Exp $ */
26f3bab1fSbouyer
36dc90320Smycroft /*-
4ba781da1Smycroft * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
56dc90320Smycroft * All rights reserved.
66dc90320Smycroft *
76dc90320Smycroft * This code is derived from software contributed to The NetBSD Foundation
8937a7a3eSbouyer * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
9937a7a3eSbouyer * Simulation Facility, NASA Ames Research Center.
106f3bab1fSbouyer *
116f3bab1fSbouyer * Redistribution and use in source and binary forms, with or without
126f3bab1fSbouyer * modification, are permitted provided that the following conditions
136f3bab1fSbouyer * are met:
146f3bab1fSbouyer * 1. Redistributions of source code must retain the above copyright
156f3bab1fSbouyer * notice, this list of conditions and the following disclaimer.
166f3bab1fSbouyer * 2. Redistributions in binary form must reproduce the above copyright
176f3bab1fSbouyer * notice, this list of conditions and the following disclaimer in the
186f3bab1fSbouyer * documentation and/or other materials provided with the distribution.
196f3bab1fSbouyer *
206dc90320Smycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
216dc90320Smycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
226dc90320Smycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
236dc90320Smycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
246dc90320Smycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
256dc90320Smycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
266dc90320Smycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
276dc90320Smycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
286dc90320Smycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
296dc90320Smycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306dc90320Smycroft * POSSIBILITY OF SUCH DAMAGE.
316f3bab1fSbouyer */
326f3bab1fSbouyer
337ba10b35Slukem #include <sys/cdefs.h>
34*fbffadb9Smrg __KERNEL_RCSID(0, "$NetBSD: atapi_base.c,v 1.30 2019/02/03 03:19:28 mrg Exp $");
357ba10b35Slukem
366f3bab1fSbouyer #include <sys/param.h>
376f3bab1fSbouyer #include <sys/systm.h>
386f3bab1fSbouyer #include <sys/kernel.h>
396f3bab1fSbouyer #include <sys/buf.h>
406f3bab1fSbouyer #include <sys/uio.h>
416f3bab1fSbouyer #include <sys/malloc.h>
426f3bab1fSbouyer #include <sys/errno.h>
436f3bab1fSbouyer #include <sys/device.h>
446f3bab1fSbouyer #include <sys/proc.h>
456f3bab1fSbouyer
466f3bab1fSbouyer #include <dev/scsipi/scsipi_all.h>
473b207eafScgd #include <dev/scsipi/scsipiconf.h>
486f3bab1fSbouyer #include <dev/scsipi/atapiconf.h>
496f3bab1fSbouyer #include <dev/scsipi/scsipi_base.h>
506f3bab1fSbouyer
516f3bab1fSbouyer /*
526f3bab1fSbouyer * Look at the returned sense and act on the error, determining
536f3bab1fSbouyer * the unix error number to pass back. (0 = report no error)
546f3bab1fSbouyer *
556f3bab1fSbouyer * THIS IS THE DEFAULT ERROR HANDLER
566f3bab1fSbouyer */
576f3bab1fSbouyer int
atapi_interpret_sense(struct scsipi_xfer * xs)586cb9b748Sthorpej atapi_interpret_sense(struct scsipi_xfer *xs)
596f3bab1fSbouyer {
60937a7a3eSbouyer struct scsipi_periph *periph = xs->xs_periph;
616f3bab1fSbouyer int key, error;
623acb3fe6Schristos const char *msg = NULL;
636f3bab1fSbouyer
646f3bab1fSbouyer /*
65f0a7346dSsnj * If the device has its own error handler, call it first.
666f3bab1fSbouyer * If it returns a legit error value, return that, otherwise
676f3bab1fSbouyer * it wants us to continue with normal error processing.
686f3bab1fSbouyer */
69937a7a3eSbouyer if (periph->periph_switch->psw_error != NULL) {
70937a7a3eSbouyer SC_DEBUG(periph, SCSIPI_DB2,
716f3bab1fSbouyer ("calling private err_handler()\n"));
72937a7a3eSbouyer error = (*periph->periph_switch->psw_error)(xs);
73937a7a3eSbouyer if (error != EJUSTRETURN)
74937a7a3eSbouyer return (error);
756f3bab1fSbouyer }
760d0ff884Sbouyer /*
770d0ff884Sbouyer * otherwise use the default, call the generic sense handler if we have
780d0ff884Sbouyer * more than the sense key
790d0ff884Sbouyer */
800d0ff884Sbouyer if (xs->error == XS_SENSE)
810d0ff884Sbouyer return (scsipi_interpret_sense(xs));
820d0ff884Sbouyer
830d0ff884Sbouyer key = (xs->sense.atapi_sense & 0xf0) >> 4;
846f3bab1fSbouyer switch (key) {
850978d23cSmjacob case SKEY_RECOVERED_ERROR:
866f3bab1fSbouyer msg = "soft error (corrected)";
87*fbffadb9Smrg /* FALLTHROUGH */
886aa030f9Smjacob case SKEY_NO_SENSE:
896f3bab1fSbouyer if (xs->resid == xs->datalen)
906f3bab1fSbouyer xs->resid = 0; /* not short read */
916f3bab1fSbouyer error = 0;
926f3bab1fSbouyer break;
936aa030f9Smjacob case SKEY_NOT_READY:
94937a7a3eSbouyer if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
95937a7a3eSbouyer periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
9616a9d90eSthorpej if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
97d7d845c3Senami return (0);
9816a9d90eSthorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
99d7d845c3Senami return (EIO);
1006f3bab1fSbouyer msg = "not ready";
1016f3bab1fSbouyer error = EIO;
1026f3bab1fSbouyer break;
1036aa030f9Smjacob case SKEY_MEDIUM_ERROR: /* MEDIUM ERROR */
1046f3bab1fSbouyer msg = "medium error";
1056f3bab1fSbouyer error = EIO;
1066f3bab1fSbouyer break;
1076aa030f9Smjacob case SKEY_HARDWARE_ERROR:
1086f3bab1fSbouyer msg = "non-media hardware failure";
1096f3bab1fSbouyer error = EIO;
1106f3bab1fSbouyer break;
1116aa030f9Smjacob case SKEY_ILLEGAL_REQUEST:
11216a9d90eSthorpej if ((xs->xs_control &
11316a9d90eSthorpej XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
114d7d845c3Senami return (0);
11516a9d90eSthorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
116d7d845c3Senami return (EIO);
1176f3bab1fSbouyer msg = "illegal request";
1186f3bab1fSbouyer error = EINVAL;
1196f3bab1fSbouyer break;
1206aa030f9Smjacob case SKEY_UNIT_ATTENTION:
121937a7a3eSbouyer if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
122937a7a3eSbouyer periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
12316a9d90eSthorpej if ((xs->xs_control &
12416a9d90eSthorpej XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
1256f3bab1fSbouyer /* XXX Should reupload any transient state. */
126937a7a3eSbouyer (periph->periph_flags & PERIPH_REMOVABLE) == 0)
127d7d845c3Senami return (ERESTART);
12816a9d90eSthorpej if ((xs->xs_control & XS_CTL_SILENT) != 0)
129d7d845c3Senami return (EIO);
1306f3bab1fSbouyer msg = "unit attention";
1316f3bab1fSbouyer error = EIO;
1326f3bab1fSbouyer break;
133df9803ceSthorpej case SKEY_DATA_PROTECT:
1346f3bab1fSbouyer msg = "readonly device";
135d5ad6606Sis error = EROFS;
1366f3bab1fSbouyer break;
1376aa030f9Smjacob case SKEY_ABORTED_COMMAND:
1386f3bab1fSbouyer msg = "command aborted";
139567e3c10Sbouyer if (xs->xs_retries != 0) {
140567e3c10Sbouyer xs->xs_retries--;
1416f3bab1fSbouyer error = ERESTART;
142567e3c10Sbouyer } else
143567e3c10Sbouyer error = EIO;
1446f3bab1fSbouyer break;
1456f3bab1fSbouyer default:
1466f3bab1fSbouyer error = EIO;
1476f3bab1fSbouyer break;
1486f3bab1fSbouyer }
1496f3bab1fSbouyer
1506f3bab1fSbouyer if (!key) {
1516f3bab1fSbouyer if (xs->sense.atapi_sense & 0x01) {
1526f3bab1fSbouyer /* Illegal length indication */
1536f3bab1fSbouyer msg = "ATA illegal length indication";
1546f3bab1fSbouyer error = EIO;
1556f3bab1fSbouyer }
1566f3bab1fSbouyer if (xs->sense.atapi_sense & 0x02) { /* vol overflow */
1576f3bab1fSbouyer msg = "ATA volume overflow";
1586f3bab1fSbouyer error = ENOSPC;
1596f3bab1fSbouyer }
1606f3bab1fSbouyer if (xs->sense.atapi_sense & 0x04) { /* Aborted command */
1616f3bab1fSbouyer msg = "ATA command aborted";
162567e3c10Sbouyer if (xs->xs_retries != 0) {
163567e3c10Sbouyer xs->xs_retries--;
1646f3bab1fSbouyer error = ERESTART;
165567e3c10Sbouyer } else
166567e3c10Sbouyer error = EIO;
1676f3bab1fSbouyer }
1686f3bab1fSbouyer }
1696f3bab1fSbouyer if (msg) {
170937a7a3eSbouyer scsipi_printaddr(periph);
1716f3bab1fSbouyer printf("%s\n", msg);
1726f3bab1fSbouyer } else {
1736f3bab1fSbouyer if (error) {
174937a7a3eSbouyer scsipi_printaddr(periph);
1756f3bab1fSbouyer printf("unknown error code %d\n",
1766f3bab1fSbouyer xs->sense.atapi_sense);
1776f3bab1fSbouyer }
1786f3bab1fSbouyer }
1796f3bab1fSbouyer
180d7d845c3Senami return (error);
1816f3bab1fSbouyer }
1826f3bab1fSbouyer
1836f3bab1fSbouyer /*
1846f3bab1fSbouyer * Utility routines often used in SCSI stuff
1856f3bab1fSbouyer */
1866f3bab1fSbouyer
1876f3bab1fSbouyer
1886f3bab1fSbouyer /*
1896f3bab1fSbouyer * Print out the scsi_link structure's address info.
1906f3bab1fSbouyer */
1916f3bab1fSbouyer void
atapi_print_addr(struct scsipi_periph * periph)1926cb9b748Sthorpej atapi_print_addr(struct scsipi_periph *periph)
1936f3bab1fSbouyer {
194937a7a3eSbouyer struct scsipi_channel *chan = periph->periph_channel;
195937a7a3eSbouyer struct scsipi_adapter *adapt = chan->chan_adapter;
1966f3bab1fSbouyer
197937a7a3eSbouyer printf("%s(%s:%d:%d): ", periph->periph_dev != NULL ?
19813783bfdScegger device_xname(periph->periph_dev) : "probe",
19913783bfdScegger device_xname(adapt->adapt_dev),
200937a7a3eSbouyer chan->chan_channel, periph->periph_target);
2016f3bab1fSbouyer }
2026f3bab1fSbouyer
2036f3bab1fSbouyer /*
2046f3bab1fSbouyer * ask the atapi driver to perform a command for us.
2056f3bab1fSbouyer * tell it where to read/write the data, and how
2066f3bab1fSbouyer * long the data is supposed to be. If we have a buf
2076f3bab1fSbouyer * to associate with the transfer, we need that too.
2086f3bab1fSbouyer */
209ba781da1Smycroft void
atapi_scsipi_cmd(struct scsipi_xfer * xs)210ba781da1Smycroft atapi_scsipi_cmd(struct scsipi_xfer *xs)
2116f3bab1fSbouyer {
212ba781da1Smycroft struct scsipi_periph *periph = xs->xs_periph;
2136f3bab1fSbouyer
214937a7a3eSbouyer SC_DEBUG(periph, SCSIPI_DB2, ("atapi_cmd\n"));
2156f3bab1fSbouyer
216937a7a3eSbouyer xs->cmdlen = (periph->periph_cap & PERIPH_CAP_CMD16) ? 16 : 12;
2176f3bab1fSbouyer }
218