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