cam_periph.c revision 42957
139212Sgibbs/*
239212Sgibbs * Common functions for CAM "type" (peripheral) drivers.
339212Sgibbs *
439212Sgibbs * Copyright (c) 1997, 1998 Justin T. Gibbs.
539212Sgibbs * Copyright (c) 1997, 1998 Kenneth D. Merry.
639212Sgibbs * All rights reserved.
739212Sgibbs *
839212Sgibbs * Redistribution and use in source and binary forms, with or without
939212Sgibbs * modification, are permitted provided that the following conditions
1039212Sgibbs * are met:
1139212Sgibbs * 1. Redistributions of source code must retain the above copyright
1239212Sgibbs *    notice, this list of conditions, and the following disclaimer,
1339212Sgibbs *    without modification, immediately at the beginning of the file.
1439212Sgibbs * 2. The name of the author may not be used to endorse or promote products
1539212Sgibbs *    derived from this software without specific prior written permission.
1639212Sgibbs *
1739212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1839212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1939212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2039212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2139212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2239212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2339212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2439212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2539212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2639212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2739212Sgibbs * SUCH DAMAGE.
2839212Sgibbs *
2942957Sdillon *      $Id: cam_periph.c,v 1.9 1999/01/14 06:21:54 jdp Exp $
3039212Sgibbs */
3139212Sgibbs
3239212Sgibbs#include <sys/param.h>
3339212Sgibbs#include <sys/systm.h>
3439212Sgibbs#include <sys/types.h>
3539212Sgibbs#include <sys/malloc.h>
3642654Sjdp#include <sys/linker_set.h>
3739212Sgibbs#include <sys/buf.h>
3839212Sgibbs#include <sys/proc.h>
3939212Sgibbs#include <sys/devicestat.h>
4039212Sgibbs#include <vm/vm.h>
4139212Sgibbs#include <vm/vm_extern.h>
4239212Sgibbs
4339212Sgibbs#include <cam/cam.h>
4439212Sgibbs#include <cam/cam_conf.h>
4539212Sgibbs#include <cam/cam_ccb.h>
4639212Sgibbs#include <cam/cam_xpt_periph.h>
4739212Sgibbs#include <cam/cam_periph.h>
4839212Sgibbs#include <cam/cam_debug.h>
4939212Sgibbs
5039212Sgibbs#include <cam/scsi/scsi_all.h>
5139212Sgibbs#include <cam/scsi/scsi_message.h>
5239212Sgibbs#include <cam/scsi/scsi_da.h>
5339212Sgibbs#include <cam/scsi/scsi_pass.h>
5439212Sgibbs
5539212Sgibbsstatic	u_int		camperiphnextunit(struct periph_driver *p_drv,
5639212Sgibbs					  u_int newunit, int wired);
5739212Sgibbsstatic	u_int		camperiphunit(struct periph_driver *p_drv,
5839212Sgibbs				      path_id_t path_id_t,
5939212Sgibbs				      target_id_t target, lun_id_t lun);
6039212Sgibbsstatic	void		camperiphdone(struct cam_periph *periph,
6139212Sgibbs					union ccb *done_ccb);
6239212Sgibbsstatic  void		camperiphfree(struct cam_periph *periph);
6339212Sgibbs
6439212Sgibbscam_status
6540603Skencam_periph_alloc(periph_ctor_t *periph_ctor,
6640603Sken		 periph_oninv_t *periph_oninvalidate,
6740603Sken		 periph_dtor_t *periph_dtor, periph_start_t *periph_start,
6840603Sken		 char *name, cam_periph_type type, struct cam_path *path,
6940603Sken		 ac_callback_t *ac_callback, ac_code code, void *arg)
7039212Sgibbs{
7139212Sgibbs	struct		periph_driver **p_drv;
7239212Sgibbs	struct		cam_periph *periph;
7339212Sgibbs	struct		cam_periph *cur_periph;
7439212Sgibbs	path_id_t	path_id;
7539212Sgibbs	target_id_t	target_id;
7639212Sgibbs	lun_id_t	lun_id;
7739212Sgibbs	cam_status	status;
7839212Sgibbs	u_int		init_level;
7939212Sgibbs	int s;
8039212Sgibbs
8139212Sgibbs	init_level = 0;
8239212Sgibbs	/*
8339212Sgibbs	 * Handle Hot-Plug scenarios.  If there is already a peripheral
8439212Sgibbs	 * of our type assigned to this path, we are likely waiting for
8539212Sgibbs	 * final close on an old, invalidated, peripheral.  If this is
8639212Sgibbs	 * the case, queue up a deferred call to the peripheral's async
8739212Sgibbs	 * handler.  If it looks like a mistaken re-alloation, complain.
8839212Sgibbs	 */
8939212Sgibbs	if ((periph = cam_periph_find(path, name)) != NULL) {
9039212Sgibbs
9139212Sgibbs		if ((periph->flags & CAM_PERIPH_INVALID) != 0
9239212Sgibbs		 && (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) == 0) {
9339212Sgibbs			periph->flags |= CAM_PERIPH_NEW_DEV_FOUND;
9439212Sgibbs			periph->deferred_callback = ac_callback;
9539212Sgibbs			periph->deferred_ac = code;
9639212Sgibbs			return (CAM_REQ_INPROG);
9739212Sgibbs		} else {
9839212Sgibbs			printf("cam_periph_alloc: attempt to re-allocate "
9939212Sgibbs			       "valid device %s%d rejected\n",
10039212Sgibbs			       periph->periph_name, periph->unit_number);
10139212Sgibbs		}
10239212Sgibbs		return (CAM_REQ_INVALID);
10339212Sgibbs	}
10439212Sgibbs
10539212Sgibbs	periph = (struct cam_periph *)malloc(sizeof(*periph), M_DEVBUF,
10639212Sgibbs					     M_NOWAIT);
10739212Sgibbs
10839212Sgibbs	if (periph == NULL)
10939212Sgibbs		return (CAM_RESRC_UNAVAIL);
11039212Sgibbs
11139212Sgibbs	init_level++;
11239212Sgibbs
11339212Sgibbs	for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
11439212Sgibbs	     *p_drv != NULL; p_drv++) {
11539212Sgibbs		if (strcmp((*p_drv)->driver_name, name) == 0)
11639212Sgibbs			break;
11739212Sgibbs	}
11839212Sgibbs
11939212Sgibbs	path_id = xpt_path_path_id(path);
12039212Sgibbs	target_id = xpt_path_target_id(path);
12139212Sgibbs	lun_id = xpt_path_lun_id(path);
12239212Sgibbs	bzero(periph, sizeof(*periph));
12339212Sgibbs	cam_init_pinfo(&periph->pinfo);
12439212Sgibbs	periph->periph_start = periph_start;
12539212Sgibbs	periph->periph_dtor = periph_dtor;
12640603Sken	periph->periph_oninval = periph_oninvalidate;
12739212Sgibbs	periph->type = type;
12839212Sgibbs	periph->periph_name = name;
12939212Sgibbs	periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
13039212Sgibbs	periph->immediate_priority = CAM_PRIORITY_NONE;
13139212Sgibbs	periph->refcount = 0;
13239212Sgibbs	SLIST_INIT(&periph->ccb_list);
13339212Sgibbs	status = xpt_create_path(&path, periph, path_id, target_id, lun_id);
13439212Sgibbs	if (status != CAM_REQ_CMP)
13539212Sgibbs		goto failure;
13639212Sgibbs
13739212Sgibbs	periph->path = path;
13839212Sgibbs	init_level++;
13939212Sgibbs
14039212Sgibbs	status = xpt_add_periph(periph);
14139212Sgibbs
14239212Sgibbs	if (status != CAM_REQ_CMP)
14339212Sgibbs		goto failure;
14439212Sgibbs
14539212Sgibbs	s = splsoftcam();
14639212Sgibbs	cur_periph = TAILQ_FIRST(&(*p_drv)->units);
14739212Sgibbs	while (cur_periph != NULL
14839212Sgibbs	    && cur_periph->unit_number < periph->unit_number)
14939212Sgibbs		cur_periph = TAILQ_NEXT(cur_periph, unit_links);
15039212Sgibbs
15139212Sgibbs	if (cur_periph != NULL)
15239212Sgibbs		TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links);
15339212Sgibbs	else {
15439212Sgibbs		TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links);
15539212Sgibbs		(*p_drv)->generation++;
15639212Sgibbs	}
15739212Sgibbs
15839212Sgibbs	splx(s);
15939212Sgibbs
16039212Sgibbs	init_level++;
16139212Sgibbs
16239212Sgibbs	status = periph_ctor(periph, arg);
16339212Sgibbs
16439212Sgibbs	if (status == CAM_REQ_CMP)
16539212Sgibbs		init_level++;
16639212Sgibbs
16739212Sgibbsfailure:
16839212Sgibbs	switch (init_level) {
16939212Sgibbs	case 4:
17039212Sgibbs		/* Initialized successfully */
17139212Sgibbs		break;
17239212Sgibbs	case 3:
17339212Sgibbs		s = splsoftcam();
17439212Sgibbs		TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
17539212Sgibbs		splx(s);
17639212Sgibbs		xpt_remove_periph(periph);
17739212Sgibbs	case 2:
17839212Sgibbs		xpt_free_path(periph->path);
17939212Sgibbs	case 1:
18039212Sgibbs		free(periph, M_DEVBUF);
18139212Sgibbs	case 0:
18239212Sgibbs		/* No cleanup to perform. */
18339212Sgibbs		break;
18439212Sgibbs	default:
18539212Sgibbs		panic("cam_periph_alloc: Unkown init level");
18639212Sgibbs	}
18739212Sgibbs	return(status);
18839212Sgibbs}
18939212Sgibbs
19039212Sgibbs/*
19139212Sgibbs * Find a peripheral structure with the specified path, target, lun,
19239212Sgibbs * and (optionally) type.  If the name is NULL, this function will return
19339212Sgibbs * the first peripheral driver that matches the specified path.
19439212Sgibbs */
19539212Sgibbsstruct cam_periph *
19639212Sgibbscam_periph_find(struct cam_path *path, char *name)
19739212Sgibbs{
19839212Sgibbs	struct periph_driver **p_drv;
19939212Sgibbs	struct cam_periph *periph;
20039212Sgibbs	int s;
20139212Sgibbs
20239212Sgibbs	for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
20339212Sgibbs	     *p_drv != NULL; p_drv++) {
20439212Sgibbs
20539212Sgibbs		if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0))
20639212Sgibbs			continue;
20739212Sgibbs
20839212Sgibbs		s = splsoftcam();
20939212Sgibbs		for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL;
21039212Sgibbs		     periph = TAILQ_NEXT(periph, unit_links)) {
21139212Sgibbs			if (xpt_path_comp(periph->path, path) == 0) {
21239212Sgibbs				splx(s);
21339212Sgibbs				return(periph);
21439212Sgibbs			}
21539212Sgibbs		}
21639212Sgibbs		splx(s);
21739212Sgibbs		if (name != NULL)
21839212Sgibbs			return(NULL);
21939212Sgibbs	}
22039212Sgibbs	return(NULL);
22139212Sgibbs}
22239212Sgibbs
22339212Sgibbscam_status
22439212Sgibbscam_periph_acquire(struct cam_periph *periph)
22539212Sgibbs{
22639212Sgibbs	int s;
22739212Sgibbs
22839212Sgibbs	if (periph == NULL)
22939212Sgibbs		return(CAM_REQ_CMP_ERR);
23039212Sgibbs
23139212Sgibbs	s = splsoftcam();
23239212Sgibbs	periph->refcount++;
23339212Sgibbs	splx(s);
23439212Sgibbs
23539212Sgibbs	return(CAM_REQ_CMP);
23639212Sgibbs}
23739212Sgibbs
23839212Sgibbsvoid
23939212Sgibbscam_periph_release(struct cam_periph *periph)
24039212Sgibbs{
24139212Sgibbs	int s;
24239212Sgibbs
24339212Sgibbs	if (periph == NULL)
24439212Sgibbs		return;
24539212Sgibbs
24639212Sgibbs	s = splsoftcam();
24739212Sgibbs	if ((--periph->refcount == 0)
24839212Sgibbs	 && (periph->flags & CAM_PERIPH_INVALID)) {
24939212Sgibbs		camperiphfree(periph);
25039212Sgibbs	}
25139212Sgibbs	splx(s);
25239212Sgibbs
25339212Sgibbs}
25439212Sgibbs
25539212Sgibbs/*
25639212Sgibbs * Look for the next unit number that is not currently in use for this
25739212Sgibbs * peripheral type starting at "newunit".  Also exclude unit numbers that
25839212Sgibbs * are reserved by for future "hardwiring" unless we already know that this
25939212Sgibbs * is a potential wired device.  Only assume that the device is "wired" the
26039212Sgibbs * first time through the loop since after that we'll be looking at unit
26139212Sgibbs * numbers that did not match a wiring entry.
26239212Sgibbs */
26339212Sgibbsstatic u_int
26439212Sgibbscamperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired)
26539212Sgibbs{
26639212Sgibbs	struct	cam_periph *periph;
26739212Sgibbs	struct	cam_periph_config *periph_conf;
26839212Sgibbs	char	*periph_name;
26939212Sgibbs	int	s;
27039212Sgibbs
27139212Sgibbs	s = splsoftcam();
27239212Sgibbs	periph_name = p_drv->driver_name;
27339212Sgibbs	for (;;newunit++) {
27439212Sgibbs
27539212Sgibbs		for (periph = TAILQ_FIRST(&p_drv->units);
27639212Sgibbs		     periph != NULL && periph->unit_number != newunit;
27739212Sgibbs		     periph = TAILQ_NEXT(periph, unit_links))
27839212Sgibbs			;
27939212Sgibbs
28039212Sgibbs		if (periph != NULL && periph->unit_number == newunit) {
28139212Sgibbs			if (wired != 0) {
28239212Sgibbs				xpt_print_path(periph->path);
28339212Sgibbs				printf("Duplicate Wired Device entry!\n");
28439212Sgibbs				xpt_print_path(periph->path);
28539212Sgibbs				printf("Second device will not be wired\n");
28639212Sgibbs				wired = 0;
28739212Sgibbs			}
28839212Sgibbs			continue;
28939212Sgibbs		}
29039212Sgibbs
29139212Sgibbs		for (periph_conf = cam_pinit;
29239212Sgibbs		     wired == 0 && periph_conf->periph_name != NULL;
29339212Sgibbs		     periph_conf++) {
29439212Sgibbs
29539212Sgibbs			/*
29639212Sgibbs			 * Don't match entries like "da 4" as a wired down
29739212Sgibbs			 * device, but do match entries like "da 4 target 5"
29839212Sgibbs			 * or even "da 4 scbus 1".
29939212Sgibbs			 */
30039212Sgibbs			if (IS_SPECIFIED(periph_conf->periph_unit)
30139212Sgibbs			 && (!strcmp(periph_name, periph_conf->periph_name))
30239212Sgibbs			 && (IS_SPECIFIED(periph_conf->target)
30339212Sgibbs			  || IS_SPECIFIED(periph_conf->pathid))
30439212Sgibbs			 && (newunit == periph_conf->periph_unit))
30539212Sgibbs				break;
30639212Sgibbs		}
30739212Sgibbs
30839212Sgibbs		if (wired != 0 || periph_conf->periph_name == NULL)
30939212Sgibbs			break;
31039212Sgibbs	}
31139212Sgibbs	splx(s);
31239212Sgibbs	return (newunit);
31339212Sgibbs}
31439212Sgibbs
31539212Sgibbsstatic u_int
31639212Sgibbscamperiphunit(struct periph_driver *p_drv, path_id_t pathid,
31739212Sgibbs	      target_id_t target, lun_id_t lun)
31839212Sgibbs{
31939212Sgibbs	struct cam_periph_config *periph_conf;
32039212Sgibbs	u_int unit;
32139212Sgibbs	int hit;
32239212Sgibbs
32339212Sgibbs	unit = 0;
32439212Sgibbs	hit = 0;
32539212Sgibbs
32639212Sgibbs	for (periph_conf = cam_pinit;
32739212Sgibbs	     periph_conf->periph_name != NULL;
32839212Sgibbs	     periph_conf++, hit = 0) {
32939212Sgibbs
33039212Sgibbs		if (!strcmp(p_drv->driver_name, periph_conf->periph_name)
33139212Sgibbs		 && IS_SPECIFIED(periph_conf->periph_unit)) {
33239212Sgibbs
33339212Sgibbs			if (IS_SPECIFIED(periph_conf->pathid)) {
33439212Sgibbs
33539212Sgibbs				if (pathid != periph_conf->pathid)
33639212Sgibbs					continue;
33739212Sgibbs				hit++;
33839212Sgibbs			}
33939212Sgibbs
34039212Sgibbs			if (IS_SPECIFIED(periph_conf->target)) {
34139212Sgibbs
34239212Sgibbs				if (target != periph_conf->target)
34339212Sgibbs					continue;
34439212Sgibbs				hit++;
34539212Sgibbs			}
34639212Sgibbs
34739212Sgibbs			if (IS_SPECIFIED(periph_conf->lun)) {
34839212Sgibbs
34939212Sgibbs				if (lun != periph_conf->lun)
35039212Sgibbs					continue;
35139212Sgibbs				hit++;
35239212Sgibbs			}
35339212Sgibbs
35439212Sgibbs			if (hit != 0) {
35539212Sgibbs				unit = periph_conf->periph_unit;
35639212Sgibbs				break;
35739212Sgibbs			}
35839212Sgibbs		}
35939212Sgibbs	}
36039212Sgibbs
36139212Sgibbs	/*
36239212Sgibbs	 * Either start from 0 looking for the next unit or from
36339212Sgibbs	 * the unit number given in the periph_conf.  This way,
36439212Sgibbs	 * if we have wildcard matches, we don't return the same
36539212Sgibbs	 * unit number twice.
36639212Sgibbs	 */
36739212Sgibbs	unit = camperiphnextunit(p_drv, unit, /*wired*/hit);
36839212Sgibbs
36939212Sgibbs	return (unit);
37039212Sgibbs}
37139212Sgibbs
37239212Sgibbsvoid
37339212Sgibbscam_periph_invalidate(struct cam_periph *periph)
37439212Sgibbs{
37539212Sgibbs	int s;
37639212Sgibbs
37740603Sken	s = splsoftcam();
37840603Sken	/*
37940603Sken	 * We only call this routine the first time a peripheral is
38040603Sken	 * invalidated.  The oninvalidate() routine is always called at
38140603Sken	 * splsoftcam().
38240603Sken	 */
38340603Sken	if (((periph->flags & CAM_PERIPH_INVALID) == 0)
38440603Sken	 && (periph->periph_oninval != NULL))
38540603Sken		periph->periph_oninval(periph);
38640603Sken
38739212Sgibbs	periph->flags |= CAM_PERIPH_INVALID;
38839212Sgibbs	periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND;
38939212Sgibbs
39039212Sgibbs	if (periph->refcount == 0)
39139212Sgibbs		camperiphfree(periph);
39239212Sgibbs	else if (periph->refcount < 0)
39339212Sgibbs		printf("cam_invalidate_periph: refcount < 0!!\n");
39439212Sgibbs	splx(s);
39539212Sgibbs}
39639212Sgibbs
39739212Sgibbsstatic void
39839212Sgibbscamperiphfree(struct cam_periph *periph)
39939212Sgibbs{
40039212Sgibbs	int s;
40139212Sgibbs	struct periph_driver **p_drv;
40239212Sgibbs
40339212Sgibbs	for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
40439212Sgibbs	     *p_drv != NULL; p_drv++) {
40539212Sgibbs		if (strcmp((*p_drv)->driver_name, periph->periph_name) == 0)
40639212Sgibbs			break;
40739212Sgibbs	}
40839212Sgibbs
40939212Sgibbs	if (periph->periph_dtor != NULL)
41039212Sgibbs		periph->periph_dtor(periph);
41139212Sgibbs
41239212Sgibbs	s = splsoftcam();
41339212Sgibbs	TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
41439212Sgibbs	(*p_drv)->generation++;
41539212Sgibbs	splx(s);
41639212Sgibbs
41739212Sgibbs	xpt_remove_periph(periph);
41839212Sgibbs
41939212Sgibbs	if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
42039212Sgibbs		union ccb ccb;
42139212Sgibbs		void *arg;
42239212Sgibbs
42339212Sgibbs		switch (periph->deferred_ac) {
42439212Sgibbs		case AC_FOUND_DEVICE:
42539212Sgibbs			ccb.ccb_h.func_code = XPT_GDEV_TYPE;
42639212Sgibbs			xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
42739212Sgibbs			xpt_action(&ccb);
42839212Sgibbs			arg = &ccb;
42939212Sgibbs			break;
43039212Sgibbs		case AC_PATH_REGISTERED:
43139212Sgibbs			ccb.ccb_h.func_code = XPT_PATH_INQ;
43239212Sgibbs			xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
43339212Sgibbs			xpt_action(&ccb);
43439212Sgibbs			arg = &ccb;
43539212Sgibbs			break;
43639212Sgibbs		default:
43739212Sgibbs			arg = NULL;
43839212Sgibbs			break;
43939212Sgibbs		}
44039212Sgibbs		periph->deferred_callback(NULL, periph->deferred_ac,
44139212Sgibbs					  periph->path, arg);
44239212Sgibbs	}
44339212Sgibbs	xpt_free_path(periph->path);
44439212Sgibbs	free(periph, M_DEVBUF);
44539212Sgibbs}
44639212Sgibbs
44739212Sgibbs/*
44839212Sgibbs * Wait interruptibly for an exclusive lock.
44939212Sgibbs */
45039212Sgibbsint
45139212Sgibbscam_periph_lock(struct cam_periph *periph, int priority)
45239212Sgibbs{
45339212Sgibbs	int error;
45439212Sgibbs
45539212Sgibbs	while ((periph->flags & CAM_PERIPH_LOCKED) != 0) {
45639212Sgibbs		periph->flags |= CAM_PERIPH_LOCK_WANTED;
45739212Sgibbs		if ((error = tsleep(periph, priority, "caplck", 0)) != 0)
45839212Sgibbs			return error;
45939212Sgibbs	}
46039212Sgibbs
46139212Sgibbs	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
46239212Sgibbs		return(ENXIO);
46339212Sgibbs
46439212Sgibbs	periph->flags |= CAM_PERIPH_LOCKED;
46539212Sgibbs	return 0;
46639212Sgibbs}
46739212Sgibbs
46839212Sgibbs/*
46939212Sgibbs * Unlock and wake up any waiters.
47039212Sgibbs */
47139212Sgibbsvoid
47239212Sgibbscam_periph_unlock(struct cam_periph *periph)
47339212Sgibbs{
47439212Sgibbs	periph->flags &= ~CAM_PERIPH_LOCKED;
47539212Sgibbs	if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) {
47639212Sgibbs		periph->flags &= ~CAM_PERIPH_LOCK_WANTED;
47739212Sgibbs		wakeup(periph);
47839212Sgibbs	}
47939212Sgibbs
48039212Sgibbs	cam_periph_release(periph);
48139212Sgibbs}
48239212Sgibbs
48339212Sgibbs/*
48439212Sgibbs * Map user virtual pointers into kernel virtual address space, so we can
48539212Sgibbs * access the memory.  This won't work on physical pointers, for now it's
48639212Sgibbs * up to the caller to check for that.  (XXX KDM -- should we do that here
48739212Sgibbs * instead?)  This also only works for up to MAXPHYS memory.  Since we use
48839212Sgibbs * buffers to map stuff in and out, we're limited to the buffer size.
48939212Sgibbs */
49039212Sgibbsint
49139212Sgibbscam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
49239212Sgibbs{
49341877Sken	int numbufs, i;
49441877Sken	int flags[CAM_PERIPH_MAXMAPS];
49539212Sgibbs	u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
49639212Sgibbs	u_int32_t lengths[CAM_PERIPH_MAXMAPS];
49739212Sgibbs	u_int32_t dirs[CAM_PERIPH_MAXMAPS];
49839212Sgibbs
49939212Sgibbs	switch(ccb->ccb_h.func_code) {
50039212Sgibbs	case XPT_DEV_MATCH:
50139212Sgibbs		if (ccb->cdm.match_buf_len == 0) {
50239212Sgibbs			printf("cam_periph_mapmem: invalid match buffer "
50339212Sgibbs			       "length 0\n");
50439212Sgibbs			return(EINVAL);
50539212Sgibbs		}
50639212Sgibbs		if (ccb->cdm.pattern_buf_len > 0) {
50739212Sgibbs			data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
50839212Sgibbs			lengths[0] = ccb->cdm.pattern_buf_len;
50939212Sgibbs			dirs[0] = CAM_DIR_OUT;
51039212Sgibbs			data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
51139212Sgibbs			lengths[1] = ccb->cdm.match_buf_len;
51239212Sgibbs			dirs[1] = CAM_DIR_IN;
51339212Sgibbs			numbufs = 2;
51439212Sgibbs		} else {
51539212Sgibbs			data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
51639212Sgibbs			lengths[0] = ccb->cdm.match_buf_len;
51739212Sgibbs			dirs[0] = CAM_DIR_IN;
51839212Sgibbs			numbufs = 1;
51939212Sgibbs		}
52039212Sgibbs		break;
52139212Sgibbs	case XPT_SCSI_IO:
52239212Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
52339212Sgibbs			return(0);
52439212Sgibbs
52539212Sgibbs		data_ptrs[0] = &ccb->csio.data_ptr;
52641877Sken		lengths[0] = ccb->csio.dxfer_len;
52739212Sgibbs		dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
52839212Sgibbs		numbufs = 1;
52939212Sgibbs		break;
53039212Sgibbs	default:
53139212Sgibbs		return(EINVAL);
53239212Sgibbs		break; /* NOTREACHED */
53339212Sgibbs	}
53439212Sgibbs
53539212Sgibbs	/*
53641877Sken	 * Check the transfer length and permissions first, so we don't
53741877Sken	 * have to unmap any previously mapped buffers.
53839212Sgibbs	 */
53939212Sgibbs	for (i = 0; i < numbufs; i++) {
54039212Sgibbs
54141877Sken		flags[i] = 0;
54241877Sken
54341877Sken		/*
54441877Sken		 * The userland data pointer passed in may not be page
54541877Sken		 * aligned.  vmapbuf() truncates the address to a page
54641877Sken		 * boundary, so if the address isn't page aligned, we'll
54741877Sken		 * need enough space for the given transfer length, plus
54841877Sken		 * whatever extra space is necessary to make it to the page
54941877Sken		 * boundary.
55041877Sken		 */
55141877Sken		if ((lengths[i] +
55241885Sken		    (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > DFLTPHYS){
55341877Sken			printf("cam_periph_mapmem: attempt to map %u bytes, "
55441885Sken			       "which is greater than DFLTPHYS(%d)\n",
55541877Sken			       lengths[i] +
55641877Sken			       (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK),
55741885Sken			       DFLTPHYS);
55841877Sken			return(E2BIG);
55941877Sken		}
56041877Sken
56139212Sgibbs		if (dirs[i] & CAM_DIR_IN) {
56241877Sken			flags[i] = B_READ;
56339212Sgibbs			if (useracc(*data_ptrs[i], lengths[i], B_READ) == 0){
56439212Sgibbs				printf("cam_periph_mapmem: error, "
56539758Sbde					"address %p, length %lu isn't "
56639212Sgibbs					"user accessible for READ\n",
56739758Sbde					(void *)*data_ptrs[i],
56839758Sbde					(u_long)lengths[i]);
56939212Sgibbs				return(EACCES);
57039212Sgibbs			}
57139212Sgibbs		}
57239212Sgibbs
57339212Sgibbs		/*
57439212Sgibbs		 * XXX this check is really bogus, since B_WRITE currently
57539212Sgibbs		 * is all 0's, and so it is "set" all the time.
57639212Sgibbs		 */
57739212Sgibbs		if (dirs[i] & CAM_DIR_OUT) {
57841877Sken			flags[i] |= B_WRITE;
57939212Sgibbs			if (useracc(*data_ptrs[i], lengths[i], B_WRITE) == 0){
58039212Sgibbs				printf("cam_periph_mapmem: error, "
58139758Sbde					"address %p, length %lu isn't "
58239212Sgibbs					"user accessible for WRITE\n",
58339758Sbde					(void *)*data_ptrs[i],
58439758Sbde					(u_long)lengths[i]);
58539212Sgibbs
58639212Sgibbs				return(EACCES);
58739212Sgibbs			}
58839212Sgibbs		}
58939212Sgibbs
59041877Sken	}
59141877Sken
59241877Sken	/* this keeps the current process from getting swapped */
59341877Sken	/*
59441877Sken	 * XXX KDM should I use P_NOSWAP instead?
59541877Sken	 */
59641877Sken	curproc->p_flag |= P_PHYSIO;
59741877Sken
59841877Sken	for (i = 0; i < numbufs; i++) {
59939212Sgibbs		/*
60039212Sgibbs		 * Get the buffer.
60139212Sgibbs		 */
60242957Sdillon		mapinfo->bp[i] = getpbuf(NULL);
60339212Sgibbs
60439212Sgibbs		/* save the buffer's data address */
60539212Sgibbs		mapinfo->bp[i]->b_saveaddr = mapinfo->bp[i]->b_data;
60639212Sgibbs
60739212Sgibbs		/* put our pointer in the data slot */
60839212Sgibbs		mapinfo->bp[i]->b_data = *data_ptrs[i];
60939212Sgibbs
61041885Sken		/* set the transfer length, we know it's < DFLTPHYS */
61139212Sgibbs		mapinfo->bp[i]->b_bufsize = lengths[i];
61239212Sgibbs
61339212Sgibbs		/* set the flags */
61441877Sken		mapinfo->bp[i]->b_flags = flags[i] | B_PHYS | B_BUSY;
61539212Sgibbs
61639212Sgibbs		/* map the buffer into kernel memory */
61739212Sgibbs		vmapbuf(mapinfo->bp[i]);
61839212Sgibbs
61939212Sgibbs		/* set our pointer to the new mapped area */
62039212Sgibbs		*data_ptrs[i] = mapinfo->bp[i]->b_data;
62139212Sgibbs
62239212Sgibbs		mapinfo->num_bufs_used++;
62339212Sgibbs	}
62439212Sgibbs
62539212Sgibbs	return(0);
62639212Sgibbs}
62739212Sgibbs
62839212Sgibbs/*
62939212Sgibbs * Unmap memory segments mapped into kernel virtual address space by
63039212Sgibbs * cam_periph_mapmem().
63139212Sgibbs */
63239212Sgibbsvoid
63339212Sgibbscam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
63439212Sgibbs{
63539212Sgibbs	int numbufs, i;
63639212Sgibbs	u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
63739212Sgibbs
63839212Sgibbs	if (mapinfo->num_bufs_used <= 0) {
63939212Sgibbs		/* allow ourselves to be swapped once again */
64039212Sgibbs		curproc->p_flag &= ~P_PHYSIO;
64139212Sgibbs		return;
64239212Sgibbs	}
64339212Sgibbs
64439212Sgibbs	switch (ccb->ccb_h.func_code) {
64539212Sgibbs	case XPT_DEV_MATCH:
64639212Sgibbs		numbufs = min(mapinfo->num_bufs_used, 2);
64739212Sgibbs
64839212Sgibbs		if (numbufs == 1) {
64939212Sgibbs			data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
65039212Sgibbs		} else {
65139212Sgibbs			data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
65239212Sgibbs			data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
65339212Sgibbs		}
65439212Sgibbs		break;
65539212Sgibbs	case XPT_SCSI_IO:
65639212Sgibbs		data_ptrs[0] = &ccb->csio.data_ptr;
65739212Sgibbs		numbufs = min(mapinfo->num_bufs_used, 1);
65839212Sgibbs		break;
65939212Sgibbs	default:
66039212Sgibbs		/* allow ourselves to be swapped once again */
66139212Sgibbs		curproc->p_flag &= ~P_PHYSIO;
66239212Sgibbs		return;
66339212Sgibbs		break; /* NOTREACHED */
66439212Sgibbs	}
66539212Sgibbs
66639212Sgibbs	for (i = 0; i < numbufs; i++) {
66739212Sgibbs		/* Set the user's pointer back to the original value */
66839212Sgibbs		*data_ptrs[i] = mapinfo->bp[i]->b_saveaddr;
66939212Sgibbs
67039212Sgibbs		/* unmap the buffer */
67139212Sgibbs		vunmapbuf(mapinfo->bp[i]);
67239212Sgibbs
67339212Sgibbs		/* clear the flags we set above */
67439212Sgibbs		mapinfo->bp[i]->b_flags &= ~(B_PHYS|B_BUSY);
67539212Sgibbs
67639212Sgibbs		/* release the buffer */
67742957Sdillon		relpbuf(mapinfo->bp[i], NULL);
67839212Sgibbs	}
67939212Sgibbs
68039212Sgibbs	/* allow ourselves to be swapped once again */
68139212Sgibbs	curproc->p_flag &= ~P_PHYSIO;
68239212Sgibbs}
68339212Sgibbs
68439212Sgibbsunion ccb *
68539212Sgibbscam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
68639212Sgibbs{
68739212Sgibbs	struct ccb_hdr *ccb_h;
68839212Sgibbs	int s;
68939212Sgibbs
69039212Sgibbs	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n"));
69139212Sgibbs
69239212Sgibbs	s = splsoftcam();
69339212Sgibbs
69439212Sgibbs	while (periph->ccb_list.slh_first == NULL) {
69539212Sgibbs		if (periph->immediate_priority > priority)
69639212Sgibbs			periph->immediate_priority = priority;
69739212Sgibbs		xpt_schedule(periph, priority);
69839212Sgibbs		if ((periph->ccb_list.slh_first != NULL)
69939212Sgibbs		 && (periph->ccb_list.slh_first->pinfo.priority == priority))
70039212Sgibbs			break;
70139212Sgibbs		tsleep(&periph->ccb_list, PRIBIO, "cgticb", 0);
70239212Sgibbs	}
70339212Sgibbs
70439212Sgibbs	ccb_h = periph->ccb_list.slh_first;
70539212Sgibbs	SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle);
70639212Sgibbs	splx(s);
70739212Sgibbs	return ((union ccb *)ccb_h);
70839212Sgibbs}
70939212Sgibbs
71039212Sgibbsvoid
71139212Sgibbscam_periph_ccbwait(union ccb *ccb)
71239212Sgibbs{
71339212Sgibbs	int s;
71439212Sgibbs
71539212Sgibbs	s = splsoftcam();
71639212Sgibbs	if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
71739212Sgibbs	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
71839212Sgibbs		tsleep(&ccb->ccb_h.cbfcnp, PRIBIO, "cbwait", 0);
71939212Sgibbs
72039212Sgibbs	splx(s);
72139212Sgibbs}
72239212Sgibbs
72339212Sgibbsint
72439212Sgibbscam_periph_ioctl(struct cam_periph *periph, int cmd, caddr_t addr,
72539212Sgibbs		 int (*error_routine)(union ccb *ccb,
72639212Sgibbs				      cam_flags camflags,
72739212Sgibbs				      u_int32_t sense_flags))
72839212Sgibbs{
72939212Sgibbs	union ccb 	     *ccb;
73039212Sgibbs	int 		     error;
73139212Sgibbs	int		     found;
73239212Sgibbs
73339212Sgibbs	error = found = 0;
73439212Sgibbs
73539212Sgibbs	switch(cmd){
73639212Sgibbs	case CAMGETPASSTHRU:
73739212Sgibbs		ccb = cam_periph_getccb(periph, /* priority */ 1);
73839212Sgibbs		xpt_setup_ccb(&ccb->ccb_h,
73939212Sgibbs			      ccb->ccb_h.path,
74039212Sgibbs			      /*priority*/1);
74139212Sgibbs		ccb->ccb_h.func_code = XPT_GDEVLIST;
74239212Sgibbs
74339212Sgibbs		/*
74439212Sgibbs		 * Basically, the point of this is that we go through
74539212Sgibbs		 * getting the list of devices, until we find a passthrough
74639212Sgibbs		 * device.  In the current version of the CAM code, the
74739212Sgibbs		 * only way to determine what type of device we're dealing
74839212Sgibbs		 * with is by its name.
74939212Sgibbs		 */
75039212Sgibbs		while (found == 0) {
75139212Sgibbs			ccb->cgdl.index = 0;
75239212Sgibbs			ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
75339212Sgibbs			while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
75439212Sgibbs
75539212Sgibbs				/* we want the next device in the list */
75639212Sgibbs				xpt_action(ccb);
75739212Sgibbs				if (strncmp(ccb->cgdl.periph_name,
75839212Sgibbs				    "pass", 4) == 0){
75939212Sgibbs					found = 1;
76039212Sgibbs					break;
76139212Sgibbs				}
76239212Sgibbs			}
76339212Sgibbs			if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) &&
76439212Sgibbs			    (found == 0)) {
76539212Sgibbs				ccb->cgdl.periph_name[0] = '\0';
76639212Sgibbs				ccb->cgdl.unit_number = 0;
76739212Sgibbs				break;
76839212Sgibbs			}
76939212Sgibbs		}
77039212Sgibbs
77139212Sgibbs		/* copy the result back out */
77239212Sgibbs		bcopy(ccb, addr, sizeof(union ccb));
77339212Sgibbs
77439212Sgibbs		/* and release the ccb */
77539212Sgibbs		xpt_release_ccb(ccb);
77639212Sgibbs
77739212Sgibbs		break;
77839212Sgibbs	default:
77939212Sgibbs		error = ENOTTY;
78039212Sgibbs		break;
78139212Sgibbs	}
78239212Sgibbs	return(error);
78339212Sgibbs}
78439212Sgibbs
78539212Sgibbsint
78639212Sgibbscam_periph_runccb(union ccb *ccb,
78739212Sgibbs		  int (*error_routine)(union ccb *ccb,
78839212Sgibbs				       cam_flags camflags,
78939212Sgibbs				       u_int32_t sense_flags),
79039212Sgibbs		  cam_flags camflags, u_int32_t sense_flags,
79139212Sgibbs		  struct devstat *ds)
79239212Sgibbs{
79339212Sgibbs	int error;
79439212Sgibbs
79539212Sgibbs	error = 0;
79639212Sgibbs
79739212Sgibbs	/*
79839212Sgibbs	 * If the user has supplied a stats structure, and if we understand
79939212Sgibbs	 * this particular type of ccb, record the transaction start.
80039212Sgibbs	 */
80139212Sgibbs	if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
80239212Sgibbs		devstat_start_transaction(ds);
80339212Sgibbs
80439212Sgibbs	xpt_action(ccb);
80539212Sgibbs
80639212Sgibbs	do {
80739212Sgibbs		cam_periph_ccbwait(ccb);
80839212Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
80939212Sgibbs			error = 0;
81039212Sgibbs		else if (error_routine != NULL)
81139212Sgibbs			error = (*error_routine)(ccb, camflags, sense_flags);
81239212Sgibbs		else
81339212Sgibbs			error = 0;
81439212Sgibbs
81539212Sgibbs	} while (error == ERESTART);
81639212Sgibbs
81739212Sgibbs	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
81839212Sgibbs		cam_release_devq(ccb->ccb_h.path,
81939212Sgibbs				 /* relsim_flags */0,
82039212Sgibbs				 /* openings */0,
82139212Sgibbs				 /* timeout */0,
82239212Sgibbs				 /* getcount_only */ FALSE);
82339212Sgibbs
82439212Sgibbs	if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
82539212Sgibbs		devstat_end_transaction(ds,
82639212Sgibbs					ccb->csio.dxfer_len,
82739212Sgibbs					ccb->csio.tag_action & 0xf,
82839212Sgibbs					((ccb->ccb_h.flags & CAM_DIR_MASK) ==
82939212Sgibbs					CAM_DIR_NONE) ?  DEVSTAT_NO_DATA :
83039212Sgibbs					(ccb->ccb_h.flags & CAM_DIR_OUT) ?
83139212Sgibbs					DEVSTAT_WRITE :
83239212Sgibbs					DEVSTAT_READ);
83339212Sgibbs
83439212Sgibbs	return(error);
83539212Sgibbs}
83639212Sgibbs
83739212Sgibbsu_int32_t
83839212Sgibbscam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
83939212Sgibbs		 u_int32_t openings, u_int32_t timeout,
84039212Sgibbs		 int getcount_only)
84139212Sgibbs{
84239212Sgibbs	struct ccb_relsim crs;
84339212Sgibbs
84439212Sgibbs	xpt_setup_ccb(&crs.ccb_h, path,
84539212Sgibbs		      /*priority*/1);
84639212Sgibbs	crs.ccb_h.func_code = XPT_REL_SIMQ;
84739212Sgibbs	crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0;
84839212Sgibbs	crs.release_flags = relsim_flags;
84939212Sgibbs	crs.openings = openings;
85039212Sgibbs	crs.release_timeout = timeout;
85139212Sgibbs	xpt_action((union ccb *)&crs);
85239212Sgibbs	return (crs.qfrozen_cnt);
85339212Sgibbs}
85439212Sgibbs
85539212Sgibbs#define saved_ccb_ptr ppriv_ptr0
85639212Sgibbsstatic void
85739212Sgibbscamperiphdone(struct cam_periph *periph, union ccb *done_ccb)
85839212Sgibbs{
85939212Sgibbs	cam_status	status;
86039212Sgibbs	int		frozen;
86139212Sgibbs	int		sense;
86239212Sgibbs	struct scsi_start_stop_unit *scsi_cmd;
86339212Sgibbs	u_int32_t	relsim_flags, timeout;
86439212Sgibbs	u_int32_t	qfrozen_cnt;
86539212Sgibbs
86639212Sgibbs	status = done_ccb->ccb_h.status;
86739212Sgibbs	frozen = (status & CAM_DEV_QFRZN) != 0;
86839212Sgibbs	sense  = (status & CAM_AUTOSNS_VALID) != 0;
86939212Sgibbs	status &= CAM_STATUS_MASK;
87039212Sgibbs
87139212Sgibbs	timeout = 0;
87239212Sgibbs	relsim_flags = 0;
87339212Sgibbs
87439212Sgibbs	/*
87539212Sgibbs	 * Unfreeze the queue once if it is already frozen..
87639212Sgibbs	 */
87739212Sgibbs	if (frozen != 0) {
87839212Sgibbs		qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path,
87939212Sgibbs					      /*relsim_flags*/0,
88039212Sgibbs					      /*openings*/0,
88139212Sgibbs					      /*timeout*/0,
88239212Sgibbs					      /*getcount_only*/0);
88339212Sgibbs	}
88439212Sgibbs
88539212Sgibbs	switch (status) {
88639212Sgibbs
88739212Sgibbs	case CAM_REQ_CMP:
88839212Sgibbs
88939212Sgibbs		/*
89039212Sgibbs		 * If we have successfully taken a device from the not
89139212Sgibbs		 * ready to ready state, re-scan the device and re-get the
89239212Sgibbs		 * inquiry information.  Many devices (mostly disks) don't
89339212Sgibbs		 * properly report their inquiry information unless they
89439212Sgibbs		 * are spun up.
89539212Sgibbs		 */
89639212Sgibbs		if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) {
89739212Sgibbs			scsi_cmd = (struct scsi_start_stop_unit *)
89839212Sgibbs					&done_ccb->csio.cdb_io.cdb_bytes;
89939212Sgibbs
90039212Sgibbs		 	if (scsi_cmd->opcode == START_STOP_UNIT)
90139212Sgibbs				xpt_async(AC_INQ_CHANGED,
90239212Sgibbs					  done_ccb->ccb_h.path, NULL);
90339212Sgibbs		}
90439212Sgibbs		bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
90539212Sgibbs		      sizeof(union ccb));
90639212Sgibbs
90740318Sken		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
90840318Sken
90939212Sgibbs		xpt_action(done_ccb);
91039212Sgibbs
91139212Sgibbs		break;
91239212Sgibbs	case CAM_SCSI_STATUS_ERROR:
91339212Sgibbs		scsi_cmd = (struct scsi_start_stop_unit *)
91439212Sgibbs				&done_ccb->csio.cdb_io.cdb_bytes;
91539212Sgibbs		if (sense != 0) {
91639212Sgibbs			struct scsi_sense_data *sense;
91739212Sgibbs			int    error_code, sense_key, asc, ascq;
91839212Sgibbs
91939212Sgibbs			sense = &done_ccb->csio.sense_data;
92039212Sgibbs			scsi_extract_sense(sense, &error_code,
92139212Sgibbs					   &sense_key, &asc, &ascq);
92239212Sgibbs
92339212Sgibbs			/*
92439212Sgibbs	 		 * If the error is "invalid field in CDB",
92539212Sgibbs			 * and the load/eject flag is set, turn the
92639212Sgibbs			 * flag off and try again.  This is just in
92739212Sgibbs			 * case the drive in question barfs on the
92839212Sgibbs			 * load eject flag.  The CAM code should set
92939212Sgibbs			 * the load/eject flag by default for
93039212Sgibbs			 * removable media.
93139212Sgibbs			 */
93239212Sgibbs
93339212Sgibbs			/* XXX KDM
93439212Sgibbs			 * Should we check to see what the specific
93539212Sgibbs			 * scsi status is??  Or does it not matter
93639212Sgibbs			 * since we already know that there was an
93739212Sgibbs			 * error, and we know what the specific
93839212Sgibbs			 * error code was, and we know what the
93939212Sgibbs			 * opcode is..
94039212Sgibbs			 */
94139212Sgibbs			if ((scsi_cmd->opcode == START_STOP_UNIT) &&
94239212Sgibbs			    ((scsi_cmd->how & SSS_LOEJ) != 0) &&
94339212Sgibbs			     (asc == 0x24) && (ascq == 0x00) &&
94439212Sgibbs			     (done_ccb->ccb_h.retry_count > 0)) {
94539212Sgibbs
94639212Sgibbs				scsi_cmd->how &= ~SSS_LOEJ;
94739212Sgibbs
94839212Sgibbs				xpt_action(done_ccb);
94939212Sgibbs
95039212Sgibbs			} else if (done_ccb->ccb_h.retry_count > 0) {
95139212Sgibbs				/*
95239212Sgibbs				 * In this case, the error recovery
95339212Sgibbs				 * command failed, but we've got
95439212Sgibbs				 * some retries left on it.  Give
95539212Sgibbs				 * it another try.
95639212Sgibbs				 */
95739212Sgibbs
95839212Sgibbs				/* set the timeout to .5 sec */
95939212Sgibbs				relsim_flags =
96039212Sgibbs					RELSIM_RELEASE_AFTER_TIMEOUT;
96139212Sgibbs				timeout = 500;
96239212Sgibbs
96339212Sgibbs				xpt_action(done_ccb);
96439212Sgibbs
96539212Sgibbs				break;
96639212Sgibbs
96739212Sgibbs			} else {
96839212Sgibbs				/*
96939212Sgibbs				 * Copy the original CCB back and
97039212Sgibbs				 * send it back to the caller.
97139212Sgibbs				 */
97239212Sgibbs				bcopy(done_ccb->ccb_h.saved_ccb_ptr,
97339212Sgibbs				      done_ccb, sizeof(union ccb));
97439212Sgibbs
97540318Sken				periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
97640318Sken
97739212Sgibbs				xpt_action(done_ccb);
97839212Sgibbs			}
97939212Sgibbs		} else {
98039212Sgibbs			/*
98139212Sgibbs			 * Eh??  The command failed, but we don't
98239212Sgibbs			 * have any sense.  What's up with that?
98339212Sgibbs			 * Fire the CCB again to return it to the
98439212Sgibbs			 * caller.
98539212Sgibbs			 */
98639212Sgibbs			bcopy(done_ccb->ccb_h.saved_ccb_ptr,
98739212Sgibbs			      done_ccb, sizeof(union ccb));
98839212Sgibbs
98940318Sken			periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
99040318Sken
99139212Sgibbs			xpt_action(done_ccb);
99239212Sgibbs
99339212Sgibbs		}
99439212Sgibbs		break;
99539212Sgibbs	default:
99639212Sgibbs		bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
99739212Sgibbs		      sizeof(union ccb));
99839212Sgibbs
99940318Sken		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
100040318Sken
100139212Sgibbs		xpt_action(done_ccb);
100239212Sgibbs
100339212Sgibbs		break;
100439212Sgibbs	}
100539212Sgibbs
100639212Sgibbs	/* decrement the retry count */
100739212Sgibbs	if (done_ccb->ccb_h.retry_count > 0)
100839212Sgibbs		done_ccb->ccb_h.retry_count--;
100939212Sgibbs
101039212Sgibbs	qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path,
101139212Sgibbs				      /*relsim_flags*/relsim_flags,
101239212Sgibbs				      /*openings*/0,
101339212Sgibbs				      /*timeout*/timeout,
101439212Sgibbs				      /*getcount_only*/0);
101539212Sgibbs}
101639212Sgibbs
101739212Sgibbs/*
101839212Sgibbs * Generic error handler.  Peripheral drivers usually filter
101939212Sgibbs * out the errors that they handle in a unique mannor, then
102039212Sgibbs * call this function.
102139212Sgibbs */
102239212Sgibbsint
102339212Sgibbscam_periph_error(union ccb *ccb, cam_flags camflags,
102439212Sgibbs		 u_int32_t sense_flags, union ccb *save_ccb)
102539212Sgibbs{
102639212Sgibbs	cam_status status;
102739212Sgibbs	int	   frozen;
102839212Sgibbs	int	   sense;
102939212Sgibbs	int	   error;
103039212Sgibbs	int        openings;
103139212Sgibbs	int	   retry;
103239212Sgibbs	u_int32_t  relsim_flags;
103339212Sgibbs	u_int32_t  timeout;
103439212Sgibbs
103539212Sgibbs	status = ccb->ccb_h.status;
103639212Sgibbs	frozen = (status & CAM_DEV_QFRZN) != 0;
103739212Sgibbs	sense  = (status & CAM_AUTOSNS_VALID) != 0;
103839212Sgibbs	status &= CAM_STATUS_MASK;
103939212Sgibbs	relsim_flags = 0;
104039212Sgibbs
104139212Sgibbs
104239212Sgibbs	switch (status) {
104339212Sgibbs	case CAM_REQ_CMP:
104439212Sgibbs		/* decrement the number of retries */
104539212Sgibbs		retry = ccb->ccb_h.retry_count > 0;
104639212Sgibbs		if (retry)
104739212Sgibbs			ccb->ccb_h.retry_count--;
104839212Sgibbs		error = 0;
104939212Sgibbs		break;
105039212Sgibbs	case CAM_SCSI_STATUS_ERROR:
105139212Sgibbs
105239212Sgibbs		switch (ccb->csio.scsi_status) {
105339212Sgibbs		case SCSI_STATUS_OK:
105439212Sgibbs		case SCSI_STATUS_COND_MET:
105539212Sgibbs		case SCSI_STATUS_INTERMED:
105639212Sgibbs		case SCSI_STATUS_INTERMED_COND_MET:
105739212Sgibbs			error = 0;
105839212Sgibbs			break;
105939212Sgibbs		case SCSI_STATUS_CMD_TERMINATED:
106039212Sgibbs		case SCSI_STATUS_CHECK_COND:
106139212Sgibbs			if (sense != 0) {
106239212Sgibbs				struct scsi_sense_data *sense;
106339212Sgibbs				int    error_code, sense_key, asc, ascq;
106439212Sgibbs				struct cam_periph *periph;
106539212Sgibbs				scsi_sense_action err_action;
106639212Sgibbs				struct ccb_getdev cgd;
106739212Sgibbs
106839212Sgibbs				sense = &ccb->csio.sense_data;
106939212Sgibbs				scsi_extract_sense(sense, &error_code,
107039212Sgibbs						   &sense_key, &asc, &ascq);
107139212Sgibbs				periph = xpt_path_periph(ccb->ccb_h.path);
107239212Sgibbs
107339212Sgibbs				/*
107439212Sgibbs				 * Grab the inquiry data for this device.
107539212Sgibbs				 */
107639212Sgibbs				xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path,
107739212Sgibbs					      /*priority*/ 1);
107839212Sgibbs				cgd.ccb_h.func_code = XPT_GDEV_TYPE;
107939212Sgibbs				xpt_action((union ccb *)&cgd);
108039212Sgibbs
108139212Sgibbs				err_action = scsi_error_action(asc, ascq,
108239212Sgibbs							       &cgd.inq_data);
108339212Sgibbs
108439212Sgibbs				/*
108539212Sgibbs				 * Send a Test Unit Ready to the device.
108639212Sgibbs				 * If the 'many' flag is set, we send 120
108739212Sgibbs				 * test unit ready commands, one every half
108839212Sgibbs				 * second.  Otherwise, we just send one TUR.
108939212Sgibbs				 * We only want to do this if the retry
109039212Sgibbs				 * count has not been exhausted.
109139212Sgibbs				 */
109239212Sgibbs				if (((err_action & SS_MASK) == SS_TUR)
109339212Sgibbs				 && save_ccb != NULL
109439212Sgibbs				 && ccb->ccb_h.retry_count > 0) {
109539212Sgibbs
109640318Sken					/*
109740318Sken					 * Since error recovery is already
109840318Sken					 * in progress, don't attempt to
109940318Sken					 * process this error.  It is probably
110040318Sken					 * related to the error that caused
110140318Sken					 * the currently active error recovery
110240318Sken					 * action.  Also, we only have
110340318Sken					 * space for one saved CCB, so if we
110440318Sken					 * had two concurrent error recovery
110540318Sken					 * actions, we would end up
110640318Sken					 * over-writing one error recovery
110740318Sken					 * CCB with another one.
110840318Sken					 */
110940318Sken					if (periph->flags &
111040318Sken					    CAM_PERIPH_RECOVERY_INPROG) {
111140318Sken						error = ERESTART;
111240318Sken						break;
111340318Sken					}
111440318Sken
111540318Sken					periph->flags |=
111640318Sken						CAM_PERIPH_RECOVERY_INPROG;
111740318Sken
111839212Sgibbs					/* decrement the number of retries */
111939212Sgibbs					if ((err_action &
112039212Sgibbs					     SSQ_DECREMENT_COUNT) != 0) {
112139212Sgibbs						retry = 1;
112239212Sgibbs						ccb->ccb_h.retry_count--;
112339212Sgibbs					}
112439212Sgibbs
112539212Sgibbs					bcopy(ccb, save_ccb, sizeof(*save_ccb));
112639212Sgibbs
112739212Sgibbs					/*
112839212Sgibbs					 * We retry this one every half
112939212Sgibbs					 * second for a minute.  If the
113039212Sgibbs					 * device hasn't become ready in a
113139212Sgibbs					 * minute's time, it's unlikely to
113239212Sgibbs					 * ever become ready.  If the table
113339212Sgibbs					 * doesn't specify SSQ_MANY, we can
113439212Sgibbs					 * only try this once.  Oh well.
113539212Sgibbs					 */
113639212Sgibbs					if ((err_action & SSQ_MANY) != 0)
113739212Sgibbs						scsi_test_unit_ready(&ccb->csio,
113839212Sgibbs							       /*retries*/120,
113939212Sgibbs							       camperiphdone,
114039212Sgibbs						 	       MSG_SIMPLE_Q_TAG,
114139212Sgibbs							       SSD_FULL_SIZE,
114239212Sgibbs							       /*timeout*/5000);
114339212Sgibbs					else
114439212Sgibbs						scsi_test_unit_ready(&ccb->csio,
114539212Sgibbs							       /*retries*/1,
114639212Sgibbs							       camperiphdone,
114739212Sgibbs						 	       MSG_SIMPLE_Q_TAG,
114839212Sgibbs							       SSD_FULL_SIZE,
114939212Sgibbs							       /*timeout*/5000);
115039212Sgibbs
115139212Sgibbs					/* release the queue after .5 sec.  */
115239212Sgibbs					relsim_flags =
115339212Sgibbs						RELSIM_RELEASE_AFTER_TIMEOUT;
115439212Sgibbs					timeout = 500;
115539212Sgibbs					/*
115639212Sgibbs					 * Drop the priority to 0 so that
115739212Sgibbs					 * we are the first to execute.  Also
115839212Sgibbs					 * freeze the queue after this command
115939212Sgibbs					 * is sent so that we can restore the
116039212Sgibbs					 * old csio and have it queued in the
116139212Sgibbs					 * proper order before we let normal
116239212Sgibbs					 * transactions go to the drive.
116339212Sgibbs					 */
116439212Sgibbs					ccb->ccb_h.pinfo.priority = 0;
116539212Sgibbs					ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
116639212Sgibbs
116739212Sgibbs					/*
116839212Sgibbs					 * Save a pointer to the original
116939212Sgibbs					 * CCB in the new CCB.
117039212Sgibbs					 */
117139212Sgibbs					ccb->ccb_h.saved_ccb_ptr = save_ccb;
117239212Sgibbs
117339212Sgibbs					error = ERESTART;
117439212Sgibbs				}
117539212Sgibbs				/*
117639212Sgibbs				 * Send a start unit command to the device,
117739212Sgibbs				 * and then retry the command.  We only
117839212Sgibbs				 * want to do this if the retry count has
117939212Sgibbs				 * not been exhausted.  If the user
118039212Sgibbs				 * specified 0 retries, then we follow
118139212Sgibbs				 * their request and do not retry.
118239212Sgibbs				 */
118339212Sgibbs				else if (((err_action & SS_MASK) == SS_START)
118439212Sgibbs				      && save_ccb != NULL
118539212Sgibbs				      && ccb->ccb_h.retry_count > 0) {
118639212Sgibbs					int le;
118739212Sgibbs
118840318Sken					/*
118940318Sken					 * Only one error recovery action
119040318Sken					 * at a time.  See above.
119140318Sken					 */
119240318Sken					if (periph->flags &
119340318Sken					    CAM_PERIPH_RECOVERY_INPROG) {
119440318Sken						error = ERESTART;
119540318Sken						break;
119640318Sken					}
119740318Sken
119840318Sken					periph->flags |=
119940318Sken						CAM_PERIPH_RECOVERY_INPROG;
120040318Sken
120139212Sgibbs					/* decrement the number of retries */
120239212Sgibbs					retry = 1;
120339212Sgibbs					ccb->ccb_h.retry_count--;
120439212Sgibbs
120539212Sgibbs					/*
120639212Sgibbs					 * Check for removable media and
120739212Sgibbs					 * set load/eject flag
120839212Sgibbs					 * appropriately.
120939212Sgibbs					 */
121039212Sgibbs					if (SID_IS_REMOVABLE(&cgd.inq_data))
121139212Sgibbs						le = TRUE;
121239212Sgibbs					else
121339212Sgibbs						le = FALSE;
121439212Sgibbs
121539212Sgibbs					/*
121639212Sgibbs					 * Attempt to start the drive up.
121739212Sgibbs					 *
121839212Sgibbs					 * Save the current ccb so it can
121939212Sgibbs					 * be restored and retried once the
122039212Sgibbs					 * drive is started up.
122139212Sgibbs					 */
122239212Sgibbs					bcopy(ccb, save_ccb, sizeof(*save_ccb));
122339212Sgibbs
122439212Sgibbs					scsi_start_stop(&ccb->csio,
122539212Sgibbs							/*retries*/1,
122639212Sgibbs							camperiphdone,
122739212Sgibbs							MSG_SIMPLE_Q_TAG,
122839212Sgibbs							/*start*/TRUE,
122939212Sgibbs							/*load/eject*/le,
123039212Sgibbs							/*immediate*/FALSE,
123139212Sgibbs							SSD_FULL_SIZE,
123239212Sgibbs							/*timeout*/50000);
123339212Sgibbs					/*
123439212Sgibbs					 * Drop the priority to 0 so that
123539212Sgibbs					 * we are the first to execute.  Also
123639212Sgibbs					 * freeze the queue after this command
123739212Sgibbs					 * is sent so that we can restore the
123839212Sgibbs					 * old csio and have it queued in the
123939212Sgibbs					 * proper order before we let normal
124039212Sgibbs					 * transactions go to the drive.
124139212Sgibbs					 */
124239212Sgibbs					ccb->ccb_h.pinfo.priority = 0;
124339212Sgibbs					ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
124439212Sgibbs
124539212Sgibbs					/*
124639212Sgibbs					 * Save a pointer to the original
124739212Sgibbs					 * CCB in the new CCB.
124839212Sgibbs					 */
124939212Sgibbs					ccb->ccb_h.saved_ccb_ptr = save_ccb;
125039212Sgibbs
125139212Sgibbs					error = ERESTART;
125239212Sgibbs				} else if ((sense_flags & SF_RETRY_UA) != 0) {
125339212Sgibbs					/*
125439212Sgibbs					 * XXX KDM this is a *horrible*
125539212Sgibbs					 * hack.
125639212Sgibbs					 */
125739212Sgibbs					error = scsi_interpret_sense(ccb,
125839212Sgibbs								  sense_flags,
125939212Sgibbs								  &relsim_flags,
126039212Sgibbs								  &openings,
126139212Sgibbs								  &timeout,
126239212Sgibbs								  err_action);
126339212Sgibbs				}
126439212Sgibbs
126539212Sgibbs				/*
126639212Sgibbs				 * Theoretically, this code should send a
126739212Sgibbs				 * test unit ready to the given device, and
126839212Sgibbs				 * if it returns and error, send a start
126939212Sgibbs				 * unit command.  Since we don't yet have
127039212Sgibbs				 * the capability to do two-command error
127139212Sgibbs				 * recovery, just send a start unit.
127239212Sgibbs				 * XXX KDM fix this!
127339212Sgibbs				 */
127439212Sgibbs				else if (((err_action & SS_MASK) == SS_TURSTART)
127539212Sgibbs				      && save_ccb != NULL
127639212Sgibbs				      && ccb->ccb_h.retry_count > 0) {
127739212Sgibbs					int le;
127839212Sgibbs
127940318Sken					/*
128040318Sken					 * Only one error recovery action
128140318Sken					 * at a time.  See above.
128240318Sken					 */
128340318Sken					if (periph->flags &
128440318Sken					    CAM_PERIPH_RECOVERY_INPROG) {
128540318Sken						error = ERESTART;
128640318Sken						break;
128740318Sken					}
128840318Sken
128940318Sken					periph->flags |=
129040318Sken						CAM_PERIPH_RECOVERY_INPROG;
129140318Sken
129239212Sgibbs					/* decrement the number of retries */
129339212Sgibbs					retry = 1;
129439212Sgibbs					ccb->ccb_h.retry_count--;
129539212Sgibbs
129639212Sgibbs					/*
129739212Sgibbs					 * Check for removable media and
129839212Sgibbs					 * set load/eject flag
129939212Sgibbs					 * appropriately.
130039212Sgibbs					 */
130139212Sgibbs					if (SID_IS_REMOVABLE(&cgd.inq_data))
130239212Sgibbs						le = TRUE;
130339212Sgibbs					else
130439212Sgibbs						le = FALSE;
130539212Sgibbs
130639212Sgibbs					/*
130739212Sgibbs					 * Attempt to start the drive up.
130839212Sgibbs					 *
130939212Sgibbs					 * Save the current ccb so it can
131039212Sgibbs					 * be restored and retried once the
131139212Sgibbs					 * drive is started up.
131239212Sgibbs					 */
131339212Sgibbs					bcopy(ccb, save_ccb, sizeof(*save_ccb));
131439212Sgibbs
131539212Sgibbs					scsi_start_stop(&ccb->csio,
131639212Sgibbs							/*retries*/1,
131739212Sgibbs							camperiphdone,
131839212Sgibbs							MSG_SIMPLE_Q_TAG,
131939212Sgibbs							/*start*/TRUE,
132039212Sgibbs							/*load/eject*/le,
132139212Sgibbs							/*immediate*/FALSE,
132239212Sgibbs							SSD_FULL_SIZE,
132339212Sgibbs							/*timeout*/50000);
132439212Sgibbs
132539212Sgibbs					/* release the queue after .5 sec.  */
132639212Sgibbs					relsim_flags =
132739212Sgibbs						RELSIM_RELEASE_AFTER_TIMEOUT;
132839212Sgibbs					timeout = 500;
132939212Sgibbs					/*
133039212Sgibbs					 * Drop the priority to 0 so that
133139212Sgibbs					 * we are the first to execute.  Also
133239212Sgibbs					 * freeze the queue after this command
133339212Sgibbs					 * is sent so that we can restore the
133439212Sgibbs					 * old csio and have it queued in the
133539212Sgibbs					 * proper order before we let normal
133639212Sgibbs					 * transactions go to the drive.
133739212Sgibbs					 */
133839212Sgibbs					ccb->ccb_h.pinfo.priority = 0;
133939212Sgibbs					ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
134039212Sgibbs
134139212Sgibbs					/*
134239212Sgibbs					 * Save a pointer to the original
134339212Sgibbs					 * CCB in the new CCB.
134439212Sgibbs					 */
134539212Sgibbs					ccb->ccb_h.saved_ccb_ptr = save_ccb;
134639212Sgibbs
134739212Sgibbs					error = ERESTART;
134839212Sgibbs				} else {
134939212Sgibbs					error = scsi_interpret_sense(ccb,
135039212Sgibbs								  sense_flags,
135139212Sgibbs								  &relsim_flags,
135239212Sgibbs								  &openings,
135339212Sgibbs								  &timeout,
135439212Sgibbs								  err_action);
135539212Sgibbs				}
135639212Sgibbs			} else if (ccb->csio.scsi_status ==
135739212Sgibbs				   SCSI_STATUS_CHECK_COND) {
135839212Sgibbs				/* no point in decrementing the retry count */
135939212Sgibbs				panic("cam_periph_error: scsi status of "
136039212Sgibbs				      "CHECK COND returned but no sense "
136139212Sgibbs				      "information is availible.  "
136239212Sgibbs				      "Controller should have returned "
136339212Sgibbs				      "CAM_AUTOSENSE_FAILED");
136439212Sgibbs				/* NOTREACHED */
136539212Sgibbs				error = EIO;
136639212Sgibbs			} else if (ccb->ccb_h.retry_count > 0) {
136739212Sgibbs				/*
136839212Sgibbs				 * XXX KDM shouldn't there be a better
136939212Sgibbs				 * argument to return??
137039212Sgibbs				 */
137139212Sgibbs				error = EIO;
137239212Sgibbs			} else {
137339212Sgibbs				/* decrement the number of retries */
137439212Sgibbs				retry = ccb->ccb_h.retry_count > 0;
137539212Sgibbs				if (retry)
137639212Sgibbs					ccb->ccb_h.retry_count--;
137739212Sgibbs				/*
137839212Sgibbs				 * If it was aborted with no
137939212Sgibbs				 * clue as to the reason, just
138039212Sgibbs				 * retry it again.
138139212Sgibbs				 */
138239212Sgibbs				error = ERESTART;
138339212Sgibbs			}
138439212Sgibbs			break;
138539212Sgibbs		case SCSI_STATUS_QUEUE_FULL:
138639212Sgibbs		{
138739212Sgibbs			/* no decrement */
138839212Sgibbs			struct ccb_getdev cgd;
138939212Sgibbs
139039212Sgibbs			/*
139139212Sgibbs			 * First off, find out what the current
139239212Sgibbs			 * transaction counts are.
139339212Sgibbs			 */
139439212Sgibbs			xpt_setup_ccb(&cgd.ccb_h,
139539212Sgibbs				      ccb->ccb_h.path,
139639212Sgibbs				      /*priority*/1);
139739212Sgibbs			cgd.ccb_h.func_code = XPT_GDEV_TYPE;
139839212Sgibbs			xpt_action((union ccb *)&cgd);
139939212Sgibbs
140039212Sgibbs			/*
140139212Sgibbs			 * If we were the only transaction active, treat
140239212Sgibbs			 * the QUEUE FULL as if it were a BUSY condition.
140339212Sgibbs			 */
140439212Sgibbs			if (cgd.dev_active != 0) {
140539212Sgibbs				/*
140639212Sgibbs			 	 * Reduce the number of openings to
140739212Sgibbs				 * be 1 less than the amount it took
140839212Sgibbs				 * to get a queue full bounded by the
140939212Sgibbs				 * minimum allowed tag count for this
141039212Sgibbs				 * device.
141139212Sgibbs			 	 */
141239212Sgibbs				openings = cgd.dev_active;
141339212Sgibbs				if (openings < cgd.mintags)
141439212Sgibbs					openings = cgd.mintags;
141539212Sgibbs				if (openings < cgd.dev_active+cgd.dev_openings)
141639212Sgibbs					relsim_flags = RELSIM_ADJUST_OPENINGS;
141739212Sgibbs				else {
141839212Sgibbs					/*
141939212Sgibbs					 * Some devices report queue full for
142039212Sgibbs					 * temporary resource shortages.  For
142139212Sgibbs					 * this reason, we allow a minimum
142239212Sgibbs					 * tag count to be entered via a
142339212Sgibbs					 * quirk entry to prevent the queue
142439212Sgibbs					 * count on these devices from falling
142539212Sgibbs					 * to a pessimisticly low value.  We
142639212Sgibbs					 * still wait for the next successful
142739212Sgibbs					 * completion, however, before queueing
142839212Sgibbs					 * more transactions to the device.
142939212Sgibbs					 */
143039212Sgibbs					relsim_flags =
143139212Sgibbs					    RELSIM_RELEASE_AFTER_CMDCMPLT;
143239212Sgibbs				}
143339212Sgibbs				timeout = 0;
143439212Sgibbs				error = ERESTART;
143539212Sgibbs				break;
143639212Sgibbs			}
143739212Sgibbs			/* FALLTHROUGH */
143839212Sgibbs		}
143939212Sgibbs		case SCSI_STATUS_BUSY:
144039212Sgibbs			/*
144139212Sgibbs			 * Restart the queue after either another
144239212Sgibbs			 * command completes or a 1 second timeout.
144339212Sgibbs			 */
144439212Sgibbs			/*
144539212Sgibbs			 * XXX KDM ask JTG about this again, do we need to
144639212Sgibbs			 * be looking at the retry count here?
144739212Sgibbs			 */
144839212Sgibbs			error = ERESTART;
144939212Sgibbs			relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT
145039212Sgibbs				     | RELSIM_RELEASE_AFTER_CMDCMPLT;
145139212Sgibbs			timeout = 1000;
145239212Sgibbs			break;
145339212Sgibbs		case SCSI_STATUS_RESERV_CONFLICT:
145439212Sgibbs			error = EIO;
145539212Sgibbs			break;
145639212Sgibbs		default:
145739212Sgibbs			error = EIO;
145839212Sgibbs			break;
145939212Sgibbs		}
146039212Sgibbs		break;
146139212Sgibbs	case CAM_REQ_CMP_ERR:
146239212Sgibbs	case CAM_AUTOSENSE_FAIL:
146339212Sgibbs	case CAM_CMD_TIMEOUT:
146439212Sgibbs	case CAM_UNEXP_BUSFREE:
146539212Sgibbs	case CAM_UNCOR_PARITY:
146639212Sgibbs	case CAM_DATA_RUN_ERR:
146739212Sgibbs		/* decrement the number of retries */
146839212Sgibbs		retry = ccb->ccb_h.retry_count > 0;
146939212Sgibbs		if (retry) {
147039212Sgibbs			ccb->ccb_h.retry_count--;
147139212Sgibbs			error = ERESTART;
147239212Sgibbs		} else {
147339212Sgibbs			error = EIO;
147439212Sgibbs		}
147539212Sgibbs		break;
147639212Sgibbs	case CAM_UA_ABORT:
147739212Sgibbs	case CAM_UA_TERMIO:
147839212Sgibbs	case CAM_MSG_REJECT_REC:
147939212Sgibbs		/* XXX Don't know that these are correct */
148039212Sgibbs		error = EIO;
148139212Sgibbs		break;
148239212Sgibbs	case CAM_SEL_TIMEOUT:
148339212Sgibbs	{
148439513Sgibbs		/*
148539513Sgibbs		 * XXX
148639513Sgibbs		 * A single selection timeout should not be enough
148739513Sgibbs		 * to invalidate a device.  We should retry for multiple
148839513Sgibbs		 * seconds assuming this isn't a probe.  We'll probably
148939513Sgibbs		 * need a special flag for that.
149039513Sgibbs		 */
149139513Sgibbs#if 0
149239212Sgibbs		struct cam_path *newpath;
149339212Sgibbs
149439212Sgibbs		/* Should we do more if we can't create the path?? */
149539212Sgibbs		if (xpt_create_path(&newpath, xpt_path_periph(ccb->ccb_h.path),
149639212Sgibbs				    xpt_path_path_id(ccb->ccb_h.path),
149739212Sgibbs				    xpt_path_target_id(ccb->ccb_h.path),
149839212Sgibbs				    CAM_LUN_WILDCARD) != CAM_REQ_CMP)
149939212Sgibbs			break;
150039212Sgibbs		/*
150139212Sgibbs		 * Let peripheral drivers know that this device has gone
150239212Sgibbs		 * away.
150339212Sgibbs		 */
150439212Sgibbs		xpt_async(AC_LOST_DEVICE, newpath, NULL);
150539212Sgibbs		xpt_free_path(newpath);
150639513Sgibbs#endif
150739513Sgibbs		error = ENXIO;
150839212Sgibbs		break;
150939212Sgibbs	}
151039212Sgibbs	case CAM_REQ_INVALID:
151139212Sgibbs	case CAM_PATH_INVALID:
151239212Sgibbs	case CAM_DEV_NOT_THERE:
151339212Sgibbs	case CAM_NO_HBA:
151439212Sgibbs	case CAM_PROVIDE_FAIL:
151539212Sgibbs	case CAM_REQ_TOO_BIG:
151639212Sgibbs		error = EINVAL;
151739212Sgibbs		break;
151839212Sgibbs	case CAM_SCSI_BUS_RESET:
151939212Sgibbs	case CAM_BDR_SENT:
152039212Sgibbs	case CAM_REQUEUE_REQ:
152139212Sgibbs		/* Unconditional requeue, dammit */
152239212Sgibbs		error = ERESTART;
152339212Sgibbs		break;
152439212Sgibbs	case CAM_RESRC_UNAVAIL:
152539212Sgibbs	case CAM_BUSY:
152639212Sgibbs		/* timeout??? */
152739212Sgibbs	default:
152839212Sgibbs		/* decrement the number of retries */
152939212Sgibbs		retry = ccb->ccb_h.retry_count > 0;
153039212Sgibbs		if (retry) {
153139212Sgibbs			ccb->ccb_h.retry_count--;
153239212Sgibbs			error = ERESTART;
153339212Sgibbs		} else {
153439212Sgibbs			/* Check the sense codes */
153539212Sgibbs			error = EIO;
153639212Sgibbs		}
153739212Sgibbs		break;
153839212Sgibbs	}
153939212Sgibbs
154039212Sgibbs	/* Attempt a retry */
154139212Sgibbs	if (error == ERESTART || error == 0) {
154239212Sgibbs		if (frozen != 0)
154339212Sgibbs			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
154439212Sgibbs
154539212Sgibbs		if (error == ERESTART)
154639212Sgibbs			xpt_action(ccb);
154739212Sgibbs
154839212Sgibbs		if (frozen != 0) {
154939212Sgibbs			cam_release_devq(ccb->ccb_h.path,
155039212Sgibbs					 relsim_flags,
155139212Sgibbs					 openings,
155239212Sgibbs					 timeout,
155339212Sgibbs					 /*getcount_only*/0);
155439212Sgibbs		}
155539212Sgibbs	}
155639212Sgibbs
155739212Sgibbs
155839212Sgibbs	return (error);
155939212Sgibbs}
1560