scsi_low.c revision 92770
167468Snon/*	$FreeBSD: head/sys/cam/scsi/scsi_low.c 92770 2002-03-20 08:56:31Z alfred $	*/
279697Snon/*	$NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $	*/
367468Snon/*	$NetBSD$	*/
467468Snon
567468Snon#define	SCSI_LOW_STATICS
679697Snon#define	SCSI_LOW_DEBUG
779697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE
879697Snon#define	SCSI_LOW_START_UP_CHECK
979697Snon
1079697Snon/* #define	SCSI_LOW_INFO_DETAIL */
1179697Snon/* #define	SCSI_LOW_QCLEAR_AFTER_CA */
1279697Snon/* #define	SCSI_LOW_FLAGS_QUIRKS_OK */
1379697Snon
1467468Snon#ifdef __NetBSD__
1567468Snon#define	SCSI_LOW_TARGET_OPEN
1679697Snon#endif	/* __NetBSD__ */
1767468Snon
1879697Snon#ifdef	__FreeBSD__
1979697Snon#define	SCSI_LOW_FLAGS_QUIRKS_OK
2079697Snon#endif	/* __FreeBSD__ */
2179697Snon
2267468Snon/*
2367468Snon * [NetBSD for NEC PC-98 series]
2479697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2567468Snon *	NetBSD/pc98 porting staff. All rights reserved.
2679697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2767468Snon *	Naofumi HONDA. All rights reserved.
2879697Snon *
2979697Snon * [Ported for FreeBSD CAM]
3079697Snon *  Copyright (c) 2000, 2001
3179697Snon *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
3279697Snon *      All rights reserved.
3367468Snon *
3467468Snon *  Redistribution and use in source and binary forms, with or without
3567468Snon *  modification, are permitted provided that the following conditions
3667468Snon *  are met:
3767468Snon *  1. Redistributions of source code must retain the above copyright
3867468Snon *     notice, this list of conditions and the following disclaimer.
3967468Snon *  2. Redistributions in binary form must reproduce the above copyright
4067468Snon *     notice, this list of conditions and the following disclaimer in the
4167468Snon *     documentation and/or other materials provided with the distribution.
4267468Snon *  3. The name of the author may not be used to endorse or promote products
4367468Snon *     derived from this software without specific prior written permission.
4467468Snon *
4567468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4667468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4767468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4867468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
4967468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5067468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5167468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5267468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
5367468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
5467468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5567468Snon * POSSIBILITY OF SUCH DAMAGE.
5667468Snon */
5767468Snon
5867468Snon/* <On the nexus establishment>
5967468Snon * When our host is reselected,
6067468Snon * nexus establish processes are little complicated.
6167468Snon * Normal steps are followings:
6279697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
6379697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
6479697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
6567468Snon */
6667468Snon#include "opt_ddb.h"
6767468Snon
6867468Snon#include <sys/param.h>
6967468Snon#include <sys/systm.h>
7067468Snon#include <sys/kernel.h>
7179697Snon
7273025Snon#ifdef __FreeBSD__
7373025Snon#if __FreeBSD_version >= 500001
7467468Snon#include <sys/bio.h>
7579697Snon#else
7679697Snon#include <machine/clock.h>
7773025Snon#endif
7869979Snon#include <sys/devicestat.h>
7979697Snon#endif	/* __FreeBSD__ */
8079697Snon
8167468Snon#include <sys/buf.h>
8267468Snon#include <sys/queue.h>
8367468Snon#include <sys/malloc.h>
8467468Snon#include <sys/errno.h>
8567468Snon
8679697Snon#ifdef	__NetBSD__
8779697Snon#include <sys/device.h>
8867468Snon#include <vm/vm.h>
8967468Snon
9067468Snon#include <machine/bus.h>
9167468Snon#include <machine/intr.h>
9267468Snon#include <machine/dvcfg.h>
9367468Snon
9467468Snon#include <dev/cons.h>
9567468Snon
9667468Snon#include <dev/scsipi/scsipi_all.h>
9767468Snon#include <dev/scsipi/scsipiconf.h>
9867468Snon#include <dev/scsipi/scsipi_disk.h>
9967468Snon#include <dev/scsipi/scsi_all.h>
10067468Snon#include <dev/scsipi/scsiconf.h>
10179697Snon#include <sys/scsiio.h>
10267468Snon
10367468Snon#include <i386/Cbus/dev/scsi_low.h>
10479697Snon#endif	/* __NetBSD__ */
10579697Snon
10667468Snon#ifdef __FreeBSD__
10767468Snon#include <cam/cam.h>
10867468Snon#include <cam/cam_ccb.h>
10967468Snon#include <cam/cam_sim.h>
11067468Snon#include <cam/cam_debug.h>
11167468Snon#include <cam/cam_periph.h>
11267468Snon
11367468Snon#include <cam/scsi/scsi_all.h>
11473025Snon#include <cam/scsi/scsi_message.h>
11567468Snon
11667468Snon#include <cam/scsi/scsi_low.h>
11767468Snon
11867468Snon#include <sys/cons.h>
11979697Snon#endif	/* __FreeBSD__ */
12067468Snon
12179697Snon/**************************************************************
12279697Snon * Constants
12379697Snon **************************************************************/
12479697Snon#define	SCSI_LOW_POLL_HZ	1000
12567468Snon
12679697Snon/* functions return values */
12779697Snon#define	SCSI_LOW_START_NO_QTAG	0
12879697Snon#define	SCSI_LOW_START_QTAG	1
12979697Snon
13067468Snon#define	SCSI_LOW_DONE_COMPLETE	0
13167468Snon#define	SCSI_LOW_DONE_RETRY	1
13267468Snon
13379697Snon/* internal disk flags */
13479697Snon#define	SCSI_LOW_DISK_DISC	0x00000001
13579697Snon#define	SCSI_LOW_DISK_QTAG	0x00000002
13679697Snon#define	SCSI_LOW_DISK_LINK	0x00000004
13779697Snon#define	SCSI_LOW_DISK_PARITY	0x00000008
13879697Snon#define	SCSI_LOW_DISK_SYNC	0x00010000
13979697Snon#define	SCSI_LOW_DISK_WIDE_16	0x00020000
14079697Snon#define	SCSI_LOW_DISK_WIDE_32	0x00040000
14179697Snon#define	SCSI_LOW_DISK_WIDE	(SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
14279697Snon#define	SCSI_LOW_DISK_LFLAGS	0x0000ffff
14379697Snon#define	SCSI_LOW_DISK_TFLAGS	0xffff0000
14479697Snon
14579697Snon/**************************************************************
14679697Snon * Declarations
14779697Snon **************************************************************/
14892770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *);
14992770Salfredstatic void scsi_low_engage(void *);
15092770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t);
15192770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *);
15292770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *);
15392770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *);
15492770Salfredstatic void scsi_low_twiddle_wait(void);
15592770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int);
15692770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int);
15792770Salfredstatic void scsi_low_calcf_lun(struct lun_info *);
15892770Salfredstatic void scsi_low_calcf_target(struct targ_info *);
15992770Salfredstatic void scsi_low_calcf_show(struct lun_info *);
16092770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int);
16192770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int);
16292770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int);
16392770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int);
16492770Salfredstatic void scsi_low_start(struct scsi_low_softc *);
16592770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *);
16667468Snon
16792770Salfredstatic int scsi_low_alloc_qtag(struct slccb *);
16892770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *);
16992770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int);
17092770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int);
17192770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *);
17292770Salfredstatic void scsi_low_timeout(void *);
17392770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *);
17479697Snon#ifdef	SCSI_LOW_START_UP_CHECK
17592770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *);
17679697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
17792770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *);
17892770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int);
17979697Snon
18079697Snonint scsi_low_version_major = 2;
18179697Snonint scsi_low_version_minor = 17;
18279697Snon
18379697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
18479697Snon
18579697Snon/**************************************************************
18679697Snon * Debug, Run test and Statics
18779697Snon **************************************************************/
18879697Snon#ifdef	SCSI_LOW_INFO_DETAIL
18979697Snon#define	SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
19079697Snon#else	/* !SCSI_LOW_INFO_DETAIL */
19179697Snon#define	SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s))
19279697Snon#endif	/* !SCSI_LOW_INFO_DETAIL */
19379697Snon
19467468Snon#ifdef	SCSI_LOW_STATICS
19589113Smsmithstatic struct scsi_low_statics {
19667468Snon	int nexus_win;
19767468Snon	int nexus_fail;
19867468Snon	int nexus_disconnected;
19967468Snon	int nexus_reselected;
20067468Snon	int nexus_conflict;
20167468Snon} scsi_low_statics;
20267468Snon#endif	/* SCSI_LOW_STATICS */
20379697Snon
20479697Snon#ifdef	SCSI_LOW_DEBUG
20579697Snon#define	SCSI_LOW_DEBUG_DONE	0x00001
20679697Snon#define	SCSI_LOW_DEBUG_DISC	0x00002
20779697Snon#define	SCSI_LOW_DEBUG_SENSE	0x00004
20879697Snon#define	SCSI_LOW_DEBUG_CALCF	0x00008
20979697Snon#define	SCSI_LOW_DEBUG_ACTION	0x10000
21079697Snonint scsi_low_debug = 0;
21179697Snon
21279697Snon#define	SCSI_LOW_MAX_ATTEN_CHECK	32
21379697Snon#define	SCSI_LOW_ATTEN_CHECK	0x0001
21479697Snon#define	SCSI_LOW_CMDLNK_CHECK	0x0002
21579697Snon#define	SCSI_LOW_ABORT_CHECK	0x0004
21679697Snon#define	SCSI_LOW_NEXUS_CHECK	0x0008
21779697Snonint scsi_low_test = 0;
21879697Snonint scsi_low_test_id = 0;
21979697Snon
22092770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *);
22192770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *);
22292770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int);
22379697Snon#define	SCSI_LOW_DEBUG_TEST_GO(fl, id) \
22479697Snon	((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
22579697Snon#define	SCSI_LOW_DEBUG_GO(fl, id) \
22679697Snon	((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
22779697Snon#endif	/* SCSI_LOW_DEBUG */
22879697Snon
22967468Snon/**************************************************************
23079697Snon * CCB
23179697Snon **************************************************************/
23279697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
23379697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain)
23479697Snon
23579697Snon/**************************************************************
23679697Snon * Inline functions
23779697Snon **************************************************************/
23879697Snon#define	SCSI_LOW_INLINE	static __inline
23992770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *);
24092770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *);
24192770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int);
24292770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *);
24392770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *);
24492770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *);
24592770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *);
24679697Snon
24779697SnonSCSI_LOW_INLINE void
24879697Snonscsi_low_activate_qtag(cb)
24979697Snon	struct slccb *cb;
25079697Snon{
25179697Snon	struct lun_info *li = cb->li;
25279697Snon
25379697Snon	if (cb->ccb_tag != SCSI_LOW_UNKTAG)
25479697Snon		return;
25579697Snon
25679697Snon	li->li_nqio ++;
25779697Snon	cb->ccb_tag = cb->ccb_otag;
25879697Snon}
25979697Snon
26079697SnonSCSI_LOW_INLINE void
26179697Snonscsi_low_deactivate_qtag(cb)
26279697Snon	struct slccb *cb;
26379697Snon{
26479697Snon	struct lun_info *li = cb->li;
26579697Snon
26679697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
26779697Snon		return;
26879697Snon
26979697Snon	li->li_nqio --;
27079697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
27179697Snon}
27279697Snon
27379697SnonSCSI_LOW_INLINE void
27479697Snonscsi_low_ccb_message_exec(slp, cb)
27579697Snon	struct scsi_low_softc *slp;
27679697Snon	struct slccb *cb;
27779697Snon{
27879697Snon
27979697Snon	scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
28079697Snon	cb->ccb_msgoutflag = 0;
28179697Snon}
28279697Snon
28379697SnonSCSI_LOW_INLINE void
28479697Snonscsi_low_ccb_message_assert(cb, msg)
28579697Snon	struct slccb *cb;
28679697Snon	u_int msg;
28779697Snon{
28879697Snon
28979697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
29079697Snon}
29179697Snon
29279697SnonSCSI_LOW_INLINE void
29379697Snonscsi_low_ccb_message_retry(cb)
29479697Snon	struct slccb *cb;
29579697Snon{
29679697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
29779697Snon}
29879697Snon
29979697SnonSCSI_LOW_INLINE void
30079697Snonscsi_low_ccb_message_clear(cb)
30179697Snon	struct slccb *cb;
30279697Snon{
30379697Snon	cb->ccb_msgoutflag = 0;
30479697Snon}
30579697Snon
30679697SnonSCSI_LOW_INLINE void
30779697Snonscsi_low_init_msgsys(slp, ti)
30879697Snon	struct scsi_low_softc *slp;
30979697Snon	struct targ_info *ti;
31079697Snon{
31179697Snon
31279697Snon	ti->ti_msginptr = 0;
31379697Snon	ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
31479697Snon	SCSI_LOW_DEASSERT_ATN(slp);
31579697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
31679697Snon}
31779697Snon
31879697Snon/*=============================================================
31979697Snon * START OF OS switch  (All OS depend fucntions should be here)
32079697Snon =============================================================*/
32179697Snon/* common os depend utitlities */
32279697Snon#define	SCSI_LOW_CMD_RESIDUAL_CHK	0x0001
32379697Snon#define	SCSI_LOW_CMD_ORDERED_QTAG	0x0002
32479697Snon#define	SCSI_LOW_CMD_ABORT_WARNING	0x0004
32579697Snon
32679697Snonstatic u_int8_t scsi_low_cmd_flags[256] = {
32779697Snon/*	0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
32879697Snon/*0*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
32979697Snon/*1*/	0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
33079697Snon/*2*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
33179697Snon/*3*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
33279697Snon};
33379697Snon
33479697Snonstruct scsi_low_error_code {
33579697Snon	int error_bits;
33679697Snon	int error_code;
33779697Snon};
33879697Snon
33992770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *);
34092770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *);
34179697Snon
34279697Snonstatic struct slccb *
34379697Snonscsi_low_find_ccb(slp, target, lun, osdep)
34479697Snon	struct scsi_low_softc *slp;
34579697Snon	u_int target, lun;
34679697Snon	void *osdep;
34779697Snon{
34879697Snon	struct targ_info *ti;
34979697Snon	struct lun_info *li;
35079697Snon	struct slccb *cb;
35179697Snon
35279697Snon	ti = slp->sl_ti[target];
35379697Snon	li = scsi_low_alloc_li(ti, lun, 0);
35479697Snon	if (li == NULL)
35579697Snon		return NULL;
35679697Snon
35779697Snon	if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
35879697Snon		return cb;
35979697Snon
36079697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
36179697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
36279697Snon	{
36379697Snon		if (cb->osdep == osdep)
36479697Snon			return cb;
36579697Snon	}
36679697Snon
36779697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL;
36879697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
36979697Snon	{
37079697Snon		if (cb->osdep == osdep)
37179697Snon			return cb;
37279697Snon	}
37379697Snon	return NULL;
37479697Snon}
37579697Snon
37679697Snonstatic int
37779697Snonscsi_low_translate_error_code(cb, tp)
37879697Snon	struct slccb *cb;
37979697Snon	struct scsi_low_error_code *tp;
38079697Snon{
38179697Snon
38279697Snon	if (cb->ccb_error == 0)
38379697Snon		return tp->error_code;
38479697Snon
38579697Snon	for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
38679697Snon		;
38779697Snon	return tp->error_code;
38879697Snon}
38979697Snon
39079697Snon#ifdef SCSI_LOW_INTERFACE_XS
39179697Snon/**************************************************************
39279697Snon * SCSI INTERFACE (XS)
39379697Snon **************************************************************/
39479697Snon#define	SCSI_LOW_MINPHYS		0x10000
39579697Snon#define	SCSI_LOW_MALLOC(size)		malloc((size), M_DEVBUF, M_NOWAIT)
39679697Snon#define	SCSI_LOW_FREE(pt)		free((pt), M_DEVBUF)
39779697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb((flags))
39879697Snon#define	SCSI_LOW_XS_POLL_HZ		1000
39979697Snon
40092770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *);
40192770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *);
40279697Snon#ifdef	SCSI_LOW_TARGET_OPEN
40392770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *);
40479697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
40592770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *);
40692770Salfredstatic int scsi_low_enable_xs(void *, int);
40792770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *);
40879697Snon
40992770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *);
41092770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *);
41192770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *);
41292770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *);
41392770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *);
41492770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int);
41592770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int);
41692770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int);
41779697Snon
41879697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = {
41979697Snon	scsi_low_attach_xs,
42079697Snon	scsi_low_world_start_xs,
42179697Snon	scsi_low_dettach_xs,
42279697Snon	scsi_low_ccb_setup_xs,
42379697Snon	scsi_low_done_xs,
42479697Snon	scsi_low_timeout_xs
42579697Snon};
42679697Snon
42779697Snonstruct scsipi_device scsi_low_dev = {
42879697Snon	NULL,	/* Use default error handler */
42979697Snon	NULL,	/* have a queue, served by this */
43079697Snon	NULL,	/* have no async handler */
43179697Snon	NULL,	/* Use default 'done' routine */
43279697Snon};
43379697Snon
43479697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = {
43579697Snon	{0,		XS_NOERROR},
43679697Snon	{SENSEIO,	XS_SENSE},
43779697Snon	{BUSYERR,	XS_BUSY	},
43879697Snon	{SELTIMEOUTIO,	XS_SELTIMEOUT},
43979697Snon	{TIMEOUTIO,	XS_TIMEOUT},
44079697Snon	{-1,		XS_DRIVER_STUFFUP}
44179697Snon};
44279697Snon
44379697Snonstatic int
44479697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p)
44579697Snon	struct scsipi_link *link;
44679697Snon	u_long cmd;
44779697Snon	caddr_t addr;
44879697Snon	int flag;
44979697Snon	struct proc *p;
45079697Snon{
45179697Snon	struct scsi_low_softc *slp;
45279697Snon	int s, error = ENOTTY;
45379697Snon
45479697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
45579697Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
45679697Snon		return ENXIO;
45779697Snon
45879697Snon	if (cmd == SCBUSIORESET)
45979697Snon	{
46079697Snon		s = SCSI_LOW_SPLSCSI();
46179697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
46279697Snon		splx(s);
46379697Snon		error = 0;
46479697Snon	}
46579697Snon	else if (slp->sl_funcs->scsi_low_ioctl != 0)
46679697Snon	{
46779697Snon		error = (*slp->sl_funcs->scsi_low_ioctl)
46879697Snon				(slp, cmd, addr, flag, p);
46979697Snon	}
47079697Snon
47179697Snon	return error;
47279697Snon}
47379697Snon
47479697Snonstatic int
47579697Snonscsi_low_enable_xs(arg, enable)
47679697Snon	void *arg;
47779697Snon	int enable;
47879697Snon{
47979697Snon	struct scsi_low_softc *slp = arg;
48079697Snon
48179697Snon	if (enable != 0)
48279697Snon	{
48379697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0)
48479697Snon			return ENXIO;
48579697Snon	}
48679697Snon	else
48779697Snon	{
48879697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0 ||
48979697Snon		    (slp->sl_flags & HW_POWERCTRL) == 0)
49079697Snon			return 0;
49179697Snon
49279697Snon		slp->sl_flags |= HW_POWDOWN;
49379697Snon		if (slp->sl_funcs->scsi_low_power != NULL)
49479697Snon		{
49579697Snon			(*slp->sl_funcs->scsi_low_power)
49679697Snon					(slp, SCSI_LOW_POWDOWN);
49779697Snon		}
49879697Snon	}
49979697Snon	return 0;
50079697Snon}
50179697Snon
50279697Snonstatic void
50379697Snonscsi_low_scsi_minphys_xs(bp)
50479697Snon	struct buf *bp;
50579697Snon{
50679697Snon
50779697Snon	if (bp->b_bcount > SCSI_LOW_MINPHYS)
50879697Snon		bp->b_bcount = SCSI_LOW_MINPHYS;
50979697Snon	minphys(bp);
51079697Snon}
51179697Snon
51279697Snonstatic int
51379697Snonscsi_low_poll_xs(slp, cb)
51479697Snon	struct scsi_low_softc *slp;
51579697Snon	struct slccb *cb;
51679697Snon{
51779697Snon	struct scsipi_xfer *xs = cb->osdep;
51879697Snon	int tcount;
51979697Snon
52079697Snon	cb->ccb_flags |= CCB_NOSDONE;
52179697Snon	tcount = 0;
52279697Snon
52379697Snon	while (slp->sl_nio > 0)
52479697Snon	{
52579697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ);
52679697Snon
52779697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
52879697Snon
52979697Snon		if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
53079697Snon		{
53179697Snon			cb->ccb_flags |= CCB_NORETRY;
53279697Snon			cb->ccb_error |= FATALIO;
53379697Snon			(void) scsi_low_revoke_ccb(slp, cb, 1);
53479697Snon			printf("%s: hardware inactive in poll mode\n",
53579697Snon				slp->sl_xname);
53679697Snon		}
53779697Snon
53879697Snon		if ((xs->flags & ITSDONE) != 0)
53979697Snon			break;
54079697Snon
54179697Snon		if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
54279697Snon			continue;
54379697Snon
54479697Snon		tcount = 0;
54579697Snon		scsi_low_timeout_check(slp);
54679697Snon	}
54779697Snon
54879697Snon	xs->flags |= ITSDONE;
54979697Snon	scsipi_done(xs);
55079697Snon	return COMPLETE;
55179697Snon}
55279697Snon
55379697Snonstatic int
55479697Snonscsi_low_scsi_cmd_xs(xs)
55579697Snon	struct scsipi_xfer *xs;
55679697Snon{
55779697Snon	struct scsipi_link *splp = xs->sc_link;
55879697Snon	struct scsi_low_softc *slp = splp->adapter_softc;
55979697Snon	struct targ_info *ti;
56079697Snon	struct lun_info *li;
56179697Snon	struct slccb *cb;
56279697Snon	int s, targ, lun, flags, rv;
56379697Snon
56479697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL)
56579697Snon		return TRY_AGAIN_LATER;
56679697Snon
56779697Snon	targ = splp->scsipi_scsi.target,
56879697Snon	lun = splp->scsipi_scsi.lun;
56979697Snon	ti = slp->sl_ti[targ];
57079697Snon
57179697Snon	cb->osdep = xs;
57279697Snon	cb->bp = xs->bp;
57379697Snon
57479697Snon	if ((xs->flags & SCSI_POLL) == 0)
57579697Snon		flags = CCB_AUTOSENSE;
57679697Snon	else
57779697Snon		flags = CCB_AUTOSENSE | CCB_POLLED;
57879697Snon
57979697Snon
58079697Snon	s = SCSI_LOW_SPLSCSI();
58179697Snon	li = scsi_low_alloc_li(ti, lun, 1);
58279697Snon	if ((u_int) splp->quirks != li->li_sloi.sloi_quirks)
58379697Snon	{
58479697Snon		scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks);
58579697Snon	}
58679697Snon
58779697Snon	if ((xs->flags & SCSI_RESET) != 0)
58879697Snon	{
58979697Snon		flags |= CCB_NORETRY | CCB_URGENT;
59079697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET);
59179697Snon	}
59279697Snon	else
59379697Snon	{
59479697Snon		if (ti->ti_setup_msg != 0)
59579697Snon		{
59679697Snon			scsi_low_message_enqueue(slp, ti, li, flags);
59779697Snon		}
59879697Snon
59979697Snon		flags |= CCB_SCSIIO;
60079697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
60179697Snon	}
60279697Snon
60379697Snon#ifdef	SCSI_LOW_DEBUG
60479697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0)
60579697Snon	{
60679697Snon		scsi_low_test_abort(slp, ti, li);
60779697Snon	}
60879697Snon#endif	/* SCSI_LOW_DEBUG */
60979697Snon
61079697Snon	if ((cb->ccb_flags & CCB_POLLED) != 0)
61179697Snon	{
61279697Snon		rv = scsi_low_poll_xs(slp, cb);
61379697Snon	}
61479697Snon	else
61579697Snon	{
61679697Snon		rv = SUCCESSFULLY_QUEUED;
61779697Snon	}
61879697Snon	splx(s);
61979697Snon	return rv;
62079697Snon}
62179697Snon
62279697Snonstatic int
62379697Snonscsi_low_attach_xs(slp)
62479697Snon	struct scsi_low_softc *slp;
62579697Snon{
62679697Snon	struct scsipi_adapter *sap;
62779697Snon	struct scsipi_link *splp;
62879697Snon
62979697Snon	strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16);
63079697Snon
63179697Snon	sap = SCSI_LOW_MALLOC(sizeof(*sap));
63279697Snon	if (sap == NULL)
63379697Snon		return ENOMEM;
63479697Snon	splp = SCSI_LOW_MALLOC(sizeof(*splp));
63579697Snon	if (splp == NULL)
63679697Snon		return ENOMEM;
63779697Snon
63879697Snon	SCSI_LOW_BZERO(sap, sizeof(*sap));
63979697Snon	SCSI_LOW_BZERO(splp, sizeof(*splp));
64079697Snon
64179697Snon	sap->scsipi_cmd = scsi_low_scsi_cmd_xs;
64279697Snon	sap->scsipi_minphys = scsi_low_scsi_minphys_xs;
64379697Snon	sap->scsipi_enable = scsi_low_enable_xs;
64479697Snon	sap->scsipi_ioctl = scsi_low_ioctl_xs;
64579697Snon#ifdef	SCSI_LOW_TARGET_OPEN
64679697Snon	sap->open_target_lu = scsi_low_target_open;
64779697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
64879697Snon
64979697Snon	splp->adapter_softc = slp;
65079697Snon	splp->scsipi_scsi.adapter_target = slp->sl_hostid;
65179697Snon	splp->scsipi_scsi.max_target = slp->sl_ntargs - 1;
65279697Snon	splp->scsipi_scsi.max_lun = slp->sl_nluns - 1;
65379697Snon	splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
65479697Snon	splp->openings = slp->sl_openings;
65579697Snon	splp->type = BUS_SCSI;
65679697Snon	splp->adapter_softc = slp;
65779697Snon	splp->adapter = sap;
65879697Snon	splp->device = &scsi_low_dev;
65979697Snon
66079697Snon	slp->sl_si.si_splp = splp;
66179697Snon	slp->sl_show_result = SHOW_ALL_NEG;
66279697Snon	return 0;
66379697Snon}
66479697Snon
66579697Snonstatic int
66679697Snonscsi_low_world_start_xs(slp)
66779697Snon	struct scsi_low_softc *slp;
66879697Snon{
66979697Snon
67079697Snon	return 0;
67179697Snon}
67279697Snon
67379697Snonstatic int
67479697Snonscsi_low_dettach_xs(slp)
67579697Snon	struct scsi_low_softc *slp;
67679697Snon{
67779697Snon
67879697Snon	/*
67979697Snon	 * scsipi does not have dettach bus fucntion.
68079697Snon	 *
68179697Snon	scsipi_dettach_scsibus(slp->sl_si.si_splp);
68279697Snon	*/
68379697Snon	return 0;
68479697Snon}
68579697Snon
68679697Snonstatic int
68779697Snonscsi_low_ccb_setup_xs(slp, cb)
68879697Snon	struct scsi_low_softc *slp;
68979697Snon	struct slccb *cb;
69079697Snon{
69179697Snon	struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep;
69279697Snon
69379697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
69479697Snon	{
69579697Snon		cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd;
69679697Snon		cb->ccb_scp.scp_cmdlen = xs->cmdlen;
69779697Snon		cb->ccb_scp.scp_data = xs->data;
69879697Snon		cb->ccb_scp.scp_datalen = xs->datalen;
69979697Snon		cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ?
70079697Snon					SCSI_LOW_WRITE : SCSI_LOW_READ;
70179697Snon		cb->ccb_tcmax = xs->timeout / 1000;
70279697Snon	}
70379697Snon	else
70479697Snon	{
70579697Snon		scsi_low_unit_ready_cmd(cb);
70679697Snon	}
70779697Snon	return SCSI_LOW_START_QTAG;
70879697Snon}
70979697Snon
71079697Snonstatic int
71179697Snonscsi_low_done_xs(slp, cb)
71279697Snon	struct scsi_low_softc *slp;
71379697Snon	struct slccb *cb;
71479697Snon{
71579697Snon	struct scsipi_xfer *xs;
71679697Snon
71779697Snon	xs = (struct scsipi_xfer *) cb->osdep;
71879697Snon	if (cb->ccb_error == 0)
71979697Snon	{
72079697Snon		xs->error = XS_NOERROR;
72179697Snon		xs->resid = 0;
72279697Snon	}
72379697Snon	else
72479697Snon	{
72579697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
72679697Snon			cb->ccb_error |= ABORTIO;
72779697Snon
72879697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
72979697Snon		    (cb->ccb_error & ABORTIO) == 0)
73079697Snon			return EJUSTRETURN;
73179697Snon
73279697Snon		if ((cb->ccb_error & SENSEIO) != 0)
73379697Snon		{
73479697Snon			xs->sense.scsi_sense = cb->ccb_sense;
73579697Snon		}
73679697Snon
73779697Snon		xs->error = scsi_low_translate_error_code(cb,
73879697Snon				&scsi_low_error_code_xs[0]);
73979697Snon
74079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
74179697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
74279697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
74379697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
74479697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
74579697Snon		{
74679697Snon			printf("%s: WARNING: scsi_low IO abort\n",
74779697Snon				slp->sl_xname);
74879697Snon			scsi_low_print(slp, NULL);
74979697Snon		}
75079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
75179697Snon	}
75279697Snon
75379697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
75479697Snon		xs->status = 0;	/* XXX */
75579697Snon	else
75679697Snon		xs->status = cb->ccb_scp.scp_status;
75779697Snon
75879697Snon	xs->flags |= ITSDONE;
75979697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
76079697Snon		scsipi_done(xs);
76179697Snon
76279697Snon	return 0;
76379697Snon}
76479697Snon
76579697Snonstatic void
76679697Snonscsi_low_timeout_xs(slp, ch, action)
76779697Snon	struct scsi_low_softc *slp;
76879697Snon	int ch;
76979697Snon	int action;
77079697Snon{
77179697Snon
77279697Snon	switch (ch)
77379697Snon	{
77479697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
77579697Snon		switch (action)
77679697Snon		{
77779697Snon		case SCSI_LOW_TIMEOUT_START:
77879697Snon			timeout(scsi_low_timeout, slp,
77979697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
78079697Snon			break;
78179697Snon		case SCSI_LOW_TIMEOUT_STOP:
78279697Snon			untimeout(scsi_low_timeout, slp);
78379697Snon			break;
78479697Snon		}
78579697Snon		break;
78679697Snon
78779697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
78879697Snon		switch (action)
78979697Snon		{
79079697Snon		case SCSI_LOW_TIMEOUT_START:
79179697Snon			timeout(scsi_low_engage, slp, 1);
79279697Snon			break;
79379697Snon		case SCSI_LOW_TIMEOUT_STOP:
79479697Snon			untimeout(scsi_low_engage, slp);
79579697Snon			break;
79679697Snon		}
79779697Snon		break;
79879697Snon
79979697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
80079697Snon		break;
80179697Snon	}
80279697Snon}
80379697Snon
80479697Snonu_int
80579697Snonscsi_low_translate_quirks_xs(quirks)
80679697Snon	u_int quirks;
80779697Snon{
80879697Snon	u_int flags;
80979697Snon
81079697Snon	flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS;
81179697Snon
81279697Snon#ifdef	SDEV_NODISC
81379697Snon	if (quirks & SDEV_NODISC)
81479697Snon		flags &= ~SCSI_LOW_DISK_DISC;
81579697Snon#endif	/* SDEV_NODISC */
81679697Snon#ifdef	SDEV_NOPARITY
81779697Snon	if (quirks & SDEV_NOPARITY)
81879697Snon		flags &= ~SCSI_LOW_DISK_PARITY;
81979697Snon#endif	/* SDEV_NOPARITY */
82079697Snon#ifdef	SDEV_NOCMDLNK
82179697Snon	if (quirks & SDEV_NOCMDLNK)
82279697Snon		flags &= ~SCSI_LOW_DISK_LINK;
82379697Snon#endif	/* SDEV_NOCMDLNK */
82479697Snon#ifdef	SDEV_NOTAG
82579697Snon	if (quirks & SDEV_NOTAG)
82679697Snon		flags &= ~SCSI_LOW_DISK_QTAG;
82779697Snon#endif	/* SDEV_NOTAG */
82879697Snon#ifdef	SDEV_NOSYNC
82979697Snon	if (quirks & SDEV_NOSYNC)
83079697Snon		flags &= ~SCSI_LOW_DISK_SYNC;
83179697Snon#endif	/* SDEV_NOSYNC */
83279697Snon
83379697Snon	return flags;
83479697Snon}
83579697Snon
83679697Snonstatic void
83779697Snonscsi_low_setup_quirks_xs(ti, li, flags)
83879697Snon	struct targ_info *ti;
83979697Snon	struct lun_info *li;
84079697Snon	u_int flags;
84179697Snon{
84279697Snon	u_int quirks;
84379697Snon
84479697Snon	li->li_sloi.sloi_quirks = flags;
84579697Snon	quirks = scsi_low_translate_quirks_xs(flags);
84679697Snon	ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS;
84779697Snon	li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS;
84879697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
84979697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
85079697Snon	scsi_low_calcf_target(ti);
85179697Snon	scsi_low_calcf_lun(li);
85279697Snon	scsi_low_calcf_show(li);
85379697Snon}
85479697Snon
85579697Snon#ifdef	SCSI_LOW_TARGET_OPEN
85679697Snonstatic int
85779697Snonscsi_low_target_open(link, cf)
85879697Snon	struct scsipi_link *link;
85979697Snon	struct cfdata *cf;
86079697Snon{
86179697Snon	u_int target = link->scsipi_scsi.target;
86279697Snon	u_int lun = link->scsipi_scsi.lun;
86379697Snon	struct scsi_low_softc *slp;
86479697Snon	struct targ_info *ti;
86579697Snon	struct lun_info *li;
86679697Snon
86779697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
86879697Snon	ti = slp->sl_ti[target];
86979697Snon	li = scsi_low_alloc_li(ti, lun, 0);
87079697Snon	if (li == NULL)
87179697Snon		return 0;
87279697Snon
87379697Snon	li->li_cfgflags = cf->cf_flags;
87479697Snon	scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks);
87579697Snon	return 0;
87679697Snon}
87779697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
87879697Snon
87979697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
88079697Snon
88179697Snon#ifdef SCSI_LOW_INTERFACE_CAM
88279697Snon/**************************************************************
88379697Snon * SCSI INTERFACE (CAM)
88479697Snon **************************************************************/
88579697Snon#define	SCSI_LOW_MALLOC(size)		malloc((size), M_DEVBUF, M_NOWAIT)
88679697Snon#define	SCSI_LOW_FREE(pt)		free((pt), M_DEVBUF)
88779697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb()
88879697Snon
88992770Salfredstatic void scsi_low_poll_cam(struct cam_sim *);
89092770Salfredstatic void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *);
89192770Salfredstatic void scsi_low_rescan_bus_cam(struct scsi_low_softc *);
89292770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
89379697Snon
89492770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *);
89592770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *);
89692770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *);
89792770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *);
89892770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *);
89992770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int);
90079697Snon
90179697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = {
90279697Snon	scsi_low_attach_cam,
90379697Snon	scsi_low_world_start_cam,
90479697Snon	scsi_low_dettach_cam,
90579697Snon	scsi_low_ccb_setup_cam,
90679697Snon	scsi_low_done_cam,
90779697Snon	scsi_low_timeout_cam
90879697Snon};
90979697Snon
91079697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = {
91179697Snon	{0,			CAM_REQ_CMP},
91279697Snon	{SENSEIO, 		CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
91379697Snon	{SENSEERR,		CAM_AUTOSENSE_FAIL},
91479697Snon	{UACAERR,		CAM_SCSI_STATUS_ERROR},
91579697Snon	{BUSYERR | STATERR,	CAM_SCSI_STATUS_ERROR},
91679697Snon	{SELTIMEOUTIO,		CAM_SEL_TIMEOUT},
91779697Snon	{TIMEOUTIO,		CAM_CMD_TIMEOUT},
91879697Snon	{PDMAERR,		CAM_DATA_RUN_ERR},
91979697Snon	{PARITYERR,		CAM_UNCOR_PARITY},
92079697Snon	{UBFERR,		CAM_UNEXP_BUSFREE},
92179697Snon	{ABORTIO,		CAM_REQ_ABORTED},
92279697Snon	{-1,			CAM_UNREC_HBA_ERROR}
92379697Snon};
92479697Snon
92579697Snon#define	SIM2SLP(sim)	((struct scsi_low_softc *) cam_sim_softc((sim)))
92679697Snon
92779697Snon/* XXX:
92879697Snon * Please check a polling hz, currently we assume scsi_low_poll() is
92979697Snon * called each 1 ms.
93079697Snon */
93179697Snon#define	SCSI_LOW_CAM_POLL_HZ	1000	/* OK ? */
93279697Snon
93379697Snonstatic void
93479697Snonscsi_low_poll_cam(sim)
93579697Snon	struct cam_sim *sim;
93679697Snon{
93779697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
93879697Snon
93979697Snon	(*slp->sl_funcs->scsi_low_poll) (slp);
94079697Snon
94179697Snon	if (slp->sl_si.si_poll_count ++ >=
94279697Snon	    SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
94379697Snon	{
94479697Snon		slp->sl_si.si_poll_count = 0;
94579697Snon		scsi_low_timeout_check(slp);
94679697Snon	}
94779697Snon}
94879697Snon
94979697Snonstatic void
95079697Snonscsi_low_cam_rescan_callback(periph, ccb)
95179697Snon	struct cam_periph *periph;
95279697Snon	union ccb *ccb;
95379697Snon{
95479697Snon
95579697Snon	xpt_free_path(ccb->ccb_h.path);
95679697Snon	free(ccb, M_DEVBUF);
95779697Snon}
95879697Snon
95979697Snonstatic void
96079697Snonscsi_low_rescan_bus_cam(slp)
96179697Snon	struct scsi_low_softc *slp;
96279697Snon{
96379697Snon  	struct cam_path *path;
96479697Snon	union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK);
96579697Snon	cam_status status;
96679697Snon
96779697Snon	bzero(ccb, sizeof(union ccb));
96879697Snon
96979697Snon	status = xpt_create_path(&path, xpt_periph,
97079697Snon				 cam_sim_path(slp->sl_si.sim), -1, 0);
97179697Snon	if (status != CAM_REQ_CMP)
97279697Snon		return;
97379697Snon
97479697Snon	xpt_setup_ccb(&ccb->ccb_h, path, 5);
97579697Snon	ccb->ccb_h.func_code = XPT_SCAN_BUS;
97679697Snon	ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback;
97779697Snon	ccb->crcn.flags = CAM_FLAG_NONE;
97879697Snon	xpt_action(ccb);
97979697Snon}
98079697Snon
98179697Snonvoid
98279697Snonscsi_low_scsi_action_cam(sim, ccb)
98379697Snon	struct cam_sim *sim;
98479697Snon	union ccb *ccb;
98579697Snon{
98679697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
98779697Snon	struct targ_info *ti;
98879697Snon	struct lun_info *li;
98979697Snon	struct slccb *cb;
99079697Snon	u_int lun, flags, msg, target;
99179697Snon	int s, rv;
99279697Snon
99379697Snon	target = (u_int) (ccb->ccb_h.target_id);
99479697Snon	lun = (u_int) ccb->ccb_h.target_lun;
99579697Snon
99679697Snon#ifdef	SCSI_LOW_DEBUG
99779697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
99879697Snon	{
99979697Snon		printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n",
100079697Snon			slp->sl_xname, ccb->ccb_h.func_code, target, lun);
100179697Snon	}
100279697Snon#endif	/* SCSI_LOW_DEBUG */
100379697Snon
100479697Snon	switch (ccb->ccb_h.func_code) {
100579697Snon	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
100679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
100779697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
100879697Snon		{
100979697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
101079697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
101179697Snon			xpt_done(ccb);
101279697Snon			return;
101379697Snon		}
101479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
101579697Snon
101679697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
101779697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
101879697Snon			xpt_done(ccb);
101979697Snon			return;
102079697Snon		}
102179697Snon
102279697Snon		ti = slp->sl_ti[target];
102379697Snon		cb->osdep = ccb;
102479697Snon		cb->bp = NULL;
102579697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
102679697Snon			flags = CCB_AUTOSENSE | CCB_SCSIIO;
102779697Snon		else
102879697Snon			flags = CCB_SCSIIO;
102979697Snon
103079697Snon		s = SCSI_LOW_SPLSCSI();
103179697Snon		li = scsi_low_alloc_li(ti, lun, 1);
103279697Snon
103379697Snon		if (ti->ti_setup_msg != 0)
103479697Snon		{
103579697Snon			scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
103679697Snon		}
103779697Snon
103879697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
103979697Snon
104079697Snon#ifdef	SCSI_LOW_DEBUG
104179697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
104279697Snon		{
104379697Snon			scsi_low_test_abort(slp, ti, li);
104479697Snon		}
104579697Snon#endif	/* SCSI_LOW_DEBUG */
104679697Snon		splx(s);
104779697Snon		break;
104879697Snon
104979697Snon	case XPT_EN_LUN:		/* Enable LUN as a target */
105079697Snon	case XPT_TARGET_IO:		/* Execute target I/O request */
105179697Snon	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
105279697Snon	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
105379697Snon		/* XXX Implement */
105479697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
105579697Snon		xpt_done(ccb);
105679697Snon		break;
105779697Snon
105879697Snon	case XPT_ABORT:			/* Abort the specified CCB */
105979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
106079697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
106179697Snon		{
106279697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
106379697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
106479697Snon			xpt_done(ccb);
106579697Snon			return;
106679697Snon		}
106779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
106879697Snon
106979697Snon		s = SCSI_LOW_SPLSCSI();
107079697Snon		cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
107179697Snon		rv = scsi_low_abort_ccb(slp, cb);
107279697Snon		splx(s);
107379697Snon
107479697Snon		if (rv == 0)
107579697Snon			ccb->ccb_h.status = CAM_REQ_CMP;
107679697Snon		else
107779697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
107879697Snon		xpt_done(ccb);
107979697Snon		break;
108079697Snon
108179697Snon	case XPT_SET_TRAN_SETTINGS: {
108279697Snon		struct ccb_trans_settings *cts;
108379697Snon		u_int val;
108479697Snon
108579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
108679697Snon		if (target == CAM_TARGET_WILDCARD)
108779697Snon		{
108879697Snon			printf("%s: invalid target\n", slp->sl_xname);
108979697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
109079697Snon			xpt_done(ccb);
109179697Snon			return;
109279697Snon		}
109379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
109479697Snon		cts = &ccb->cts;
109579697Snon		ti = slp->sl_ti[target];
109679697Snon		if (lun == CAM_LUN_WILDCARD)
109779697Snon			lun = 0;
109879697Snon
109979697Snon		s = SCSI_LOW_SPLSCSI();
110079697Snon		if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID |
110179697Snon				   CCB_TRANS_SYNC_RATE_VALID |
110279697Snon				   CCB_TRANS_SYNC_OFFSET_VALID)) != 0)
110379697Snon		{
110479697Snon			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
110579697Snon				val = cts->bus_width;
110679697Snon				if (val < ti->ti_width)
110779697Snon					ti->ti_width = val;
110879697Snon			}
110979697Snon			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
111079697Snon				val = cts->sync_period;
111179697Snon				if (val == 0 || val > ti->ti_maxsynch.period)
111279697Snon					ti->ti_maxsynch.period = val;
111379697Snon			}
111479697Snon			if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
111579697Snon				val = cts->sync_offset;
111679697Snon				if (val < ti->ti_maxsynch.offset)
111779697Snon					ti->ti_maxsynch.offset = val;
111879697Snon			}
111979697Snon
112079697Snon			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
112179697Snon			scsi_low_calcf_target(ti);
112279697Snon		}
112379697Snon
112479697Snon		if ((cts->valid & (CCB_TRANS_DISC_VALID |
112579697Snon				   CCB_TRANS_TQ_VALID)) != 0)
112679697Snon		{
112779697Snon			li = scsi_low_alloc_li(ti, lun, 1);
112879697Snon			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0)
112979697Snon			{
113079697Snon				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
113179697Snon					li->li_quirks |= SCSI_LOW_DISK_DISC;
113279697Snon				else
113379697Snon					li->li_quirks &= ~SCSI_LOW_DISK_DISC;
113479697Snon			}
113579697Snon			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0)
113679697Snon			{
113779697Snon				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
113879697Snon					li->li_quirks |= SCSI_LOW_DISK_QTAG;
113979697Snon				else
114079697Snon					li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
114179697Snon			}
114279697Snon
114379697Snon			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
114479697Snon			scsi_low_calcf_target(ti);
114579697Snon			scsi_low_calcf_lun(li);
114679697Snon			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
114779697Snon				scsi_low_calcf_show(li);
114879697Snon		}
114979697Snon		splx(s);
115079697Snon
115179697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
115279697Snon		xpt_done(ccb);
115379697Snon		break;
115479697Snon	}
115579697Snon
115679697Snon	case XPT_GET_TRAN_SETTINGS: {
115779697Snon		struct ccb_trans_settings *cts;
115879697Snon		u_int diskflags;
115979697Snon
116079697Snon		cts = &ccb->cts;
116179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
116279697Snon		if (target == CAM_TARGET_WILDCARD)
116379697Snon		{
116479697Snon			printf("%s: invalid target\n", slp->sl_xname);
116579697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
116679697Snon			xpt_done(ccb);
116779697Snon			return;
116879697Snon		}
116979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
117079697Snon		ti = slp->sl_ti[target];
117179697Snon		if (lun == CAM_LUN_WILDCARD)
117279697Snon			lun = 0;
117379697Snon
117479697Snon		s = SCSI_LOW_SPLSCSI();
117579697Snon		li = scsi_low_alloc_li(ti, lun, 1);
117679697Snon#ifdef CAM_NEW_TRAN_CODE
117779697Snon		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
117879697Snon			struct ccb_trans_settings_scsi *scsi =
117979697Snon				&cts->proto_specific.scsi;
118079697Snon			struct ccb_trans_settings_spi *spi =
118179697Snon				&cts->xport_specific.spi;
118279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
118379697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
118479697Snon			{
118579697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
118679697Snon				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
118779697Snon					slp->sl_xname);
118879697Snon				goto settings_out;
118979697Snon			}
119079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
119179697Snon			cts->protocol = PROTO_SCSI;
119279697Snon			cts->protocol_version = SCSI_REV_2;
119379697Snon			cts->transport = XPORT_SPI;
119479697Snon			cts->transport_version = 2;
119579697Snon
119679697Snon			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
119779697Snon			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
119879697Snon
119979697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
120079697Snon			if (diskflags & SCSI_LOW_DISK_DISC)
120179697Snon				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
120279697Snon			if (diskflags & SCSI_LOW_DISK_QTAG)
120379697Snon				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
120479697Snon
120579697Snon			spi->sync_period = ti->ti_maxsynch.period;
120679697Snon			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
120779697Snon			spi->sync_offset = ti->ti_maxsynch.offset;
120879697Snon			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
120979697Snon
121079697Snon			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
121179697Snon			spi->bus_width = ti->ti_width;
121279697Snon
121379697Snon			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
121479697Snon				scsi->valid = CTS_SCSI_VALID_TQ;
121579697Snon				spi->valid |= CTS_SPI_VALID_DISC;
121679697Snon			} else
121779697Snon				scsi->valid = 0;
121879697Snon		} else
121979697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
122079697Snon#else
122179697Snon 		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
122279697Snon 		{
122379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
122479697Snon			if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0)
122579697Snon			{
122679697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
122779697Snon				printf("%s: invalid GET_TRANS_USER_SETTINGS call\n",
122879697Snon					slp->sl_xname);
122979697Snon				goto settings_out;
123079697Snon			}
123179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
123279697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
123379697Snon			if ((diskflags & SCSI_LOW_DISK_DISC) != 0)
123479697Snon				cts->flags |= CCB_TRANS_DISC_ENB;
123579697Snon			else
123679697Snon				cts->flags &= ~CCB_TRANS_DISC_ENB;
123779697Snon			if ((diskflags & SCSI_LOW_DISK_QTAG) != 0)
123879697Snon				cts->flags |= CCB_TRANS_TAG_ENB;
123979697Snon			else
124079697Snon				cts->flags &= ~CCB_TRANS_TAG_ENB;
124179697Snon		}
124279697Snon		else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
124379697Snon		{
124479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
124579697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
124679697Snon			{
124779697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
124879697Snon				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
124979697Snon					slp->sl_xname);
125079697Snon				goto settings_out;
125179697Snon			}
125279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
125379697Snon			if ((li->li_flags & SCSI_LOW_DISC) != 0)
125479697Snon				cts->flags |= CCB_TRANS_DISC_ENB;
125579697Snon			else
125679697Snon				cts->flags &= ~CCB_TRANS_DISC_ENB;
125779697Snon			if ((li->li_flags & SCSI_LOW_QTAG) != 0)
125879697Snon				cts->flags |= CCB_TRANS_TAG_ENB;
125979697Snon			else
126079697Snon				cts->flags &= ~CCB_TRANS_TAG_ENB;
126179697Snon		}
126279697Snon		else
126379697Snon		{
126479697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
126579697Snon			goto settings_out;
126679697Snon		}
126779697Snon
126879697Snon		cts->sync_period = ti->ti_maxsynch.period;
126979697Snon		cts->sync_offset = ti->ti_maxsynch.offset;
127079697Snon		cts->bus_width = ti->ti_width;
127179697Snon
127279697Snon		cts->valid = CCB_TRANS_SYNC_RATE_VALID
127379697Snon			   | CCB_TRANS_SYNC_OFFSET_VALID
127479697Snon			   | CCB_TRANS_BUS_WIDTH_VALID
127579697Snon			   | CCB_TRANS_DISC_VALID
127679697Snon			   | CCB_TRANS_TQ_VALID;
127779697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
127879697Snon#endif
127979697Snonsettings_out:
128079697Snon		splx(s);
128179697Snon		xpt_done(ccb);
128279697Snon		break;
128379697Snon	}
128479697Snon
128579697Snon	case XPT_CALC_GEOMETRY: { /* not yet HN2 */
128679697Snon		struct	  ccb_calc_geometry *ccg;
128779697Snon		u_int32_t size_mb;
128879697Snon		u_int32_t secs_per_cylinder;
128979697Snon		int       extended;
129079697Snon
129179697Snon		extended = 1;
129279697Snon		ccg = &ccb->ccg;
129379697Snon		size_mb = ccg->volume_size
129479697Snon			/ ((1024L * 1024L) / ccg->block_size);
129579697Snon
129679697Snon		if (size_mb > 1024 && extended) {
129779697Snon		        ccg->heads = 255;
129879697Snon		        ccg->secs_per_track = 63;
129979697Snon		} else {
130079697Snon		        ccg->heads = 64;
130179697Snon		        ccg->secs_per_track = 32;
130279697Snon		}
130379697Snon		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
130479697Snon		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
130579697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
130679697Snon		xpt_done(ccb);
130779697Snon		break;
130879697Snon	}
130979697Snon
131079697Snon	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
131179697Snon		s = SCSI_LOW_SPLSCSI();
131279697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
131379697Snon		splx(s);
131479697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
131579697Snon		xpt_done(ccb);
131679697Snon		break;
131779697Snon
131879697Snon	case XPT_TERM_IO:	/* Terminate the I/O process */
131979697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
132079697Snon		xpt_done(ccb);
132179697Snon		break;
132279697Snon
132379697Snon	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
132479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
132579697Snon		if (target == CAM_TARGET_WILDCARD)
132679697Snon		{
132779697Snon			printf("%s: invalid target\n", slp->sl_xname);
132879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
132979697Snon			xpt_done(ccb);
133079697Snon			return;
133179697Snon		}
133279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
133379697Snon
133479697Snon		msg = SCSI_LOW_MSG_RESET;
133579697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
133679697Snon		{
133779697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
133879697Snon			xpt_done(ccb);
133979697Snon			return;
134079697Snon		}
134179697Snon
134279697Snon		ti = slp->sl_ti[target];
134379697Snon		if (lun == CAM_LUN_WILDCARD)
134479697Snon			lun = 0;
134579697Snon		cb->osdep = ccb;
134679697Snon		cb->bp = NULL;
134779697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
134879697Snon			flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
134979697Snon		else
135079697Snon			flags = CCB_NORETRY | CCB_URGENT;
135179697Snon
135279697Snon		s = SCSI_LOW_SPLSCSI();
135379697Snon		li = scsi_low_alloc_li(ti, lun, 1);
135479697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, msg);
135579697Snon		splx(s);
135679697Snon		break;
135779697Snon
135879697Snon	case XPT_PATH_INQ: {		/* Path routing inquiry */
135979697Snon		struct ccb_pathinq *cpi = &ccb->cpi;
136079697Snon
136179697Snon		cpi->version_num = scsi_low_version_major;
136279697Snon		cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
136379697Snon		ti = slp->sl_ti[slp->sl_hostid];	/* host id */
136479697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
136579697Snon			cpi->hba_inquiry |= PI_WIDE_16;
136679697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
136779697Snon			cpi->hba_inquiry |= PI_WIDE_32;
136879697Snon		if (ti->ti_maxsynch.offset > 0)
136979697Snon			cpi->hba_inquiry |= PI_SDTR_ABLE;
137079697Snon		cpi->target_sprt = 0;
137179697Snon		cpi->hba_misc = 0;
137279697Snon		cpi->hba_eng_cnt = 0;
137379697Snon		cpi->max_target = slp->sl_ntargs - 1;
137479697Snon		cpi->max_lun = slp->sl_nluns - 1;
137579697Snon		cpi->initiator_id = slp->sl_hostid;
137679697Snon		cpi->bus_id = cam_sim_bus(sim);
137779697Snon		cpi->base_transfer_speed = 3300;
137879697Snon#ifdef CAM_NEW_TRAN_CODE
137979697Snon		cpi->transport = XPORT_SPI;
138079697Snon		cpi->transport_version = 2;
138179697Snon		cpi->protocol = PROTO_SCSI;
138279697Snon		cpi->protocol_version = SCSI_REV_2;
138379697Snon#endif
138479697Snon		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
138579697Snon		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
138679697Snon		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
138779697Snon		cpi->unit_number = cam_sim_unit(sim);
138879697Snon		cpi->ccb_h.status = CAM_REQ_CMP;
138979697Snon		xpt_done(ccb);
139079697Snon		break;
139179697Snon	}
139279697Snon
139379697Snon	default:
139479697Snon	        printf("scsi_low: non support func_code = %d ",
139579697Snon			ccb->ccb_h.func_code);
139679697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
139779697Snon		xpt_done(ccb);
139879697Snon		break;
139979697Snon	}
140079697Snon}
140179697Snon
140279697Snonstatic int
140379697Snonscsi_low_attach_cam(slp)
140479697Snon	struct scsi_low_softc *slp;
140579697Snon{
140679697Snon	struct cam_devq *devq;
140779697Snon	int tagged_openings;
140879697Snon
140979697Snon	sprintf(slp->sl_xname, "%s%d",
141079697Snon		DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev));
141179697Snon
141279697Snon	devq = cam_simq_alloc(SCSI_LOW_NCCB);
141379697Snon	if (devq == NULL)
141479697Snon		return (ENOMEM);
141579697Snon
141679697Snon	/*
141779697Snon	 * ask the adapter what subunits are present
141879697Snon	 */
141979697Snon	tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
142079697Snon	slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
142179697Snon				scsi_low_poll_cam,
142279697Snon				DEVPORT_DEVNAME(slp->sl_dev), slp,
142379697Snon				DEVPORT_DEVUNIT(slp->sl_dev),
142479697Snon				slp->sl_openings, tagged_openings, devq);
142579697Snon
142679697Snon	if (slp->sl_si.sim == NULL) {
142779697Snon		cam_simq_free(devq);
142879697Snon	 	return ENODEV;
142979697Snon	}
143079697Snon
143179697Snon	if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) {
143279697Snon		free(slp->sl_si.sim, M_DEVBUF);
143379697Snon	 	return ENODEV;
143479697Snon	}
143579697Snon
143679697Snon	if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL,
143779697Snon			cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD,
143879697Snon			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
143979697Snon		xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
144079697Snon		cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE);
144179697Snon		free(slp->sl_si.sim, M_DEVBUF);
144279697Snon		return ENODEV;
144379697Snon	}
144479697Snon
144579697Snon	slp->sl_show_result = SHOW_CALCF_RES;		/* OK ? */
144679697Snon	return 0;
144779697Snon}
144879697Snon
144979697Snonstatic int
145079697Snonscsi_low_world_start_cam(slp)
145179697Snon	struct scsi_low_softc *slp;
145279697Snon{
145379697Snon
145479697Snon	if (!cold)
145579697Snon		scsi_low_rescan_bus_cam(slp);
145679697Snon	return 0;
145779697Snon}
145879697Snon
145979697Snonstatic int
146079697Snonscsi_low_dettach_cam(slp)
146179697Snon	struct scsi_low_softc *slp;
146279697Snon{
146379697Snon
146479697Snon	xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL);
146579697Snon	xpt_free_path(slp->sl_si.path);
146679697Snon	xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
146779697Snon	cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE);
146879697Snon	return 0;
146979697Snon}
147079697Snon
147179697Snonstatic int
147279697Snonscsi_low_ccb_setup_cam(slp, cb)
147379697Snon	struct scsi_low_softc *slp;
147479697Snon	struct slccb *cb;
147579697Snon{
147679697Snon        union ccb *ccb = (union ccb *) cb->osdep;
147779697Snon
147879697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
147979697Snon	{
148079697Snon		cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
148179697Snon		cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
148279697Snon		cb->ccb_scp.scp_data = ccb->csio.data_ptr;
148379697Snon		cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
148479697Snon		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
148579697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
148679697Snon		else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
148779697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_READ;
148879697Snon		cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
148979697Snon	}
149079697Snon	else
149179697Snon	{
149279697Snon		scsi_low_unit_ready_cmd(cb);
149379697Snon	}
149479697Snon	return SCSI_LOW_START_QTAG;
149579697Snon}
149679697Snon
149779697Snonstatic int
149879697Snonscsi_low_done_cam(slp, cb)
149979697Snon	struct scsi_low_softc *slp;
150079697Snon	struct slccb *cb;
150179697Snon{
150279697Snon	union ccb *ccb;
150379697Snon
150479697Snon	ccb = (union ccb *) cb->osdep;
150579697Snon	if (cb->ccb_error == 0)
150679697Snon	{
150779697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
150879697Snon		ccb->csio.resid = 0;
150979697Snon	}
151079697Snon	else
151179697Snon	{
151279697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
151379697Snon			cb->ccb_error |= ABORTIO;
151479697Snon
151579697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
151679697Snon		    (cb->ccb_error & ABORTIO) == 0)
151779697Snon			return EJUSTRETURN;
151879697Snon
151979697Snon		if ((cb->ccb_error & SENSEIO) != 0)
152079697Snon		{
152179697Snon			memcpy(&ccb->csio.sense_data,
152279697Snon			       &cb->ccb_sense,
152379697Snon			       sizeof(ccb->csio.sense_data));
152479697Snon		}
152579697Snon
152679697Snon		ccb->ccb_h.status = scsi_low_translate_error_code(cb,
152779697Snon					&scsi_low_error_code_cam[0]);
152879697Snon
152979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
153079697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
153179697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
153279697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
153379697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
153479697Snon		{
153579697Snon			printf("%s: WARNING: scsi_low IO abort\n",
153679697Snon				slp->sl_xname);
153779697Snon			scsi_low_print(slp, NULL);
153879697Snon		}
153979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
154079697Snon	}
154179697Snon
154279697Snon	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
154379697Snon		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
154479697Snon
154579697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
154679697Snon		ccb->csio.scsi_status = 0;	/* XXX */
154779697Snon	else
154879697Snon		ccb->csio.scsi_status = cb->ccb_scp.scp_status;
154979697Snon
155079697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
155179697Snon		xpt_done(ccb);
155279697Snon	return 0;
155379697Snon}
155479697Snon
155579697Snonstatic void
155679697Snonscsi_low_timeout_cam(slp, ch, action)
155779697Snon	struct scsi_low_softc *slp;
155879697Snon	int ch;
155979697Snon	int action;
156079697Snon{
156179697Snon
156279697Snon	switch (ch)
156379697Snon	{
156479697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
156579697Snon		switch (action)
156679697Snon		{
156779697Snon		case SCSI_LOW_TIMEOUT_START:
156879697Snon			slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp,
156979697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
157079697Snon			break;
157179697Snon		case SCSI_LOW_TIMEOUT_STOP:
157279697Snon			untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch);
157379697Snon			break;
157479697Snon		}
157579697Snon		break;
157679697Snon
157779697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
157879697Snon		switch (action)
157979697Snon		{
158079697Snon		case SCSI_LOW_TIMEOUT_START:
158179697Snon			slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1);
158279697Snon			break;
158379697Snon		case SCSI_LOW_TIMEOUT_STOP:
158479697Snon			untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch);
158579697Snon			break;
158679697Snon		}
158779697Snon		break;
158879697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
158979697Snon		break;
159079697Snon	}
159179697Snon}
159279697Snon
159379697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
159479697Snon
159579697Snon/*=============================================================
159679697Snon * END OF OS switch  (All OS depend fucntions should be above)
159779697Snon =============================================================*/
159879697Snon
159979697Snon/**************************************************************
160079697Snon * scsi low deactivate and activate
160179697Snon **************************************************************/
160279697Snonint
160379697Snonscsi_low_is_busy(slp)
160479697Snon	struct scsi_low_softc *slp;
160579697Snon{
160679697Snon
160779697Snon	if (slp->sl_nio > 0)
160879697Snon		return EBUSY;
160979697Snon	return 0;
161079697Snon}
161179697Snon
161279697Snonint
161379697Snonscsi_low_deactivate(slp)
161479697Snon	struct scsi_low_softc *slp;
161579697Snon{
161679697Snon	int s;
161779697Snon
161879697Snon	s = SCSI_LOW_SPLSCSI();
161979697Snon	slp->sl_flags |= HW_INACTIVE;
162079697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
162179697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP);
162279697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
162379697Snon		(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
162479697Snon	splx(s);
162579697Snon	return 0;
162679697Snon}
162779697Snon
162879697Snonint
162979697Snonscsi_low_activate(slp)
163079697Snon	struct scsi_low_softc *slp;
163179697Snon{
163279697Snon	int error, s;
163379697Snon
163479697Snon	s = SCSI_LOW_SPLSCSI();
163579697Snon	slp->sl_flags &= ~HW_INACTIVE;
163679697Snon	if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
163779697Snon	{
163879697Snon		slp->sl_flags |= HW_INACTIVE;
163979697Snon		splx(s);
164079697Snon		return error;
164179697Snon	}
164279697Snon
164379697Snon	slp->sl_timeout_count = 0;
164479697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
164579697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
164679697Snon	splx(s);
164779697Snon	return 0;
164879697Snon}
164979697Snon
165079697Snon/**************************************************************
165179697Snon * scsi low log
165279697Snon **************************************************************/
165379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
165492770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *);
165592770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int);
165692770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int);
165779697Snon
165879697Snonstatic void
165979697Snonscsi_low_msg_log_init(slmlp)
166079697Snon	struct scsi_low_msg_log *slmlp;
166179697Snon{
166279697Snon
166379697Snon	slmlp->slml_ptr = 0;
166479697Snon}
166579697Snon
166679697Snonstatic void
166779697Snonscsi_low_msg_log_write(slmlp, datap, len)
166879697Snon	struct scsi_low_msg_log *slmlp;
166979697Snon	u_int8_t *datap;
167079697Snon	int len;
167179697Snon{
167279697Snon	int ptr, ind;
167379697Snon
167479697Snon	if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
167579697Snon		return;
167679697Snon
167779697Snon	ptr = slmlp->slml_ptr ++;
167879697Snon	for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
167979697Snon		slmlp->slml_msg[ptr].msg[ind] = datap[ind];
168079697Snon	for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
168179697Snon		slmlp->slml_msg[ptr].msg[ind] = 0;
168279697Snon}
168379697Snon
168479697Snonstatic void
168579697Snonscsi_low_msg_log_show(slmlp, s, len)
168679697Snon	struct scsi_low_msg_log *slmlp;
168779697Snon	char *s;
168879697Snon	int len;
168979697Snon{
169079697Snon	int ptr, ind;
169179697Snon
169279697Snon	printf("%s: (%d) ", s, slmlp->slml_ptr);
169379697Snon	for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
169479697Snon	{
169579697Snon		for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
169679697Snon		     ind ++)
169779697Snon		{
169879697Snon			printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
169979697Snon		}
170079697Snon		printf(">");
170179697Snon	}
170279697Snon	printf("\n");
170379697Snon}
170479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
170579697Snon
170679697Snon/**************************************************************
170767468Snon * power control
170867468Snon **************************************************************/
170967468Snonstatic void
171067468Snonscsi_low_engage(arg)
171167468Snon	void *arg;
171267468Snon{
171367468Snon	struct scsi_low_softc *slp = arg;
171479697Snon	int s = SCSI_LOW_SPLSCSI();
171567468Snon
171667468Snon	switch (slp->sl_rstep)
171767468Snon	{
171867468Snon	case 0:
171967468Snon		slp->sl_rstep ++;
172067468Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
172179697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
172279697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START);
172367468Snon		break;
172467468Snon
172567468Snon	case 1:
172667468Snon		slp->sl_rstep ++;
172767468Snon		slp->sl_flags &= ~HW_RESUME;
172867468Snon		scsi_low_start(slp);
172967468Snon		break;
173067468Snon
173167468Snon	case 2:
173267468Snon		break;
173367468Snon	}
173467468Snon	splx(s);
173567468Snon}
173667468Snon
173767468Snonstatic int
173867468Snonscsi_low_init(slp, flags)
173967468Snon	struct scsi_low_softc *slp;
174067468Snon	u_int flags;
174167468Snon{
174279697Snon	int rv = 0;
174367468Snon
174479697Snon	slp->sl_flags |= HW_INITIALIZING;
174579697Snon
174679697Snon	/* clear power control timeout */
174767468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
174867468Snon	{
174979697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
175079697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
175167468Snon		slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
175267468Snon		slp->sl_active = 1;
175367468Snon		slp->sl_powc = SCSI_LOW_POWDOWN_TC;
175467468Snon	}
175567468Snon
175667468Snon	/* reset current nexus */
175767468Snon	scsi_low_reset_nexus(slp, flags);
175867468Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
175979697Snon	{
176079697Snon		rv = EBUSY;
176179697Snon		goto out;
176279697Snon	}
176367468Snon
176479697Snon	if (flags != SCSI_LOW_RESTART_SOFT)
176579697Snon	{
176679697Snon		rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
176779697Snon	}
176867468Snon
176979697Snonout:
177079697Snon	slp->sl_flags &= ~HW_INITIALIZING;
177179697Snon	return rv;
177267468Snon}
177367468Snon
177467468Snon/**************************************************************
177567468Snon * allocate lun_info
177667468Snon **************************************************************/
177767468Snonstatic struct lun_info *
177867468Snonscsi_low_alloc_li(ti, lun, alloc)
177967468Snon	struct targ_info *ti;
178067468Snon	int lun;
178167468Snon	int alloc;
178267468Snon{
178379697Snon	struct scsi_low_softc *slp = ti->ti_sc;
178467468Snon	struct lun_info *li;
178567468Snon
178667468Snon	li = LIST_FIRST(&ti->ti_litab);
178767468Snon	if (li != NULL)
178867468Snon	{
178967468Snon		if (li->li_lun == lun)
179067468Snon			return li;
179167468Snon
179267468Snon		while ((li = LIST_NEXT(li, lun_chain)) != NULL)
179367468Snon		{
179467468Snon			if (li->li_lun == lun)
179567468Snon			{
179667468Snon				LIST_REMOVE(li, lun_chain);
179767468Snon				LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
179867468Snon				return li;
179967468Snon			}
180067468Snon		}
180167468Snon	}
180267468Snon
180367468Snon	if (alloc == 0)
180467468Snon		return li;
180567468Snon
180679697Snon	li = SCSI_LOW_MALLOC(ti->ti_lunsize);
180767468Snon	if (li == NULL)
180867468Snon		panic("no lun info mem\n");
180967468Snon
181079697Snon	SCSI_LOW_BZERO(li, ti->ti_lunsize);
181167468Snon	li->li_lun = lun;
181267468Snon	li->li_ti = ti;
181367468Snon
181479697Snon	li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
181579697Snon			  SCSI_LOW_QTAG;
181679697Snon	li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
181779697Snon	li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
181879697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
181979697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
182079697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
182179697Snon
182279697Snon	li->li_qtagbits = (u_int) -1;
182379697Snon
182479697Snon	TAILQ_INIT(&li->li_discq);
182567468Snon	LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
182667468Snon
182779697Snon	/* host specific structure initialization per lun */
182879697Snon	if (slp->sl_funcs->scsi_low_lun_init != NULL)
182979697Snon		(*slp->sl_funcs->scsi_low_lun_init)
183079697Snon			(slp, ti, li, SCSI_LOW_INFO_ALLOC);
183179697Snon	scsi_low_calcf_lun(li);
183267468Snon	return li;
183367468Snon}
183467468Snon
183567468Snon/**************************************************************
183667468Snon * allocate targ_info
183767468Snon **************************************************************/
183867468Snonstatic struct targ_info *
183979697Snonscsi_low_alloc_ti(slp, targ)
184067468Snon	struct scsi_low_softc *slp;
184179697Snon	int targ;
184267468Snon{
184367468Snon	struct targ_info *ti;
184467468Snon
184571999Sphk	if (TAILQ_FIRST(&slp->sl_titab) == NULL)
184667468Snon		TAILQ_INIT(&slp->sl_titab);
184767468Snon
184879697Snon	ti = SCSI_LOW_MALLOC(slp->sl_targsize);
184967468Snon	if (ti == NULL)
185067468Snon		panic("%s short of memory\n", slp->sl_xname);
185167468Snon
185279697Snon	SCSI_LOW_BZERO(ti, slp->sl_targsize);
185367468Snon	ti->ti_id = targ;
185467468Snon	ti->ti_sc = slp;
185567468Snon
185667468Snon	slp->sl_ti[targ] = ti;
185767468Snon	TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
185867468Snon	LIST_INIT(&ti->ti_litab);
185967468Snon
186079697Snon	ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
186179697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
186279697Snon	ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
186379697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
186479697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
186579697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
186673025Snon
186779697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
186879697Snon	{
186979697Snon		(*slp->sl_funcs->scsi_low_targ_init)
187079697Snon			(slp, ti, SCSI_LOW_INFO_ALLOC);
187179697Snon	}
187279697Snon	scsi_low_calcf_target(ti);
187367468Snon	return ti;
187467468Snon}
187567468Snon
187667468Snonstatic void
187767468Snonscsi_low_free_ti(slp)
187867468Snon	struct scsi_low_softc *slp;
187967468Snon{
188067468Snon	struct targ_info *ti, *tib;
188167468Snon	struct lun_info *li, *nli;
188267468Snon
188371999Sphk	for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
188467468Snon	{
188567468Snon		for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
188667468Snon		{
188779697Snon			if (slp->sl_funcs->scsi_low_lun_init != NULL)
188879697Snon			{
188979697Snon				(*slp->sl_funcs->scsi_low_lun_init)
189079697Snon					(slp, ti, li, SCSI_LOW_INFO_DEALLOC);
189179697Snon			}
189267468Snon			nli = LIST_NEXT(li, lun_chain);
189379697Snon			SCSI_LOW_FREE(li);
189467468Snon		}
189579697Snon
189679697Snon		if (slp->sl_funcs->scsi_low_targ_init != NULL)
189779697Snon		{
189879697Snon			(*slp->sl_funcs->scsi_low_targ_init)
189979697Snon				(slp, ti, SCSI_LOW_INFO_DEALLOC);
190079697Snon		}
190179697Snon		tib = TAILQ_NEXT(ti, ti_chain);
190279697Snon		SCSI_LOW_FREE(ti);
190367468Snon	}
190467468Snon}
190567468Snon
190667468Snon/**************************************************************
190767468Snon * timeout
190867468Snon **************************************************************/
190967468Snonvoid
191079697Snonscsi_low_bus_idle(slp)
191179697Snon	struct scsi_low_softc *slp;
191279697Snon{
191379697Snon
191479697Snon	slp->sl_retry_sel = 0;
191579697Snon	if (slp->sl_Tnexus == NULL)
191679697Snon		scsi_low_start(slp);
191779697Snon}
191879697Snon
191979697Snonstatic void
192067468Snonscsi_low_timeout(arg)
192167468Snon	void *arg;
192267468Snon{
192367468Snon	struct scsi_low_softc *slp = arg;
192479697Snon	int s;
192579697Snon
192679697Snon	s = SCSI_LOW_SPLSCSI();
192779697Snon	(void) scsi_low_timeout_check(slp);
192879697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
192979697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
193079697Snon	splx(s);
193179697Snon}
193279697Snon
193379697Snonstatic int
193479697Snonscsi_low_timeout_check(slp)
193579697Snon	struct scsi_low_softc *slp;
193679697Snon{
193767468Snon	struct targ_info *ti;
193879697Snon	struct lun_info *li;
193967468Snon	struct slccb *cb = NULL;		/* XXX */
194067468Snon
194179697Snon	/* selection restart */
194279697Snon	if (slp->sl_retry_sel != 0)
194367468Snon	{
194479697Snon		slp->sl_retry_sel = 0;
194579697Snon		if (slp->sl_Tnexus != NULL)
194679697Snon			goto step1;
194767468Snon
194879697Snon		cb = TAILQ_FIRST(&slp->sl_start);
194979697Snon		if (cb == NULL)
195079697Snon			goto step1;
195179697Snon
195279697Snon		if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
195367468Snon		{
195479697Snon			cb->ccb_flags |= CCB_NORETRY;
195579697Snon			cb->ccb_error |= SELTIMEOUTIO;
195679697Snon			if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
195779697Snon				panic("%s: ccb not finished\n", slp->sl_xname);
195867468Snon		}
195979697Snon
196079697Snon		if (slp->sl_Tnexus == NULL)
196179697Snon			scsi_low_start(slp);
196267468Snon	}
196379697Snon
196479697Snon	/* call hardware timeout */
196579697Snonstep1:
196679697Snon	if (slp->sl_funcs->scsi_low_timeout != NULL)
196767468Snon	{
196879697Snon		(*slp->sl_funcs->scsi_low_timeout) (slp);
196979697Snon	}
197079697Snon
197179697Snon	if (slp->sl_timeout_count ++ <
197279697Snon	    SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
197379697Snon		return 0;
197479697Snon
197579697Snon	slp->sl_timeout_count = 0;
197679697Snon	if (slp->sl_nio > 0)
197779697Snon	{
197879697Snon		if ((cb = slp->sl_Qnexus) != NULL)
197967468Snon		{
198067468Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
198167468Snon			if (cb->ccb_tc < 0)
198267468Snon				goto bus_reset;
198367468Snon		}
198479697Snon		else if (slp->sl_disc == 0)
198567468Snon		{
198679697Snon		        if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
198779697Snon				return 0;
198867468Snon
198979697Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
199079697Snon			if (cb->ccb_tc < 0)
199179697Snon				goto bus_reset;
199279697Snon		}
199379697Snon		else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
199479697Snon		          ti = TAILQ_NEXT(ti, ti_chain))
199579697Snon		{
199679697Snon			if (ti->ti_disc == 0)
199779697Snon				continue;
199867468Snon
199979697Snon			for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
200079697Snon			     li = LIST_NEXT(li, lun_chain))
200167468Snon			{
200279697Snon				for (cb = TAILQ_FIRST(&li->li_discq);
200379697Snon				     cb != NULL;
200479697Snon				     cb = TAILQ_NEXT(cb, ccb_chain))
200579697Snon				{
200679697Snon					cb->ccb_tc -=
200779697Snon						SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
200879697Snon					if (cb->ccb_tc < 0)
200979697Snon						goto bus_reset;
201079697Snon				}
201167468Snon			}
201267468Snon		}
201379697Snon
201467468Snon	}
201579697Snon	else if ((slp->sl_flags & HW_POWERCTRL) != 0)
201679697Snon	{
201779697Snon		if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
201879697Snon			return 0;
201967468Snon
202079697Snon		if (slp->sl_active != 0)
202179697Snon		{
202279697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
202379697Snon			slp->sl_active = 0;
202479697Snon			return 0;
202579697Snon		}
202667468Snon
202779697Snon		slp->sl_powc --;
202879697Snon		if (slp->sl_powc < 0)
202979697Snon		{
203079697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
203179697Snon			slp->sl_flags |= HW_POWDOWN;
203279697Snon			(*slp->sl_funcs->scsi_low_power)
203379697Snon					(slp, SCSI_LOW_POWDOWN);
203479697Snon		}
203579697Snon	}
203679697Snon	return 0;
203767468Snon
203867468Snonbus_reset:
203967468Snon	cb->ccb_error |= TIMEOUTIO;
204079697Snon	printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb);
204167468Snon	scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
204267468Snon	scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
204367468Snon	scsi_low_start(slp);
204479697Snon	return ERESTART;
204567468Snon}
204667468Snon
204767468Snon
204879697Snonstatic int
204979697Snonscsi_low_abort_ccb(slp, cb)
205079697Snon	struct scsi_low_softc *slp;
205179697Snon	struct slccb *cb;
205279697Snon{
205379697Snon	struct targ_info *ti;
205479697Snon	struct lun_info *li;
205579697Snon	u_int msg;
205667468Snon
205779697Snon	if (cb == NULL)
205879697Snon		return EINVAL;
205979697Snon	if ((cb->ccb_omsgoutflag &
206079697Snon	     (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
206179697Snon		return EBUSY;
206267468Snon
206379697Snon	ti = cb->ti;
206479697Snon	li = cb->li;
206579697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
206679697Snon		msg = SCSI_LOW_MSG_ABORT;
206779697Snon	else
206879697Snon		msg = SCSI_LOW_MSG_ABORT_QTAG;
206967468Snon
207079697Snon	cb->ccb_error |= ABORTIO;
207179697Snon	cb->ccb_flags |= CCB_NORETRY;
207279697Snon	scsi_low_ccb_message_assert(cb, msg);
207367468Snon
207479697Snon	if (cb == slp->sl_Qnexus)
207579697Snon	{
207679697Snon		scsi_low_assert_msg(slp, ti, msg, 1);
207779697Snon	}
207879697Snon	else if ((cb->ccb_flags & CCB_DISCQ) != 0)
207979697Snon	{
208079697Snon		if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
208179697Snon			panic("%s: revoked ccb done\n", slp->sl_xname);
208267468Snon
208379697Snon		cb->ccb_flags |= CCB_STARTQ;
208479697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
208567468Snon
208679697Snon		if (slp->sl_Tnexus == NULL)
208779697Snon			scsi_low_start(slp);
208879697Snon	}
208979697Snon	else
209079697Snon	{
209179697Snon		if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
209279697Snon			panic("%s: revoked ccb retried\n", slp->sl_xname);
209379697Snon	}
209479697Snon	return 0;
209567468Snon}
209667468Snon
209779697Snon/**************************************************************
209879697Snon * Generic SCSI INTERFACE
209979697Snon **************************************************************/
210067468Snonint
210179697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
210267468Snon	struct scsi_low_softc *slp;
210379697Snon	int openings, ntargs, nluns, targsize, lunsize;
210467468Snon{
210567468Snon	struct targ_info *ti;
210667468Snon	struct lun_info *li;
210779697Snon	int s, i, nccb, rv;
210867468Snon
210979697Snon#ifdef	SCSI_LOW_INTERFACE_XS
211079697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs;
211179697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
211279697Snon#ifdef	SCSI_LOW_INTERFACE_CAM
211379697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam;
211479697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
211579697Snon
211679697Snon	if (slp->sl_osdep_fp == NULL)
211779697Snon		panic("scsi_low: interface not spcified\n");
211879697Snon
211967468Snon	if (ntargs > SCSI_LOW_NTARGETS)
212067468Snon	{
212167468Snon		printf("scsi_low: %d targets are too large\n", ntargs);
212267468Snon		printf("change kernel options SCSI_LOW_NTARGETS");
212379697Snon		return EINVAL;
212467468Snon	}
212567468Snon
212679697Snon	if (openings <= 0)
212779697Snon		slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
212879697Snon	else
212979697Snon		slp->sl_openings = openings;
213079697Snon	slp->sl_ntargs = ntargs;
213179697Snon	slp->sl_nluns = nluns;
213279697Snon	slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
213367468Snon
213479697Snon	if (lunsize < sizeof(struct lun_info))
213579697Snon		lunsize = sizeof(struct lun_info);
213679697Snon
213779697Snon	if (targsize < sizeof(struct targ_info))
213879697Snon		targsize = sizeof(struct targ_info);
213979697Snon
214079697Snon	slp->sl_targsize = targsize;
214167468Snon	for (i = 0; i < ntargs; i ++)
214267468Snon	{
214379697Snon		ti = scsi_low_alloc_ti(slp, i);
214479697Snon		ti->ti_lunsize = lunsize;
214567468Snon		li = scsi_low_alloc_li(ti, 0, 1);
214667468Snon	}
214767468Snon
214867468Snon	/* initialize queue */
214979697Snon	nccb = openings * ntargs;
215067468Snon	if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
215167468Snon		nccb = SCSI_LOW_NCCB;
215267468Snon	scsi_low_init_ccbque(nccb);
215367468Snon	TAILQ_INIT(&slp->sl_start);
215467468Snon
215579697Snon	/* call os depend attach */
215679697Snon	s = SCSI_LOW_SPLSCSI();
215779697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp);
215879697Snon	if (rv != 0)
215979697Snon	{
216079697Snon		splx(s);
216179697Snon		printf("%s: scsi_low_attach: osdep attach failed\n",
216279697Snon			slp->sl_xname);
216379697Snon		return EINVAL;
216479697Snon	}
216567468Snon
216679697Snon	/* check hardware */
216779697Snon	SCSI_LOW_DELAY(1000);	/* wait for 1ms */
216879697Snon	if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
216979697Snon	{
217079697Snon		splx(s);
217179697Snon		printf("%s: scsi_low_attach: initialization failed\n",
217279697Snon			slp->sl_xname);
217379697Snon		return EINVAL;
217479697Snon	}
217567468Snon
217667468Snon	/* start watch dog */
217779697Snon	slp->sl_timeout_count = 0;
217879697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
217979697Snon		 (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
218079697Snon	LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
218167468Snon
218279697Snon	/* fake call */
218379697Snon	scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
218467468Snon
218579697Snon#ifdef	SCSI_LOW_START_UP_CHECK
218679697Snon	/* probing devices */
218779697Snon	scsi_low_start_up(slp);
218879697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
218967468Snon
219079697Snon	/* call os depend attach done*/
219179697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp);
219279697Snon	splx(s);
219379697Snon	return 0;
219467468Snon}
219567468Snon
219667468Snonint
219767468Snonscsi_low_dettach(slp)
219867468Snon	struct scsi_low_softc *slp;
219967468Snon{
220079697Snon	int s, rv;
220167468Snon
220279697Snon	s = SCSI_LOW_SPLSCSI();
220379697Snon	if (scsi_low_is_busy(slp) != 0)
220479697Snon	{
220579697Snon		splx(s);
220667468Snon		return EBUSY;
220779697Snon	}
220867468Snon
220979697Snon	scsi_low_deactivate(slp);
221067468Snon
221179697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp);
221279697Snon	if (rv != 0)
221379697Snon	{
221479697Snon		splx(s);
221579697Snon		return EBUSY;
221679697Snon	}
221767468Snon
221867468Snon	scsi_low_free_ti(slp);
221979697Snon	LIST_REMOVE(slp, sl_chain);
222079697Snon	splx(s);
222167468Snon	return 0;
222267468Snon}
222367468Snon
222479697Snon/**************************************************************
222579697Snon * Generic enqueue
222679697Snon **************************************************************/
222779697Snonstatic int
222879697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg)
222979697Snon	struct scsi_low_softc *slp;
223067468Snon	struct targ_info *ti;
223167468Snon	struct lun_info *li;
223267468Snon	struct slccb *cb;
223379697Snon	u_int flags, msg;
223479697Snon{
223567468Snon
223679697Snon	cb->ti = ti;
223779697Snon	cb->li = li;
223867468Snon
223979697Snon	scsi_low_ccb_message_assert(cb, msg);
224067468Snon
224179697Snon	cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
224279697Snon	scsi_low_alloc_qtag(cb);
224367468Snon
224479697Snon	cb->ccb_flags = flags | CCB_STARTQ;
224579697Snon	cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
224679697Snon	cb->ccb_error |= PENDINGIO;
224779697Snon
224879697Snon	if ((flags & CCB_URGENT) != 0)
224979697Snon	{
225079697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
225179697Snon	}
225279697Snon	else
225379697Snon	{
225467468Snon		TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
225579697Snon	}
225667468Snon
225779697Snon	slp->sl_nio ++;
225867468Snon
225979697Snon	if (slp->sl_Tnexus == NULL)
226079697Snon		scsi_low_start(slp);
226179697Snon	return 0;
226279697Snon}
226367468Snon
226479697Snonstatic int
226579697Snonscsi_low_message_enqueue(slp, ti, li, flags)
226679697Snon	struct scsi_low_softc *slp;
226779697Snon	struct targ_info *ti;
226879697Snon	struct lun_info *li;
226979697Snon	u_int flags;
227079697Snon{
227179697Snon	struct slccb *cb;
227279697Snon	u_int tmsgflags;
227367468Snon
227479697Snon	tmsgflags = ti->ti_setup_msg;
227579697Snon	ti->ti_setup_msg = 0;
227667468Snon
227779697Snon	flags |= CCB_NORETRY;
227879697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
227979697Snon		return ENOMEM;
228067468Snon
228179697Snon	cb->osdep = NULL;
228279697Snon	cb->bp = NULL;
228379697Snon	scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
228479697Snon	return 0;
228579697Snon}
228667468Snon
228779697Snon/**************************************************************
228879697Snon * Generic Start & Done
228979697Snon **************************************************************/
229079697Snon#define	SLSC_MODE_SENSE_SHORT   0x1a
229179697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
229279697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
229379697Snon			      sizeof(struct scsi_low_mode_sense_data), 0};
229479697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
229579697Snon			      sizeof(struct scsi_low_inq_data), 0};
229679697Snonstatic u_int8_t unit_ready_cmd[6];
229792770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
229892770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
229992770Salfredstatic int scsi_low_resume(struct scsi_low_softc *);
230079697Snon
230179697Snonstatic void
230279697Snonscsi_low_unit_ready_cmd(cb)
230379697Snon	struct slccb *cb;
230479697Snon{
230579697Snon
230679697Snon	cb->ccb_scp.scp_cmd = unit_ready_cmd;
230779697Snon	cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
230879697Snon	cb->ccb_scp.scp_datalen = 0;
230979697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
231079697Snon	cb->ccb_tcmax = 15;
231167468Snon}
231279697Snon
231367468Snonstatic int
231479697Snonscsi_low_sense_abort_start(slp, ti, li, cb)
231579697Snon	struct scsi_low_softc *slp;
231667468Snon	struct targ_info *ti;
231779697Snon	struct lun_info *li;
231867468Snon	struct slccb *cb;
231979697Snon{
232067468Snon
232179697Snon	cb->ccb_scp.scp_cmdlen = 6;
232279697Snon	SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
232379697Snon	cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
232479697Snon	cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
232579697Snon	cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
232679697Snon	cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
232779697Snon	cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
232879697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
232979697Snon	cb->ccb_tcmax = 15;
233079697Snon	scsi_low_ccb_message_clear(cb);
233179697Snon	if ((cb->ccb_flags & CCB_CLEARQ) != 0)
233267468Snon	{
233379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
233467468Snon	}
233579697Snon	else
233679697Snon	{
233779697Snon		SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense));
233879697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
233979697Snon		scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
234079697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
234179697Snon	}
234267468Snon
234379697Snon	return SCSI_LOW_START_NO_QTAG;
234479697Snon}
234567468Snon
234679697Snonstatic int
234779697Snonscsi_low_setup_start(slp, ti, li, cb)
234879697Snon	struct scsi_low_softc *slp;
234979697Snon	struct targ_info *ti;
235079697Snon	struct lun_info *li;
235179697Snon	struct slccb *cb;
235279697Snon{
235367468Snon
235479697Snon	switch(li->li_state)
235579697Snon	{
235679697Snon	case SCSI_LOW_LUN_SLEEP:
235779697Snon		scsi_low_unit_ready_cmd(cb);
235879697Snon		break;
235967468Snon
236079697Snon	case SCSI_LOW_LUN_START:
236179697Snon		cb->ccb_scp.scp_cmd = ss_cmd;
236279697Snon		cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
236379697Snon		cb->ccb_scp.scp_datalen = 0;
236479697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
236579697Snon		cb->ccb_tcmax = 30;
236679697Snon		break;
236767468Snon
236879697Snon	case SCSI_LOW_LUN_INQ:
236979697Snon		cb->ccb_scp.scp_cmd = inq_cmd;
237079697Snon		cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
237179697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
237279697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
237379697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
237479697Snon		cb->ccb_tcmax = 15;
237579697Snon		break;
237667468Snon
237779697Snon	case SCSI_LOW_LUN_MODEQ:
237879697Snon		cb->ccb_scp.scp_cmd = sms_cmd;
237979697Snon		cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
238079697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
238179697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
238279697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
238379697Snon		cb->ccb_tcmax = 15;
238479697Snon		return SCSI_LOW_START_QTAG;
238567468Snon
238679697Snon	default:
238779697Snon		panic("%s: no setup phase\n", slp->sl_xname);
238867468Snon	}
238967468Snon
239079697Snon	return SCSI_LOW_START_NO_QTAG;
239167468Snon}
239267468Snon
239379697Snonstatic int
239479697Snonscsi_low_resume(slp)
239579697Snon	struct scsi_low_softc *slp;
239667468Snon{
239767468Snon
239879697Snon	if (slp->sl_flags & HW_RESUME)
239979697Snon		return EJUSTRETURN;
240079697Snon	slp->sl_flags &= ~HW_POWDOWN;
240179697Snon	if (slp->sl_funcs->scsi_low_power != NULL)
240279697Snon	{
240379697Snon		slp->sl_flags |= HW_RESUME;
240479697Snon		slp->sl_rstep = 0;
240579697Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
240679697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
240779697Snon					(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE,
240879697Snon				         SCSI_LOW_TIMEOUT_START);
240979697Snon		return EJUSTRETURN;
241079697Snon	}
241179697Snon	return 0;
241267468Snon}
241367468Snon
241467468Snonstatic void
241567468Snonscsi_low_start(slp)
241667468Snon	struct scsi_low_softc *slp;
241767468Snon{
241867468Snon	struct targ_info *ti;
241967468Snon	struct lun_info *li;
242067468Snon	struct slccb *cb;
242167468Snon	int rv;
242267468Snon
242379697Snon	/* check hardware exists or under initializations ? */
242479697Snon	if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
242567468Snon		return;
242667468Snon
242767468Snon	/* check hardware power up ? */
242867468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
242967468Snon	{
243067468Snon		slp->sl_active ++;
243167468Snon		if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
243267468Snon		{
243379697Snon			if (scsi_low_resume(slp) == EJUSTRETURN)
243467468Snon				return;
243567468Snon		}
243667468Snon	}
243767468Snon
243867468Snon	/* setup nexus */
243967468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
244079697Snon	if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
244167468Snon	{
244267468Snon		scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
244379697Snon		panic("%s: inconsistent\n", slp->sl_xname);
244467468Snon	}
244567468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
244667468Snon
244779697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
244879697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
244967468Snon	{
245067468Snon		li = cb->li;
245179697Snon
245279697Snon		if (li->li_disc == 0)
245379697Snon		{
245467468Snon			goto scsi_low_cmd_start;
245579697Snon		}
245679697Snon		else if (li->li_nqio > 0)
245779697Snon		{
245879697Snon			if (li->li_nqio < li->li_maxnqio ||
245979697Snon		            (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
246079697Snon				goto scsi_low_cmd_start;
246179697Snon		}
246267468Snon	}
246367468Snon	return;
246467468Snon
246567468Snonscsi_low_cmd_start:
246679697Snon	cb->ccb_flags &= ~CCB_STARTQ;
246779697Snon	TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
246879697Snon	ti = cb->ti;
246967468Snon
247067468Snon	/* clear all error flag bits (for restart) */
247167468Snon	cb->ccb_error = 0;
247279697Snon	cb->ccb_datalen = -1;
247379697Snon	cb->ccb_scp.scp_status = ST_UNKNOWN;
247467468Snon
247567468Snon	/* setup nexus pointer */
247679697Snon	slp->sl_Qnexus = cb;
247779697Snon	slp->sl_Lnexus = li;
247879697Snon	slp->sl_Tnexus = ti;
247967468Snon
248067468Snon	/* initialize msgsys */
248167468Snon	scsi_low_init_msgsys(slp, ti);
248267468Snon
248379697Snon	/* exec cmd */
248479697Snon	if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
248567468Snon	{
248679697Snon		/* CA state or forced abort */
248779697Snon		rv = scsi_low_sense_abort_start(slp, ti, li, cb);
248867468Snon	}
248979697Snon	else if (li->li_state >= SCSI_LOW_LUN_OK)
249067468Snon	{
249179697Snon		cb->ccb_flags &= ~CCB_INTERNAL;
249279697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb);
249379697Snon		if (cb->ccb_msgoutflag != 0)
249479697Snon		{
249579697Snon			scsi_low_ccb_message_exec(slp, cb);
249679697Snon		}
249767468Snon	}
249879697Snon	else
249967468Snon	{
250079697Snon		cb->ccb_flags |= CCB_INTERNAL;
250179697Snon		rv = scsi_low_setup_start(slp, ti, li, cb);
250279697Snon	}
250367468Snon
250479697Snon	/* allocate qtag */
250579697Snon#define	SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
250667468Snon
250779697Snon	if (rv == SCSI_LOW_START_QTAG &&
250879697Snon	    (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
250979697Snon	    li->li_maxnqio > 0)
251079697Snon	{
251179697Snon		u_int qmsg;
251267468Snon
251379697Snon		scsi_low_activate_qtag(cb);
251479697Snon		if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
251579697Snon		     SCSI_LOW_CMD_ORDERED_QTAG) != 0)
251679697Snon			qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
251779697Snon		else if ((cb->ccb_flags & CCB_URGENT) != 0)
251879697Snon			qmsg = SCSI_LOW_MSG_HEAD_QTAG;
251979697Snon		else
252079697Snon			qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
252179697Snon		scsi_low_assert_msg(slp, ti, qmsg, 0);
252267468Snon	}
252367468Snon
252467468Snon	/* timeout */
252567468Snon	if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
252667468Snon		cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
252767468Snon	cb->ccb_tc = cb->ccb_tcmax;
252867468Snon
252967468Snon	/* setup saved scsi data pointer */
253067468Snon	cb->ccb_sscp = cb->ccb_scp;
253167468Snon
253267468Snon	/* setup current scsi pointer */
253367468Snon	slp->sl_scp = cb->ccb_sscp;
253467468Snon	slp->sl_error = cb->ccb_error;
253567468Snon
253679697Snon	/* assert always an identify msg */
253779697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
253879697Snon
253979697Snon	/* debug section */
254079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
254179697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
254279697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
254379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
254479697Snon
254567468Snon	/* selection start */
254679697Snon	slp->sl_selid = cb;
254767468Snon	rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
254867468Snon	if (rv == SCSI_LOW_START_OK)
254967468Snon	{
255067468Snon#ifdef	SCSI_LOW_STATICS
255167468Snon		scsi_low_statics.nexus_win ++;
255267468Snon#endif	/* SCSI_LOW_STATICS */
255367468Snon		return;
255467468Snon	}
255567468Snon
255679697Snon	scsi_low_arbit_fail(slp, cb);
255767468Snon#ifdef	SCSI_LOW_STATICS
255867468Snon	scsi_low_statics.nexus_fail ++;
255967468Snon#endif	/* SCSI_LOW_STATICS */
256067468Snon}
256167468Snon
256267468Snonvoid
256379697Snonscsi_low_arbit_fail(slp, cb)
256467468Snon	struct scsi_low_softc *slp;
256579697Snon	struct slccb *cb;
256679697Snon{
256779697Snon	struct targ_info *ti = cb->ti;
256879697Snon
256979697Snon	scsi_low_deactivate_qtag(cb);
257079697Snon	scsi_low_ccb_message_retry(cb);
257179697Snon	cb->ccb_flags |= CCB_STARTQ;
257279697Snon	TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
257379697Snon
257479697Snon	scsi_low_bus_release(slp, ti);
257579697Snon
257679697Snon	cb->ccb_selrcnt ++;
257779697Snon	if (slp->sl_disc == 0)
257879697Snon	{
257979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
258079697Snon		printf("%s: try selection again\n", slp->sl_xname);
258179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
258279697Snon		slp->sl_retry_sel = 1;
258379697Snon	}
258479697Snon}
258579697Snon
258679697Snonstatic void
258779697Snonscsi_low_bus_release(slp, ti)
258879697Snon	struct scsi_low_softc *slp;
258967468Snon	struct targ_info *ti;
259067468Snon{
259167468Snon
259279697Snon	if (ti->ti_disc > 0)
259379697Snon	{
259479697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
259579697Snon	}
259679697Snon	else
259779697Snon	{
259879697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
259979697Snon	}
260079697Snon
260167468Snon	/* clear all nexus pointer */
260279697Snon	slp->sl_Qnexus = NULL;
260379697Snon	slp->sl_Lnexus = NULL;
260479697Snon	slp->sl_Tnexus = NULL;
260567468Snon
260667468Snon	/* clear selection assert */
260767468Snon	slp->sl_selid = NULL;
260867468Snon
260967468Snon	/* clear nexus data */
261067468Snon	slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
261179697Snon
261279697Snon	/* clear phase change counter */
261379697Snon	slp->sl_ph_count = 0;
261467468Snon}
261567468Snon
261667468Snonstatic int
261779697Snonscsi_low_setup_done(slp, cb)
261867468Snon	struct scsi_low_softc *slp;
261967468Snon	struct slccb *cb;
262067468Snon{
262167468Snon	struct targ_info *ti;
262267468Snon	struct lun_info *li;
262367468Snon
262467468Snon	ti = cb->ti;
262567468Snon	li = cb->li;
262679697Snon
262779697Snon	if (cb->ccb_rcnt >= slp->sl_max_retry)
262867468Snon	{
262979697Snon		cb->ccb_error |= ABORTIO;
263079697Snon		return SCSI_LOW_DONE_COMPLETE;
263179697Snon	}
263279697Snon
263379697Snon	/* XXX: special huck for selection timeout */
263479697Snon	if (li->li_state == SCSI_LOW_LUN_SLEEP &&
263579697Snon	    (cb->ccb_error & SELTIMEOUTIO) != 0)
263679697Snon	{
263779697Snon		cb->ccb_error |= ABORTIO;
263879697Snon		return SCSI_LOW_DONE_COMPLETE;
263979697Snon	}
264079697Snon
264179697Snon	switch(li->li_state)
264279697Snon	{
264379697Snon	case SCSI_LOW_LUN_INQ:
264479697Snon		if (cb->ccb_error != 0)
264567468Snon		{
264679697Snon			li->li_diskflags &=
264779697Snon				~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
264879697Snon			if (li->li_lun > 0)
264979697Snon				goto resume;
265079697Snon			ti->ti_diskflags &=
265179697Snon				~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
265267468Snon		}
265379697Snon		else if ((li->li_inq.sd_version & 7) >= 2 ||
265479697Snon		         (li->li_inq.sd_len >= 4))
265567468Snon		{
265679697Snon			if ((li->li_inq.sd_support & 0x2) == 0)
265779697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
265879697Snon			if ((li->li_inq.sd_support & 0x8) == 0)
265979697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
266079697Snon			if (li->li_lun > 0)
266179697Snon				goto resume;
266279697Snon			if ((li->li_inq.sd_support & 0x10) == 0)
266379697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
266479697Snon			if ((li->li_inq.sd_support & 0x20) == 0)
266579697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
266679697Snon			if ((li->li_inq.sd_support & 0x40) == 0)
266779697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
266879697Snon		}
266979697Snon		else
267079697Snon		{
267179697Snon			li->li_diskflags &=
267279697Snon				~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
267379697Snon			if (li->li_lun > 0)
267479697Snon				goto resume;
267579697Snon			ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
267679697Snon		}
267779697Snon		ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
267879697Snonresume:
267979697Snon		scsi_low_calcf_target(ti);
268079697Snon		scsi_low_calcf_lun(li);
268179697Snon		break;
268279697Snon
268379697Snon	case SCSI_LOW_LUN_MODEQ:
268479697Snon		if (cb->ccb_error != 0)
268579697Snon		{
268679697Snon			if (cb->ccb_error & SENSEIO)
268767468Snon			{
268879697Snon#ifdef	SCSI_LOW_DEBUG
268979697Snon				if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
269079697Snon				{
269179697Snon					printf("SENSE: [%x][%x][%x][%x][%x]\n",
269279697Snon					(u_int) cb->ccb_sense.error_code,
269379697Snon					(u_int) cb->ccb_sense.segment,
269479697Snon					(u_int) cb->ccb_sense.flags,
269579697Snon					(u_int) cb->ccb_sense.add_sense_code,
269679697Snon					(u_int) cb->ccb_sense.add_sense_code_qual);
269779697Snon				}
269879697Snon#endif	/* SCSI_LOW_DEBUG */
269967468Snon			}
270079697Snon			else
270179697Snon			{
270279697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
270379697Snon			}
270479697Snon		}
270579697Snon		else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
270679697Snon		{
270779697Snon			if (li->li_sms.sms_cmp.cmp_qc & 0x02)
270879697Snon				li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
270979697Snon			else
271079697Snon				li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
271179697Snon			if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
271279697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
271379697Snon		}
271479697Snon		li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
271579697Snon		scsi_low_calcf_lun(li);
271679697Snon		break;
271767468Snon
271879697Snon	default:
271979697Snon		break;
272079697Snon	}
272179697Snon
272279697Snon	li->li_state ++;
272379697Snon	if (li->li_state == SCSI_LOW_LUN_OK)
272479697Snon	{
272579697Snon		scsi_low_calcf_target(ti);
272679697Snon		scsi_low_calcf_lun(li);
272779697Snon		if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
272879697Snon	            (slp->sl_show_result & SHOW_CALCF_RES) != 0)
272979697Snon		{
273079697Snon			scsi_low_calcf_show(li);
273179697Snon		}
273279697Snon	}
273379697Snon
273479697Snon	cb->ccb_rcnt --;
273579697Snon	return SCSI_LOW_DONE_RETRY;
273679697Snon}
273779697Snon
273879697Snonstatic int
273979697Snonscsi_low_done(slp, cb)
274079697Snon	struct scsi_low_softc *slp;
274179697Snon	struct slccb *cb;
274279697Snon{
274379697Snon	int rv;
274479697Snon
274579697Snon	if (cb->ccb_error == 0)
274679697Snon	{
274779697Snon		if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
274879697Snon		{
274979697Snon#ifdef	SCSI_LOW_QCLEAR_AFTER_CA
275079697Snon			/* XXX:
275179697Snon			 * SCSI-2 draft suggests
275279697Snon			 * page 0x0a QErr bit determins if
275379697Snon			 * the target aborts or continues
275479697Snon			 * the queueing io's after CA state resolved.
275579697Snon			 * However many targets seem not to support
275679697Snon			 * the page 0x0a. Thus we should manually clear the
275779697Snon			 * queuing io's after CA state.
275879697Snon			 */
275979697Snon			if ((cb->ccb_flags & CCB_CLEARQ) == 0)
276067468Snon			{
276179697Snon				cb->ccb_rcnt --;
276279697Snon				cb->ccb_flags |= CCB_CLEARQ;
276379697Snon				goto retry;
276479697Snon			}
276579697Snon#endif	/* SCSI_LOW_QCLEAR_AFTER_CA */
276679697Snon
276779697Snon			if ((cb->ccb_flags & CCB_SENSE) != 0)
276879697Snon				cb->ccb_error |= (SENSEIO | ABORTIO);
276979697Snon			cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
277079697Snon		}
277179697Snon		else switch (cb->ccb_sscp.scp_status)
277279697Snon		{
277379697Snon		case ST_GOOD:
277479697Snon		case ST_MET:
277579697Snon		case ST_INTERGOOD:
277679697Snon		case ST_INTERMET:
277779697Snon			if (cb->ccb_datalen == 0 ||
277879697Snon			    cb->ccb_scp.scp_datalen == 0)
277967468Snon				break;
278067468Snon
278179697Snon			if (cb->ccb_scp.scp_cmdlen > 0 &&
278279697Snon			    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
278379697Snon			     SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
278479697Snon				break;
278579697Snon
278667468Snon			cb->ccb_error |= PDMAERR;
278767468Snon			break;
278867468Snon
278979697Snon		case ST_BUSY:
279079697Snon		case ST_QUEFULL:
279179697Snon			cb->ccb_error |= (BUSYERR | STATERR);
279279697Snon			break;
279379697Snon
279479697Snon		case ST_CONFLICT:
279579697Snon			cb->ccb_error |= (STATERR | ABORTIO);
279679697Snon			break;
279779697Snon
279867468Snon		case ST_CHKCOND:
279979697Snon		case ST_CMDTERM:
280079697Snon			if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
280179697Snon			{
280279697Snon				cb->ccb_rcnt --;
280373025Snon				cb->ccb_flags |= CCB_SENSE;
280473025Snon				goto retry;
280573025Snon			}
280679697Snon			cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
280773025Snon			break;
280867468Snon
280979697Snon		case ST_UNKNOWN:
281067468Snon		default:
281167468Snon			cb->ccb_error |= FATALIO;
281267468Snon			break;
281367468Snon		}
281467468Snon	}
281567468Snon	else
281667468Snon	{
281779697Snon		if (cb->ccb_flags & CCB_SENSE)
281867468Snon		{
281979697Snon			cb->ccb_error |= (SENSEERR | ABORTIO);
282067468Snon		}
282179697Snon		cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
282279697Snon	}
282367468Snon
282479697Snon	/* internal ccb */
282579697Snon	if ((cb->ccb_flags & CCB_INTERNAL) != 0)
282679697Snon	{
282779697Snon		if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
282879697Snon			goto retry;
282967468Snon	}
283067468Snon
283179697Snon	/* check a ccb msgout flag */
283279697Snon	if (cb->ccb_omsgoutflag != 0)
283367468Snon	{
283479697Snon#define	SCSI_LOW_MSG_ABORT_OK	(SCSI_LOW_MSG_ABORT | \
283579697Snon				 SCSI_LOW_MSG_ABORT_QTAG | \
283679697Snon				 SCSI_LOW_MSG_CLEAR_QTAG | \
283779697Snon				 SCSI_LOW_MSG_TERMIO)
283879697Snon
283979697Snon		if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
284067468Snon		{
284179697Snon			cb->ccb_error |= ABORTIO;
284267468Snon		}
284367468Snon	}
284467468Snon
284579697Snon	/* call OS depend done */
284679697Snon	if (cb->osdep != NULL)
284767468Snon	{
284879697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb);
284979697Snon		if (rv == EJUSTRETURN)
285079697Snon			goto retry;
285167468Snon	}
285279697Snon	else if (cb->ccb_error != 0)
285367468Snon	{
285479697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
285579697Snon			cb->ccb_error |= ABORTIO;
285679697Snon
285779697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
285879697Snon		    (cb->ccb_error & ABORTIO) == 0)
285967468Snon			goto retry;
286067468Snon	}
286179697Snon
286279697Snon	/* free our target */
286379697Snon#ifdef	SCSI_LOW_DEBUG
286479697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
286567468Snon	{
286679697Snon		printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
286779697Snon		scsi_low_print(slp, NULL);
286867468Snon	}
286979697Snon#endif	/* SCSI_LOW_DEBUG */
287067468Snon
287179697Snon	scsi_low_deactivate_qtag(cb);
287279697Snon	scsi_low_dealloc_qtag(cb);
287367468Snon	scsi_low_free_ccb(cb);
287479697Snon	slp->sl_nio --;
287567468Snon	return SCSI_LOW_DONE_COMPLETE;
287667468Snon
287767468Snonretry:
287879697Snon#ifdef	SCSI_LOW_DEBUG
287979697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
288067468Snon	{
288179697Snon		printf("** SCSI_LOW_DONE_RETRY ===============\n");
288279697Snon		scsi_low_print(slp, NULL);
288367468Snon	}
288479697Snon#endif	/* SCSI_LOW_DEBUG */
288579697Snon
288679697Snon	cb->ccb_rcnt ++;
288779697Snon	scsi_low_deactivate_qtag(cb);
288879697Snon	scsi_low_ccb_message_retry(cb);
288967468Snon	return SCSI_LOW_DONE_RETRY;
289067468Snon}
289167468Snon
289267468Snon/**************************************************************
289367468Snon * Reset
289467468Snon **************************************************************/
289567468Snonstatic void
289679697Snonscsi_low_reset_nexus_target(slp, ti, fdone)
289779697Snon	struct scsi_low_softc *slp;
289879697Snon	struct targ_info *ti;
289979697Snon	int fdone;
290067468Snon{
290179697Snon	struct lun_info *li;
290267468Snon
290379697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
290479697Snon	     li = LIST_NEXT(li, lun_chain))
290579697Snon	{
290679697Snon		scsi_low_reset_nexus_lun(slp, li, fdone);
290779697Snon		li->li_state = SCSI_LOW_LUN_SLEEP;
290879697Snon		li->li_maxnqio = 0;
290979697Snon	}
291079697Snon
291179697Snon	ti->ti_disc = 0;
291279697Snon	ti->ti_setup_msg = 0;
291379697Snon	ti->ti_setup_msg_done = 0;
291479697Snon
291579697Snon	ti->ti_osynch.offset = ti->ti_osynch.period = 0;
291679697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
291779697Snon
291879697Snon	ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
291979697Snon	ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
292079697Snon
292179697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
292279697Snon	{
292379697Snon		((*slp->sl_funcs->scsi_low_targ_init)
292479697Snon			(slp, ti, SCSI_LOW_INFO_REVOKE));
292579697Snon	}
292679697Snon	scsi_low_calcf_target(ti);
292779697Snon
292879697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
292979697Snon	     li = LIST_NEXT(li, lun_chain))
293079697Snon	{
293179697Snon		li->li_flags = 0;
293279697Snon
293379697Snon		li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
293479697Snon		li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
293579697Snon
293679697Snon		if (slp->sl_funcs->scsi_low_lun_init != NULL)
293779697Snon		{
293879697Snon			((*slp->sl_funcs->scsi_low_lun_init)
293979697Snon				(slp, ti, li, SCSI_LOW_INFO_REVOKE));
294079697Snon		}
294179697Snon		scsi_low_calcf_lun(li);
294279697Snon	}
294367468Snon}
294467468Snon
294567468Snonstatic void
294667468Snonscsi_low_reset_nexus(slp, fdone)
294767468Snon	struct scsi_low_softc *slp;
294867468Snon	int fdone;
294967468Snon{
295067468Snon	struct targ_info *ti;
295179697Snon	struct slccb *cb, *topcb;
295267468Snon
295379697Snon	if ((cb = slp->sl_Qnexus) != NULL)
295467468Snon	{
295579697Snon		topcb = scsi_low_revoke_ccb(slp, cb, fdone);
295667468Snon	}
295779697Snon	else
295879697Snon	{
295979697Snon		topcb = NULL;
296079697Snon	}
296167468Snon
296279697Snon	for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
296379697Snon	     ti = TAILQ_NEXT(ti, ti_chain))
296467468Snon	{
296579697Snon		scsi_low_reset_nexus_target(slp, ti, fdone);
296679697Snon		scsi_low_bus_release(slp, ti);
296767468Snon		scsi_low_init_msgsys(slp, ti);
296867468Snon	}
296967468Snon
297079697Snon	if (topcb != NULL)
297179697Snon	{
297279697Snon		topcb->ccb_flags |= CCB_STARTQ;
297379697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
297479697Snon	}
297579697Snon
297679697Snon	slp->sl_disc = 0;
297779697Snon	slp->sl_retry_sel = 0;
297867468Snon	slp->sl_flags &= ~HW_PDMASTART;
297967468Snon}
298067468Snon
298167468Snon/* misc */
298267468Snonstatic int tw_pos;
298367468Snonstatic char tw_chars[] = "|/-\\";
298479697Snon#define	TWIDDLEWAIT		10000
298567468Snon
298667468Snonstatic void
298767468Snonscsi_low_twiddle_wait(void)
298867468Snon{
298967468Snon
299067468Snon	cnputc('\b');
299167468Snon	cnputc(tw_chars[tw_pos++]);
299267468Snon	tw_pos %= (sizeof(tw_chars) - 1);
299379697Snon	SCSI_LOW_DELAY(TWIDDLEWAIT);
299467468Snon}
299567468Snon
299667468Snonvoid
299767468Snonscsi_low_bus_reset(slp)
299867468Snon	struct scsi_low_softc *slp;
299967468Snon{
300067468Snon	int i;
300167468Snon
300267468Snon	(*slp->sl_funcs->scsi_low_bus_reset) (slp);
300367468Snon
300467468Snon	printf("%s: try to reset scsi bus  ", slp->sl_xname);
300567468Snon	for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++)
300667468Snon		scsi_low_twiddle_wait();
300767468Snon	cnputc('\b');
300867468Snon	printf("\n");
300967468Snon}
301067468Snon
301167468Snonint
301267468Snonscsi_low_restart(slp, flags, s)
301367468Snon	struct scsi_low_softc *slp;
301467468Snon	int flags;
301567468Snon	u_char *s;
301667468Snon{
301767468Snon	int error;
301867468Snon
301967468Snon	if (s != NULL)
302067468Snon		printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s);
302167468Snon
302267468Snon	if ((error = scsi_low_init(slp, flags)) != 0)
302367468Snon		return error;
302467468Snon
302567468Snon	scsi_low_start(slp);
302667468Snon	return 0;
302767468Snon}
302867468Snon
302967468Snon/**************************************************************
303067468Snon * disconnect and reselect
303167468Snon **************************************************************/
303267468Snon#define	MSGCMD_LUN(msg)	(msg & 0x07)
303367468Snon
303467468Snonstatic struct slccb *
303567468Snonscsi_low_establish_ccb(ti, li, tag)
303667468Snon	struct targ_info *ti;
303767468Snon	struct lun_info *li;
303867468Snon	scsi_low_tag_t tag;
303967468Snon{
304067468Snon	struct scsi_low_softc *slp = ti->ti_sc;
304167468Snon	struct slccb *cb;
304267468Snon
304379697Snon	if (li == NULL)
304479697Snon		return NULL;
304579697Snon
304679697Snon	cb = TAILQ_FIRST(&li->li_discq);
304771999Sphk	for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
304879697Snon		if (cb->ccb_tag == tag)
304967468Snon			goto found;
305067468Snon	return cb;
305167468Snon
305267468Snon	/*
305367468Snon	 * establish our ccb nexus
305467468Snon	 */
305567468Snonfound:
305679697Snon#ifdef	SCSI_LOW_DEBUG
305779697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
305879697Snon	{
305979697Snon		printf("%s: nexus(0x%lx) abort check start\n",
306079697Snon			slp->sl_xname, (u_long) cb);
306179697Snon		cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
306279697Snon		scsi_low_revoke_ccb(slp, cb, 1);
306379697Snon		return NULL;
306479697Snon	}
306567468Snon
306679697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
306779697Snon	{
306879697Snon		if (cb->ccb_omsgoutflag == 0)
306979697Snon			scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
307079697Snon	}
307179697Snon#endif	/* SCSI_LOW_DEBUG */
307279697Snon
307379697Snon	TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
307479697Snon	cb->ccb_flags &= ~CCB_DISCQ;
307579697Snon	slp->sl_Qnexus = cb;
307679697Snon
307767468Snon	slp->sl_scp = cb->ccb_sscp;
307867468Snon	slp->sl_error |= cb->ccb_error;
307967468Snon
308067468Snon	slp->sl_disc --;
308179697Snon	ti->ti_disc --;
308267468Snon	li->li_disc --;
308367468Snon
308467468Snon	/* inform "ccb nexus established" to the host driver */
308579697Snon	(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
308679697Snon
308779697Snon	/* check msg */
308879697Snon	if (cb->ccb_msgoutflag != 0)
308979697Snon	{
309079697Snon		scsi_low_ccb_message_exec(slp, cb);
309179697Snon	}
309279697Snon
309367468Snon	return cb;
309467468Snon}
309567468Snon
309667468Snonstruct targ_info *
309767468Snonscsi_low_reselected(slp, targ)
309867468Snon	struct scsi_low_softc *slp;
309967468Snon	u_int targ;
310067468Snon{
310167468Snon	struct targ_info *ti;
310279697Snon	struct slccb *cb;
310367468Snon	u_char *s;
310467468Snon
310567468Snon	/*
310667468Snon	 * Check select vs reselected collision.
310767468Snon	 */
310867468Snon
310979697Snon	if ((cb = slp->sl_selid) != NULL)
311067468Snon	{
311179697Snon		scsi_low_arbit_fail(slp, cb);
311267468Snon#ifdef	SCSI_LOW_STATICS
311367468Snon		scsi_low_statics.nexus_conflict ++;
311467468Snon#endif	/* SCSI_LOW_STATICS */
311567468Snon	}
311679697Snon
311779697Snon	/*
311879697Snon	 * Check if no current active nexus.
311979697Snon	 */
312079697Snon	if (slp->sl_Tnexus != NULL)
312167468Snon	{
312267468Snon		s = "host busy";
312367468Snon		goto world_restart;
312467468Snon	}
312567468Snon
312667468Snon	/*
312767468Snon	 * Check a valid target id asserted ?
312867468Snon	 */
312967468Snon	if (targ >= slp->sl_ntargs || targ == slp->sl_hostid)
313067468Snon	{
313167468Snon		s = "scsi id illegal";
313267468Snon		goto world_restart;
313367468Snon	}
313467468Snon
313567468Snon	/*
313667468Snon	 * Check the target scsi status.
313767468Snon	 */
313867468Snon	ti = slp->sl_ti[targ];
313979697Snon	if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
314067468Snon	{
314167468Snon		s = "phase mismatch";
314267468Snon		goto world_restart;
314367468Snon	}
314467468Snon
314567468Snon	/*
314679697Snon	 * Setup init msgsys
314767468Snon	 */
314867468Snon	slp->sl_error = 0;
314967468Snon	scsi_low_init_msgsys(slp, ti);
315067468Snon
315167468Snon	/*
315267468Snon	 * Establish our target nexus
315367468Snon	 */
315467468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
315579697Snon	slp->sl_Tnexus = ti;
315667468Snon#ifdef	SCSI_LOW_STATICS
315767468Snon	scsi_low_statics.nexus_reselected ++;
315867468Snon#endif	/* SCSI_LOW_STATICS */
315967468Snon	return ti;
316067468Snon
316167468Snonworld_restart:
316267468Snon	printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s);
316367468Snon	scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
316467468Snon		         "reselect: scsi world confused");
316567468Snon	return NULL;
316667468Snon}
316767468Snon
316867468Snon/**************************************************************
316967468Snon * cmd out pointer setup
317067468Snon **************************************************************/
317167468Snonint
317267468Snonscsi_low_cmd(slp, ti)
317367468Snon	struct scsi_low_softc *slp;
317467468Snon	struct targ_info *ti;
317567468Snon{
317679697Snon	struct slccb *cb = slp->sl_Qnexus;
317767468Snon
317879697Snon	slp->sl_ph_count ++;
317967468Snon	if (cb == NULL)
318067468Snon	{
318167468Snon		/*
318279697Snon		 * no ccb, abort!
318367468Snon		 */
318467468Snon		slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
318567468Snon		slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
318667468Snon		slp->sl_scp.scp_datalen = 0;
318767468Snon		slp->sl_scp.scp_direction = SCSI_LOW_READ;
318879697Snon		slp->sl_error |= FATALIO;
318979697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
319079697Snon		SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
319179697Snon		return EINVAL;
319267468Snon	}
319379697Snon	else
319467468Snon	{
319579697Snon#ifdef	SCSI_LOW_DEBUG
319679697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
319779697Snon		{
319879697Snon			scsi_low_test_cmdlnk(slp, cb);
319979697Snon		}
320079697Snon#endif	/* SCSI_LOW_DEBUG */
320167468Snon	}
320267468Snon	return 0;
320367468Snon}
320467468Snon
320567468Snon/**************************************************************
320667468Snon * data out pointer setup
320767468Snon **************************************************************/
320867468Snonint
320967468Snonscsi_low_data(slp, ti, bp, direction)
321067468Snon	struct scsi_low_softc *slp;
321167468Snon	struct targ_info *ti;
321267468Snon	struct buf **bp;
321367468Snon	int direction;
321467468Snon{
321579697Snon	struct slccb *cb = slp->sl_Qnexus;
321667468Snon
321779697Snon	if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
321867468Snon	{
321979697Snon		*bp = cb->bp;
322079697Snon		return 0;
322167468Snon	}
322267468Snon
322379697Snon	slp->sl_error |= (FATALIO | PDMAERR);
322479697Snon	slp->sl_scp.scp_datalen = 0;
322579697Snon	slp->sl_scp.scp_direction = direction;
322679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
322779697Snon	if (ti->ti_ophase != ti->ti_phase)
322867468Snon	{
322979697Snon		char *s;
323079697Snon
323179697Snon		if (cb == NULL)
323279697Snon			s = "DATA PHASE: ccb nexus not found";
323379697Snon		else
323479697Snon			s = "DATA PHASE: xfer direction mismatch";
323579697Snon		SCSI_LOW_INFO(slp, ti, s);
323667468Snon	}
323767468Snon
323879697Snon	*bp = NULL;
323979697Snon	return EINVAL;
324067468Snon}
324167468Snon
324267468Snon/**************************************************************
324367468Snon * MSG_SYS
324467468Snon **************************************************************/
324567468Snon#define	MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
324667468Snon#define	MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
324767468Snon#define	MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
324879697Snon#define	MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
324967468Snon#define	MSGIN_DATA_LAST	0x30
325067468Snon
325192770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int);
325292770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int);
325392770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int);
325492770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int);
325567468Snon
325692770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *);
325792770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *);
325892770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *);
325992770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *);
326092770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *);
326192770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *);
326292770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *);
326367468Snon
326467468Snonstruct scsi_low_msgout_data {
326567468Snon	u_int	md_flags;
326667468Snon	u_int8_t md_msg;
326792770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
326892770Salfred	int (*md_errfunc)(struct scsi_low_softc *, u_int);
326979697Snon#define	MSG_RELEASE_ATN	0x0001
327079697Snon	u_int md_condition;
327167468Snon};
327267468Snon
327367468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = {
327479697Snon/* 0 */	{SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
327579697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
327679697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
327779697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
327879697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
327979697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
328079697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
328179697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG,  MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
328279697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
328379697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG,  MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
328479697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL,  MSG_RELEASE_ATN},
328579697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
328679697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
328779697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
328879697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
328979697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0},
329067468Snon};
329167468Snon
329292770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *);
329392770Salfredstatic int scsi_low_synch(struct scsi_low_softc *);
329492770Salfredstatic int scsi_low_wide(struct scsi_low_softc *);
329592770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *);
329692770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *);
329792770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *);
329892770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *);
329992770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *);
330092770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *);
330192770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *);
330292770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *);
330392770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *);
330492770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *);
330592770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *);
330667468Snon
330767468Snonstruct scsi_low_msgin_data {
330867468Snon	u_int md_len;
330992770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
331067468Snon};
331167468Snon
331267468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = {
331367468Snon/* 0 */	{1,	scsi_low_msginfunc_cc},
331467468Snon/* 1 */ {2,	scsi_low_msginfunc_ext},
331567468Snon/* 2 */ {1,	scsi_low_msginfunc_sdp},
331679697Snon/* 3 */ {1,	scsi_low_msginfunc_rp},
331767468Snon/* 4 */ {1,	scsi_low_msginfunc_disc},
331867468Snon/* 5 */ {1,	scsi_low_msginfunc_rejop},
331967468Snon/* 6 */ {1,	scsi_low_msginfunc_rejop},
332067468Snon/* 7 */ {1,	scsi_low_msginfunc_msg_reject},
332167468Snon/* 8 */ {1,	scsi_low_msginfunc_noop},
332267468Snon/* 9 */ {1,	scsi_low_msginfunc_parity},
332379697Snon/* a */ {1,	scsi_low_msginfunc_lcc},
332479697Snon/* b */ {1,	scsi_low_msginfunc_lcc},
332567468Snon/* c */ {1,	scsi_low_msginfunc_rejop},
332667468Snon/* d */ {2,	scsi_low_msginfunc_rejop},
332767468Snon/* e */ {1,	scsi_low_msginfunc_rejop},
332867468Snon/* f */ {1,	scsi_low_msginfunc_rejop},
332967468Snon/* 0x10 */ {1,	scsi_low_msginfunc_rejop},
333067468Snon/* 0x11 */ {1,	scsi_low_msginfunc_rejop},
333167468Snon/* 0x12 */ {1,	scsi_low_msginfunc_rejop},
333267468Snon/* 0x13 */ {1,	scsi_low_msginfunc_rejop},
333367468Snon/* 0x14 */ {1,	scsi_low_msginfunc_rejop},
333467468Snon/* 0x15 */ {1,	scsi_low_msginfunc_rejop},
333567468Snon/* 0x16 */ {1,	scsi_low_msginfunc_rejop},
333667468Snon/* 0x17 */ {1,	scsi_low_msginfunc_rejop},
333767468Snon/* 0x18 */ {1,	scsi_low_msginfunc_rejop},
333867468Snon/* 0x19 */ {1,	scsi_low_msginfunc_rejop},
333967468Snon/* 0x1a */ {1,	scsi_low_msginfunc_rejop},
334067468Snon/* 0x1b */ {1,	scsi_low_msginfunc_rejop},
334167468Snon/* 0x1c */ {1,	scsi_low_msginfunc_rejop},
334267468Snon/* 0x1d */ {1,	scsi_low_msginfunc_rejop},
334367468Snon/* 0x1e */ {1,	scsi_low_msginfunc_rejop},
334467468Snon/* 0x1f */ {1,	scsi_low_msginfunc_rejop},
334579697Snon/* 0x20 */ {2,	scsi_low_msginfunc_simple_qtag},
334667468Snon/* 0x21 */ {2,	scsi_low_msginfunc_rejop},
334767468Snon/* 0x22 */ {2,	scsi_low_msginfunc_rejop},
334879697Snon/* 0x23 */ {2,	scsi_low_msginfunc_i_wide_residue},
334967468Snon/* 0x24 */ {2,	scsi_low_msginfunc_rejop},
335067468Snon/* 0x25 */ {2,	scsi_low_msginfunc_rejop},
335167468Snon/* 0x26 */ {2,	scsi_low_msginfunc_rejop},
335267468Snon/* 0x27 */ {2,	scsi_low_msginfunc_rejop},
335367468Snon/* 0x28 */ {2,	scsi_low_msginfunc_rejop},
335467468Snon/* 0x29 */ {2,	scsi_low_msginfunc_rejop},
335567468Snon/* 0x2a */ {2,	scsi_low_msginfunc_rejop},
335667468Snon/* 0x2b */ {2,	scsi_low_msginfunc_rejop},
335767468Snon/* 0x2c */ {2,	scsi_low_msginfunc_rejop},
335867468Snon/* 0x2d */ {2,	scsi_low_msginfunc_rejop},
335967468Snon/* 0x2e */ {2,	scsi_low_msginfunc_rejop},
336067468Snon/* 0x2f */ {2,	scsi_low_msginfunc_rejop},
336167468Snon/* 0x30 */ {1,	scsi_low_msginfunc_rejop}	/* default rej op */
336267468Snon};
336367468Snon
336467468Snon/**************************************************************
336567468Snon * msgout
336667468Snon **************************************************************/
336767468Snonstatic int
336879697Snonscsi_low_msgfunc_synch(slp)
336979697Snon	struct scsi_low_softc *slp;
337067468Snon{
337179697Snon	struct targ_info *ti = slp->sl_Tnexus;
337267468Snon	int ptr = ti->ti_msgoutlen;
337367468Snon
337467468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
337567468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
337673025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
337773025Snon	ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset;
337867468Snon	return MSG_EXTEND_SYNCHLEN + 2;
337967468Snon}
338067468Snon
338167468Snonstatic int
338279697Snonscsi_low_msgfunc_wide(slp)
338379697Snon	struct scsi_low_softc *slp;
338467468Snon{
338579697Snon	struct targ_info *ti = slp->sl_Tnexus;
338667468Snon	int ptr = ti->ti_msgoutlen;
338767468Snon
338867468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
338967468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
339073025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
339167468Snon	return MSG_EXTEND_WIDELEN + 2;
339267468Snon}
339367468Snon
339467468Snonstatic int
339579697Snonscsi_low_msgfunc_identify(slp)
339679697Snon	struct scsi_low_softc *slp;
339767468Snon{
339879697Snon	struct targ_info *ti = slp->sl_Tnexus;
339979697Snon	struct lun_info *li = slp->sl_Lnexus;
340079697Snon	struct slccb *cb = slp->sl_Qnexus;
340179697Snon	int ptr = ti->ti_msgoutlen;
340279697Snon	u_int8_t msg;
340367468Snon
340479697Snon	msg = MSG_IDENTIFY;
340579697Snon	if (cb == NULL)
340667468Snon	{
340779697Snon		slp->sl_error |= FATALIO;
340879697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
340979697Snon		SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
341067468Snon	}
341167468Snon	else
341267468Snon	{
341379697Snon		if (scsi_low_is_disconnect_ok(cb) != 0)
341479697Snon			msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
341579697Snon		else
341679697Snon			msg |= li->li_lun;
341779697Snon
341879697Snon		if (ti->ti_phase == PH_MSGOUT)
341979697Snon		{
342079697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
342179697Snon			if (cb->ccb_tag == SCSI_LOW_UNKTAG)
342279697Snon			{
342379697Snon				(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
342479697Snon			}
342579697Snon		}
342667468Snon	}
342779697Snon	ti->ti_msgoutstr[ptr + 0] = msg;
342867468Snon	return 1;
342967468Snon}
343067468Snon
343167468Snonstatic int
343279697Snonscsi_low_msgfunc_abort(slp)
343379697Snon	struct scsi_low_softc *slp;
343467468Snon{
343567468Snon
343679697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
343779697Snon	return 1;
343879697Snon}
343979697Snon
344079697Snonstatic int
344179697Snonscsi_low_msgfunc_qabort(slp)
344279697Snon	struct scsi_low_softc *slp;
344379697Snon{
344479697Snon
344579697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
344679697Snon	return 1;
344779697Snon}
344879697Snon
344979697Snonstatic int
345079697Snonscsi_low_msgfunc_reset(slp)
345179697Snon	struct scsi_low_softc *slp;
345279697Snon{
345379697Snon
345479697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
345579697Snon	return 1;
345679697Snon}
345779697Snon
345879697Snonstatic int
345979697Snonscsi_low_msgfunc_qtag(slp)
346079697Snon	struct scsi_low_softc *slp;
346179697Snon{
346279697Snon	struct targ_info *ti = slp->sl_Tnexus;
346379697Snon	struct slccb *cb = slp->sl_Qnexus;
346479697Snon	int ptr = ti->ti_msgoutlen;
346579697Snon
346679697Snon	if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
346767468Snon	{
346867468Snon		ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
346967468Snon		return 1;
347067468Snon	}
347167468Snon	else
347267468Snon	{
347379697Snon		ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
347479697Snon		if (ti->ti_phase == PH_MSGOUT)
347579697Snon		{
347679697Snon			(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
347779697Snon		}
347867468Snon	}
347979697Snon	return 2;
348067468Snon}
348167468Snon
348267468Snon/*
348367468Snon * The following functions are called when targets give unexpected
348467468Snon * responces in msgin (after msgout).
348567468Snon */
348667468Snonstatic int
348779697Snonscsi_low_errfunc_identify(slp, msgflags)
348879697Snon	struct scsi_low_softc *slp;
348967468Snon	u_int msgflags;
349067468Snon{
349167468Snon
349279697Snon	if (slp->sl_Lnexus != NULL)
349379697Snon	{
349479697Snon	        slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
349579697Snon		scsi_low_calcf_lun(slp->sl_Lnexus);
349679697Snon	}
349767468Snon	return 0;
349867468Snon}
349967468Snon
350067468Snonstatic int
350179697Snonscsi_low_errfunc_synch(slp, msgflags)
350279697Snon	struct scsi_low_softc *slp;
350367468Snon	u_int msgflags;
350467468Snon{
350579697Snon	struct targ_info *ti = slp->sl_Tnexus;
350667468Snon
350767468Snon	MSGIN_PERIOD(ti) = 0;
350867468Snon	MSGIN_OFFSET(ti) = 0;
350979697Snon	scsi_low_synch(slp);
351067468Snon	return 0;
351167468Snon}
351267468Snon
351367468Snonstatic int
351479697Snonscsi_low_errfunc_wide(slp, msgflags)
351579697Snon	struct scsi_low_softc *slp;
351667468Snon	u_int msgflags;
351767468Snon{
351879697Snon	struct targ_info *ti = slp->sl_Tnexus;
351979697Snon
352079697Snon	MSGIN_WIDTHP(ti) = 0;
352179697Snon	scsi_low_wide(slp);
352267468Snon	return 0;
352367468Snon}
352467468Snon
352579697Snonstatic int
352679697Snonscsi_low_errfunc_qtag(slp, msgflags)
352779697Snon	struct scsi_low_softc *slp;
352879697Snon	u_int msgflags;
352979697Snon{
353079697Snon
353179697Snon	if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
353279697Snon	{
353379697Snon		if (slp->sl_Qnexus != NULL)
353479697Snon		{
353579697Snon			scsi_low_deactivate_qtag(slp->sl_Qnexus);
353679697Snon		}
353779697Snon		if (slp->sl_Lnexus != NULL)
353879697Snon		{
353979697Snon			slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
354079697Snon			scsi_low_calcf_lun(slp->sl_Lnexus);
354179697Snon		}
354279697Snon		printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname);
354379697Snon	}
354479697Snon	return 0;
354579697Snon}
354679697Snon
354779697Snon
354867468Snonint
354979697Snonscsi_low_msgout(slp, ti, fl)
355067468Snon	struct scsi_low_softc *slp;
355167468Snon	struct targ_info *ti;
355279697Snon	u_int fl;
355367468Snon{
355467468Snon	struct scsi_low_msgout_data *mdp;
355567468Snon	int len = 0;
355667468Snon
355779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
355879697Snon	if (ti != slp->sl_Tnexus)
355979697Snon	{
356079697Snon		scsi_low_print(slp, NULL);
356179697Snon		panic("scsi_low_msgout: Target nexus inconsistent");
356279697Snon	}
356379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
356479697Snon
356579697Snon	slp->sl_ph_count ++;
356679697Snon	if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
356779697Snon	{
356879697Snon		printf("%s: too many phase changes\n", slp->sl_xname);
356979697Snon		slp->sl_error |= FATALIO;
357079697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
357179697Snon	}
357279697Snon
357367468Snon	/* STEP I.
357467468Snon	 * Scsi phase changes.
357567468Snon	 * Previously msgs asserted are accepted by our target or
357667468Snon	 * processed by scsi_low_msgin.
357767468Snon	 * Thus clear all saved informations.
357867468Snon	 */
357979697Snon	if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
358067468Snon	{
358167468Snon		ti->ti_omsgflags = 0;
358267468Snon		ti->ti_emsgflags = 0;
358367468Snon	}
358479697Snon	else if (slp->sl_atten == 0)
358579697Snon	{
358667468Snon	/* STEP II.
358767468Snon	 * We did not assert attention, however still our target required
358867468Snon	 * msgs. Resend previous msgs.
358967468Snon	 */
359067468Snon		ti->ti_msgflags |= ti->ti_omsgflags;
359179697Snon		ti->ti_omsgflags = 0;
359267468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
359367468Snon		printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname);
359467468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
359567468Snon	}
359667468Snon
359767468Snon	/* STEP III.
359879697Snon	 * We have no msgs. send MSG_NOOP (OK?)
359967468Snon	 */
360079697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
360167468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
360267468Snon
360367468Snon	/* STEP IV.
360467468Snon	 * Process all msgs
360567468Snon	 */
360667468Snon	ti->ti_msgoutlen = 0;
360779697Snon	slp->sl_clear_atten = 0;
360867468Snon	mdp = &scsi_low_msgout_data[0];
360967468Snon	for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
361067468Snon	{
361167468Snon		if ((ti->ti_msgflags & mdp->md_flags) != 0)
361267468Snon		{
361367468Snon			ti->ti_omsgflags |= mdp->md_flags;
361467468Snon			ti->ti_msgflags &= ~mdp->md_flags;
361567468Snon			ti->ti_emsgflags = mdp->md_flags;
361667468Snon
361767468Snon			ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
361867468Snon			if (mdp->md_msgfunc != NULL)
361979697Snon				len = (*mdp->md_msgfunc) (slp);
362067468Snon			else
362167468Snon				len = 1;
362267468Snon
362379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
362479697Snon			scsi_low_msg_log_write(&ti->ti_log_msgout,
362579697Snon			       &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
362679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
362779697Snon
362867468Snon			ti->ti_msgoutlen += len;
362979697Snon			if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
363079697Snon			{
363179697Snon				slp->sl_clear_atten = 1;
363279697Snon				break;
363379697Snon			}
363479697Snon
363579697Snon			if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
363667468Snon			    ti->ti_msgflags == 0)
363767468Snon				break;
363879697Snon
363967468Snon			if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
364067468Snon				break;
364167468Snon		}
364267468Snon	}
364367468Snon
364479697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
364579697Snon		slp->sl_clear_atten = 1;
364667468Snon
364767468Snon	return ti->ti_msgoutlen;
364867468Snon}
364967468Snon
365067468Snon/**************************************************************
365167468Snon * msgin
365267468Snon **************************************************************/
365367468Snonstatic int
365479697Snonscsi_low_msginfunc_noop(slp)
365579697Snon	struct scsi_low_softc *slp;
365667468Snon{
365767468Snon
365867468Snon	return 0;
365967468Snon}
366067468Snon
366167468Snonstatic int
366279697Snonscsi_low_msginfunc_rejop(slp)
366379697Snon	struct scsi_low_softc *slp;
366467468Snon{
366579697Snon	struct targ_info *ti = slp->sl_Tnexus;
366667468Snon	u_int8_t msg = ti->ti_msgin[0];
366767468Snon
366879697Snon	printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg);
366967468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
367067468Snon	return 0;
367167468Snon}
367267468Snon
367367468Snonstatic int
367479697Snonscsi_low_msginfunc_cc(slp)
367579697Snon	struct scsi_low_softc *slp;
367667468Snon{
367779697Snon	struct lun_info *li;
367867468Snon
367967468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
368079697Snon
368179697Snon	/* validate status */
368279697Snon	if (slp->sl_Qnexus == NULL)
368379697Snon		return ENOENT;
368479697Snon
368579697Snon	slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
368679697Snon 	li = slp->sl_Lnexus;
368779697Snon	switch (slp->sl_scp.scp_status)
368879697Snon	{
368979697Snon	case ST_GOOD:
369079697Snon		li->li_maxnqio = li->li_maxnexus;
369179697Snon		break;
369279697Snon
369379697Snon	case ST_CHKCOND:
369479697Snon		li->li_maxnqio = 0;
369579697Snon		if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
369679697Snon			scsi_low_reset_nexus_lun(slp, li, 0);
369779697Snon		break;
369879697Snon
369979697Snon	case ST_BUSY:
370079697Snon		li->li_maxnqio = 0;
370179697Snon		break;
370279697Snon
370379697Snon	case ST_QUEFULL:
370479697Snon		if (li->li_maxnexus >= li->li_nqio)
370579697Snon			li->li_maxnexus = li->li_nqio - 1;
370679697Snon		li->li_maxnqio = li->li_maxnexus;
370779697Snon		break;
370879697Snon
370979697Snon	case ST_INTERGOOD:
371079697Snon	case ST_INTERMET:
371179697Snon		slp->sl_error |= MSGERR;
371279697Snon		break;
371379697Snon
371479697Snon	default:
371579697Snon		break;
371679697Snon	}
371767468Snon	return 0;
371867468Snon}
371967468Snon
372067468Snonstatic int
372179697Snonscsi_low_msginfunc_lcc(slp)
372279697Snon	struct scsi_low_softc *slp;
372379697Snon{
372467468Snon	struct targ_info *ti;
372579697Snon	struct lun_info *li;
372679697Snon	struct slccb *ncb, *cb;
372779697Snon
372879697Snon	ti = slp->sl_Tnexus;
372979697Snon 	li = slp->sl_Lnexus;
373079697Snon	if ((cb = slp->sl_Qnexus) == NULL)
373179697Snon		goto bad;
373279697Snon
373379697Snon	cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
373479697Snon	switch (slp->sl_scp.scp_status)
373579697Snon	{
373679697Snon	case ST_INTERGOOD:
373779697Snon	case ST_INTERMET:
373879697Snon		li->li_maxnqio = li->li_maxnexus;
373979697Snon		break;
374079697Snon
374179697Snon	default:
374279697Snon		slp->sl_error |= MSGERR;
374379697Snon		break;
374479697Snon	}
374579697Snon
374679697Snon	if ((li->li_flags & SCSI_LOW_LINK) == 0)
374779697Snon		goto bad;
374879697Snon
374979697Snon	cb->ccb_error |= slp->sl_error;
375079697Snon	if (cb->ccb_error != 0)
375179697Snon		goto bad;
375279697Snon
375379697Snon	for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
375479697Snon	     ncb = TAILQ_NEXT(ncb, ccb_chain))
375579697Snon	{
375679697Snon		if (ncb->li == li)
375779697Snon			goto cmd_link_start;
375879697Snon	}
375979697Snon
376079697Snon
376179697Snonbad:
376279697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
376379697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
376479697Snon	return EIO;
376579697Snon
376679697Snoncmd_link_start:
376779697Snon	ncb->ccb_flags &= ~CCB_STARTQ;
376879697Snon	TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
376979697Snon
377079697Snon	scsi_low_dealloc_qtag(ncb);
377179697Snon	ncb->ccb_tag = cb->ccb_tag;
377279697Snon	ncb->ccb_otag = cb->ccb_otag;
377379697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
377479697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
377579697Snon	if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
377679697Snon		panic("%s: linked ccb retried\n", slp->sl_xname);
377779697Snon
377879697Snon	slp->sl_Qnexus = ncb;
377979697Snon	slp->sl_ph_count = 0;
378079697Snon
378179697Snon	ncb->ccb_error = 0;
378279697Snon	ncb->ccb_datalen = -1;
378379697Snon	ncb->ccb_scp.scp_status = ST_UNKNOWN;
378479697Snon	ncb->ccb_flags &= ~CCB_INTERNAL;
378579697Snon
378679697Snon	scsi_low_init_msgsys(slp, ti);
378779697Snon
378879697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb);
378979697Snon
379079697Snon	if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
379179697Snon		ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
379279697Snon	ncb->ccb_tc = ncb->ccb_tcmax;
379379697Snon
379479697Snon	/* setup saved scsi data pointer */
379579697Snon	ncb->ccb_sscp = ncb->ccb_scp;
379679697Snon	slp->sl_scp = ncb->ccb_sscp;
379779697Snon	slp->sl_error = ncb->ccb_error;
379879697Snon
379979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
380079697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
380179697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
380279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
380379697Snon	return EJUSTRETURN;
380479697Snon}
380579697Snon
380679697Snonstatic int
380779697Snonscsi_low_msginfunc_disc(slp)
380879697Snon	struct scsi_low_softc *slp;
380967468Snon{
381067468Snon
381167468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
381267468Snon	return 0;
381367468Snon}
381467468Snon
381567468Snonstatic int
381679697Snonscsi_low_msginfunc_sdp(slp)
381779697Snon	struct scsi_low_softc *slp;
381867468Snon{
381979697Snon	struct slccb *cb = slp->sl_Qnexus;
382067468Snon
382179697Snon	if (cb != NULL)
382279697Snon	{
382379697Snon		cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
382479697Snon		cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
382579697Snon	}
382667468Snon	else
382779697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
382867468Snon	return 0;
382967468Snon}
383067468Snon
383167468Snonstatic int
383279697Snonscsi_low_msginfunc_rp(slp)
383379697Snon	struct scsi_low_softc *slp;
383467468Snon{
383567468Snon
383679697Snon	if (slp->sl_Qnexus != NULL)
383779697Snon		slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
383867468Snon	else
383979697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
384067468Snon	return 0;
384167468Snon}
384267468Snon
384367468Snonstatic int
384479697Snonscsi_low_synch(slp)
384579697Snon	struct scsi_low_softc *slp;
384667468Snon{
384779697Snon	struct targ_info *ti = slp->sl_Tnexus;
384879697Snon	u_int period = 0, offset = 0, speed;
384967468Snon	u_char *s;
385067468Snon	int error;
385167468Snon
385279697Snon	if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
385379697Snon	     MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
385479697Snon	     MSGIN_OFFSET(ti) == 0)
385567468Snon	{
385667468Snon		if ((offset = MSGIN_OFFSET(ti)) != 0)
385767468Snon			period = MSGIN_PERIOD(ti);
385867468Snon		s = offset ? "synchronous" : "async";
385967468Snon	}
386067468Snon	else
386167468Snon	{
386267468Snon		/* XXX:
386367468Snon		 * Target seems to be brain damaged.
386467468Snon		 * Force async transfer.
386567468Snon		 */
386673025Snon		ti->ti_maxsynch.period = 0;
386773025Snon		ti->ti_maxsynch.offset = 0;
386867468Snon		printf("%s: target brain damaged. async transfer\n",
386967468Snon			slp->sl_xname);
387067468Snon		return EINVAL;
387167468Snon	}
387267468Snon
387373025Snon	ti->ti_maxsynch.period = period;
387473025Snon	ti->ti_maxsynch.offset = offset;
387567468Snon
387667468Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH);
387767468Snon	if (error != 0)
387867468Snon	{
387967468Snon		/* XXX:
388067468Snon		 * Current period and offset are not acceptable
388167468Snon		 * for our adapter.
388267468Snon		 * The adapter changes max synch and max offset.
388367468Snon		 */
388467468Snon		printf("%s: synch neg failed. retry synch msg neg ...\n",
388567468Snon			slp->sl_xname);
388667468Snon		return error;
388767468Snon	}
388867468Snon
388979697Snon	ti->ti_osynch = ti->ti_maxsynch;
389079697Snon	if (offset > 0)
389179697Snon	{
389279697Snon		ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
389379697Snon	}
389479697Snon
389567468Snon	/* inform data */
389679697Snon	if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
389767468Snon	{
389879697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
389979697Snon		struct slccb *cb = slp->sl_Qnexus;
390079697Snon
390179697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
390279697Snon			return 0;
390379697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
390479697Snon
390579697Snon		printf("%s(%d:*): <%s> offset %d period %dns ",
390679697Snon			slp->sl_xname, ti->ti_id, s, offset, period * 4);
390779697Snon
390879697Snon		if (period != 0)
390979697Snon		{
391079697Snon			speed = 1000 * 10 / (period * 4);
391179697Snon			printf("%d.%d M/s", speed / 10, speed % 10);
391279697Snon		}
391379697Snon		printf("\n");
391467468Snon	}
391579697Snon	return 0;
391679697Snon}
391767468Snon
391879697Snonstatic int
391979697Snonscsi_low_wide(slp)
392079697Snon	struct scsi_low_softc *slp;
392179697Snon{
392279697Snon	struct targ_info *ti = slp->sl_Tnexus;
392379697Snon	int error;
392479697Snon
392579697Snon	ti->ti_width = MSGIN_WIDTHP(ti);
392679697Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
392779697Snon	if (error != 0)
392879697Snon	{
392979697Snon		/* XXX:
393079697Snon		 * Current width is not acceptable for our adapter.
393179697Snon		 * The adapter changes max width.
393279697Snon		 */
393379697Snon		printf("%s: wide neg failed. retry wide msg neg ...\n",
393479697Snon			slp->sl_xname);
393579697Snon		return error;
393679697Snon	}
393779697Snon
393879697Snon	ti->ti_owidth = ti->ti_width;
393979697Snon	if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
394079697Snon	{
394179697Snon		ti->ti_setup_msg_done |=
394279697Snon			(SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
394379697Snon	}
394479697Snon
394579697Snon	/* inform data */
394679697Snon	if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
394779697Snon	{
394879697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
394979697Snon		struct slccb *cb = slp->sl_Qnexus;
395079697Snon
395179697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
395279697Snon			return 0;
395379697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
395479697Snon
395579697Snon		printf("%s(%d:*): transfer width %d bits\n",
395679697Snon			slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width));
395779697Snon	}
395867468Snon	return 0;
395967468Snon}
396067468Snon
396167468Snonstatic int
396279697Snonscsi_low_msginfunc_simple_qtag(slp)
396379697Snon	struct scsi_low_softc *slp;
396467468Snon{
396579697Snon	struct targ_info *ti = slp->sl_Tnexus;
396679697Snon	scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
396779697Snon
396879697Snon	if (slp->sl_Qnexus != NULL)
396979697Snon	{
397079697Snon		if (slp->sl_Qnexus->ccb_tag != etag)
397179697Snon		{
397279697Snon			slp->sl_error |= FATALIO;
397379697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
397479697Snon			SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
397579697Snon		}
397679697Snon	}
397779697Snon	else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
397879697Snon	{
397979697Snon#ifdef	SCSI_LOW_DEBUG
398079697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
398179697Snon			return 0;
398279697Snon#endif	/* SCSI_LOW_DEBUG */
398379697Snon
398479697Snon		slp->sl_error |= FATALIO;
398579697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
398679697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
398779697Snon	}
398879697Snon	return 0;
398979697Snon}
399079697Snon
399179697Snonstatic int
399279697Snonscsi_low_msginfunc_i_wide_residue(slp)
399379697Snon	struct scsi_low_softc *slp;
399479697Snon{
399579697Snon	struct targ_info *ti = slp->sl_Tnexus;
399679697Snon	struct slccb *cb = slp->sl_Qnexus;
399779697Snon	int res = (int) ti->ti_msgin[1];
399879697Snon
399979697Snon	if (cb == NULL || res <= 0 ||
400079697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
400179697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
400279697Snon		return EINVAL;
400379697Snon
400479697Snon	if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
400579697Snon		return EINVAL;
400679697Snon
400779697Snon	slp->sl_scp.scp_datalen += res;
400879697Snon	slp->sl_scp.scp_data -= res;
400979697Snon	scsi_low_data_finish(slp);
401079697Snon	return 0;
401179697Snon}
401279697Snon
401379697Snonstatic int
401479697Snonscsi_low_msginfunc_ext(slp)
401579697Snon	struct scsi_low_softc *slp;
401679697Snon{
401779697Snon	struct slccb *cb = slp->sl_Qnexus;
401879697Snon	struct lun_info *li = slp->sl_Lnexus;
401979697Snon	struct targ_info *ti = slp->sl_Tnexus;
402067468Snon	int count, retry;
402167468Snon	u_int32_t *ptr;
402267468Snon
402367468Snon	if (ti->ti_msginptr == 2)
402467468Snon	{
402567468Snon		ti->ti_msginlen = ti->ti_msgin[1] + 2;
402667468Snon		return 0;
402767468Snon	}
402867468Snon
402967468Snon	switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
403067468Snon	{
403167468Snon	case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
403267468Snon		if (cb == NULL)
403367468Snon			break;
403467468Snon
403567468Snon		ptr = (u_int32_t *)(&ti->ti_msgin[3]);
403667468Snon		count = (int) htonl((long) (*ptr));
403767468Snon		if(slp->sl_scp.scp_datalen - count < 0 ||
403867468Snon		   slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen)
403967468Snon			break;
404067468Snon
404167468Snon		slp->sl_scp.scp_datalen -= count;
404267468Snon		slp->sl_scp.scp_data += count;
404367468Snon		return 0;
404467468Snon
404567468Snon	case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
404667468Snon		if (li == NULL)
404767468Snon			break;
404867468Snon
404979697Snon		retry = scsi_low_synch(slp);
405067468Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
405167468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
405279697Snon
405379697Snon#ifdef	SCSI_LOW_DEBUG
405479697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
405579697Snon		{
405679697Snon			scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
405779697Snon		}
405879697Snon#endif	/* SCSI_LOW_DEBUG */
405967468Snon		return 0;
406067468Snon
406167468Snon	case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
406267468Snon		if (li == NULL)
406367468Snon			break;
406467468Snon
406579697Snon		retry = scsi_low_wide(slp);
406679697Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
406779697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
406879697Snon
406967468Snon		return 0;
407067468Snon
407167468Snon	default:
407267468Snon		break;
407367468Snon	}
407467468Snon
407567468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
407667468Snon	return EINVAL;
407767468Snon}
407867468Snon
407967468Snonstatic int
408079697Snonscsi_low_msginfunc_parity(slp)
408179697Snon	struct scsi_low_softc *slp;
408267468Snon{
408379697Snon	struct targ_info *ti = slp->sl_Tnexus;
408467468Snon
408579697Snon	/* only I -> T, invalid! */
408679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
408767468Snon	return 0;
408867468Snon}
408967468Snon
409067468Snonstatic int
409179697Snonscsi_low_msginfunc_msg_reject(slp)
409279697Snon	struct scsi_low_softc *slp;
409367468Snon{
409479697Snon	struct targ_info *ti = slp->sl_Tnexus;
409567468Snon	struct scsi_low_msgout_data *mdp;
409667468Snon	u_int msgflags;
409767468Snon
409879697Snon	if (ti->ti_emsgflags != 0)
409967468Snon	{
410079697Snon		printf("%s: msg flags [0x%x] rejected\n",
410179697Snon		       slp->sl_xname, ti->ti_emsgflags);
410267468Snon		msgflags = SCSI_LOW_MSG_REJECT;
410367468Snon		mdp = &scsi_low_msgout_data[0];
410467468Snon		for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
410567468Snon		{
410667468Snon			if ((ti->ti_emsgflags & mdp->md_flags) != 0)
410767468Snon			{
410867468Snon				ti->ti_emsgflags &= ~mdp->md_flags;
410967468Snon				if (mdp->md_errfunc != NULL)
411079697Snon					(*mdp->md_errfunc) (slp, msgflags);
411167468Snon				break;
411267468Snon			}
411367468Snon		}
411479697Snon		return 0;
411567468Snon	}
411679697Snon	else
411779697Snon	{
411879697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
411979697Snon		slp->sl_error |= MSGERR;
412079697Snon	}
412179697Snon	return EINVAL;
412267468Snon}
412367468Snon
412479697Snonint
412567468Snonscsi_low_msgin(slp, ti, c)
412667468Snon	struct scsi_low_softc *slp;
412767468Snon	struct targ_info *ti;
412879697Snon	u_int c;
412967468Snon{
413067468Snon	struct scsi_low_msgin_data *sdp;
413167468Snon	struct lun_info *li;
413267468Snon	u_int8_t msg;
413367468Snon
413479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
413579697Snon	if (ti != slp->sl_Tnexus)
413679697Snon	{
413779697Snon		scsi_low_print(slp, NULL);
413879697Snon		panic("scsi_low_msgin: Target nexus inconsistent");
413979697Snon	}
414079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
414179697Snon
414267468Snon	/*
414367468Snon	 * Phase changes, clear the pointer.
414467468Snon	 */
414567468Snon	if (ti->ti_ophase != ti->ti_phase)
414667468Snon	{
414767468Snon		MSGINPTR_CLR(ti);
414879697Snon		ti->ti_msgin_parity_error = 0;
414979697Snon
415079697Snon		slp->sl_ph_count ++;
415179697Snon		if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
415279697Snon		{
415379697Snon			printf("%s: too many phase changes\n", slp->sl_xname);
415479697Snon			slp->sl_error |= FATALIO;
415579697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
415679697Snon		}
415767468Snon	}
415867468Snon
415967468Snon	/*
416067468Snon	 * Store a current messages byte into buffer and
416167468Snon	 * wait for the completion of the current msg.
416267468Snon	 */
416379697Snon	ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
416467468Snon	if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
416567468Snon	{
416667468Snon		ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
416767468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
416867468Snon	}
416967468Snon
417067468Snon	/*
417179697Snon	 * Check parity errors.
417279697Snon	 */
417379697Snon	if ((c & SCSI_LOW_DATA_PE) != 0)
417479697Snon	{
417579697Snon		ti->ti_msgin_parity_error ++;
417679697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
417779697Snon		goto out;
417879697Snon	}
417979697Snon
418079697Snon	if (ti->ti_msgin_parity_error != 0)
418179697Snon		goto out;
418279697Snon
418379697Snon	/*
418467468Snon	 * Calculate messages length.
418567468Snon	 */
418667468Snon	msg = ti->ti_msgin[0];
418767468Snon	if (msg < MSGIN_DATA_LAST)
418867468Snon		sdp = &scsi_low_msgin_data[msg];
418967468Snon	else
419067468Snon		sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST];
419167468Snon
419267468Snon	if (ti->ti_msginlen == 0)
419367468Snon	{
419467468Snon		ti->ti_msginlen = sdp->md_len;
419567468Snon	}
419667468Snon
419767468Snon	/*
419867468Snon	 * Check comletion.
419967468Snon	 */
420067468Snon	if (ti->ti_msginptr < ti->ti_msginlen)
420179697Snon		return EJUSTRETURN;
420267468Snon
420367468Snon	/*
420467468Snon	 * Do process.
420567468Snon	 */
420667468Snon	if ((msg & MSG_IDENTIFY) == 0)
420767468Snon	{
420879697Snon		if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
420979697Snon			return EJUSTRETURN;
421067468Snon	}
421167468Snon	else
421267468Snon	{
421379697Snon		li = slp->sl_Lnexus;
421467468Snon		if (li == NULL)
421567468Snon		{
421679697Snon			li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
421767468Snon			if (li == NULL)
421867468Snon				goto badlun;
421979697Snon			slp->sl_Lnexus = li;
422079697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
422167468Snon		}
422279697Snon		else
422379697Snon		{
422479697Snon			if (MSGCMD_LUN(msg) != li->li_lun)
422579697Snon				goto badlun;
422679697Snon		}
422767468Snon
422879697Snon		if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
422967468Snon		{
423067468Snon			if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
423179697Snon			{
423279697Snon#ifdef	SCSI_LOW_DEBUG
423379697Snon				if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
423479697Snon				{
423579697Snon					goto out;
423679697Snon				}
423779697Snon#endif	/* SCSI_LOW_DEBUG */
423867468Snon				goto badlun;
423979697Snon			}
424067468Snon		}
424167468Snon	}
424279697Snon	goto out;
424367468Snon
424467468Snon	/*
424579697Snon	 * Msg process completed, reset msgin pointer and assert ATN if desired.
424667468Snon	 */
424779697Snonbadlun:
424879697Snon	slp->sl_error |= FATALIO;
424979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
425079697Snon	SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
425179697Snon
425279697Snonout:
425379697Snon	if (ti->ti_msginptr < ti->ti_msginlen)
425479697Snon		return EJUSTRETURN;
425579697Snon
425679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
425779697Snon	scsi_low_msg_log_write(&ti->ti_log_msgin,
425879697Snon			       &ti->ti_msgin[0], ti->ti_msginlen);
425979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
426079697Snon
426179697Snon	MSGINPTR_CLR(ti);
426279697Snon	return 0;
426379697Snon}
426479697Snon
426579697Snon/**********************************************************
426679697Snon * disconnect
426779697Snon **********************************************************/
426879697Snonint
426979697Snonscsi_low_disconnected(slp, ti)
427079697Snon	struct scsi_low_softc *slp;
427179697Snon	struct targ_info *ti;
427279697Snon{
427379697Snon	struct slccb *cb = slp->sl_Qnexus;
427479697Snon
427579697Snon	/* check phase completion */
427679697Snon	switch (slp->sl_msgphase)
427767468Snon	{
427879697Snon	case MSGPH_RESET:
427979697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
428079697Snon		scsi_low_msginfunc_cc(slp);
428179697Snon		scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
428279697Snon		goto io_resume;
428367468Snon
428479697Snon	case MSGPH_ABORT:
428579697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
428679697Snon		scsi_low_msginfunc_cc(slp);
428779697Snon		scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
428879697Snon		goto io_resume;
428979697Snon
429079697Snon	case MSGPH_TERM:
429179697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
429279697Snon		scsi_low_msginfunc_cc(slp);
429379697Snon		goto io_resume;
429479697Snon
429579697Snon	case MSGPH_DISC:
429679697Snon		if (cb != NULL)
429767468Snon		{
429879697Snon			struct lun_info *li;
429979697Snon
430079697Snon			li = cb->li;
430179697Snon			TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
430279697Snon			cb->ccb_flags |= CCB_DISCQ;
430379697Snon			cb->ccb_error |= slp->sl_error;
430479697Snon			li->li_disc ++;
430579697Snon			ti->ti_disc ++;
430679697Snon			slp->sl_disc ++;
430779697Snon		}
430879697Snon
430979697Snon#ifdef	SCSI_LOW_STATICS
431079697Snon		scsi_low_statics.nexus_disconnected ++;
431179697Snon#endif	/* SCSI_LOW_STATICS */
431279697Snon
431379697Snon#ifdef	SCSI_LOW_DEBUG
431479697Snon		if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
431579697Snon		{
431679697Snon			printf("## SCSI_LOW_DISCONNECTED ===============\n");
431779697Snon			scsi_low_print(slp, NULL);
431879697Snon		}
431979697Snon#endif	/* SCSI_LOW_DEBUG */
432079697Snon		break;
432179697Snon
432279697Snon	case MSGPH_NULL:
432379697Snon		slp->sl_error |= FATALIO;
432479697Snon		if (ti->ti_phase == PH_SELSTART)
432579697Snon			slp->sl_error |= SELTIMEOUTIO;
432679697Snon		else
432779697Snon			slp->sl_error |= UBFERR;
432879697Snon		/* fall through */
432979697Snon
433079697Snon	case MSGPH_LCTERM:
433179697Snon	case MSGPH_CMDC:
433279697Snonio_resume:
433379697Snon		if (cb == NULL)
433479697Snon			break;
433579697Snon
433679697Snon#ifdef	SCSI_LOW_DEBUG
433779697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
433879697Snon		{
433979697Snon			if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
434079697Snon			    (cb->ccb_msgoutflag != 0 ||
434179697Snon			     (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
434279697Snon			{
434379697Snon				scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
434479697Snon			}
434579697Snon		}
434679697Snon#endif	/* SCSI_LOW_DEBUG */
434779697Snon
434879697Snon		cb->ccb_error |= slp->sl_error;
434979697Snon		if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
435079697Snon		{
435179697Snon			cb->ccb_flags |= CCB_STARTQ;
435279697Snon			TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
435379697Snon		}
435479697Snon		break;
435579697Snon	}
435679697Snon
435779697Snon	scsi_low_bus_release(slp, ti);
435879697Snon	scsi_low_start(slp);
435979697Snon	return 1;
436079697Snon}
436179697Snon
436279697Snon/**********************************************************
436379697Snon * TAG operations
436479697Snon **********************************************************/
436579697Snonint
436679697Snonscsi_low_alloc_qtag(cb)
436779697Snon	struct slccb *cb;
436879697Snon{
436979697Snon	struct lun_info *li = cb->li;
437079697Snon	scsi_low_tag_t etag;
437179697Snon
437279697Snon	if (cb->ccb_otag != SCSI_LOW_UNKTAG)
437379697Snon		return 0;
437479697Snon
437579697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
437679697Snon	etag = ffs(li->li_qtagbits);
437779697Snon	if (etag == 0)
437879697Snon		return ENOSPC;
437979697Snon
438079697Snon	li->li_qtagbits &= ~(1 << (etag - 1));
438179697Snon	cb->ccb_otag = etag;
438279697Snon	return 0;
438379697Snon
438479697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
438579697Snon	for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
438679697Snon		if (li->li_qtagarray[li->li_qd] == 0)
438779697Snon			goto found;
438879697Snon
438979697Snon	for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
439079697Snon		if (li->li_qtagarray[li->li_qd] == 0)
439179697Snon			goto found;
439279697Snon
439379697Snon	return ENOSPC;
439479697Snon
439579697Snonfound:
439679697Snon	li->li_qtagarray[li->li_qd] ++;
439779697Snon	cb->ccb_otag = (li->li_qd ++);
439879697Snon	return 0;
439979697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
440079697Snon}
440179697Snon
440279697Snonint
440379697Snonscsi_low_dealloc_qtag(cb)
440479697Snon	struct slccb *cb;
440579697Snon{
440679697Snon	struct lun_info *li = cb->li;
440779697Snon	scsi_low_tag_t etag;
440879697Snon
440979697Snon	if (cb->ccb_otag == SCSI_LOW_UNKTAG)
441079697Snon		return 0;
441179697Snon
441279697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
441379697Snon	etag = cb->ccb_otag - 1;
441467468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
441579697Snon	if (etag >= sizeof(li->li_qtagbits) * NBBY)
441679697Snon		panic("scsi_low_dealloc_tag: illegal tag");
441767468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
441879697Snon	li->li_qtagbits |= (1 << etag);
441979697Snon
442079697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
442179697Snon	etag = cb->ccb_otag;
442279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
442379697Snon	if (etag >= SCSI_LOW_MAXNEXUS)
442479697Snon		panic("scsi_low_dealloc_tag: illegal tag");
442579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
442679697Snon	li->li_qtagarray[etag] --;
442779697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
442879697Snon
442979697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
443079697Snon	return 0;
443179697Snon}
443279697Snon
443379697Snonstruct slccb *
443479697Snonscsi_low_revoke_ccb(slp, cb, fdone)
443579697Snon	struct scsi_low_softc *slp;
443679697Snon	struct slccb *cb;
443779697Snon	int fdone;
443879697Snon{
443979697Snon	struct targ_info *ti = cb->ti;
444079697Snon	struct lun_info *li = cb->li;
444179697Snon
444279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
444379697Snon	if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
444479697Snon	    (CCB_STARTQ | CCB_DISCQ))
444579697Snon	{
444679697Snon		panic("%s: ccb in both queue\n", slp->sl_xname);
444767468Snon	}
444879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
444967468Snon
445079697Snon	if ((cb->ccb_flags & CCB_STARTQ) != 0)
445179697Snon	{
445279697Snon		TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
445379697Snon	}
445479697Snon
445579697Snon	if ((cb->ccb_flags & CCB_DISCQ) != 0)
445679697Snon	{
445779697Snon		TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
445879697Snon		li->li_disc --;
445979697Snon		ti->ti_disc --;
446079697Snon		slp->sl_disc --;
446179697Snon	}
446279697Snon
446379697Snon	cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
446479697Snon			   CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
446579697Snon
446679697Snon	if (fdone != 0 &&
446779697Snon	    (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
446879697Snon	     (cb->ccb_flags & CCB_NORETRY) != 0))
446979697Snon	{
447079697Snon		cb->ccb_error |= FATALIO;
447179697Snon		cb->ccb_flags &= ~CCB_AUTOSENSE;
447279697Snon		if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
447379697Snon			panic("%s: done ccb retried\n", slp->sl_xname);
447479697Snon		return NULL;
447579697Snon	}
447679697Snon	else
447779697Snon	{
447879697Snon		cb->ccb_error |= PENDINGIO;
447979697Snon		scsi_low_deactivate_qtag(cb);
448079697Snon		scsi_low_ccb_message_retry(cb);
448179697Snon		cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
448279697Snon		return cb;
448379697Snon	}
448467468Snon}
448567468Snon
448679697Snonvoid
448779697Snonscsi_low_reset_nexus_lun(slp, li, fdone)
448879697Snon	struct scsi_low_softc *slp;
448979697Snon	struct lun_info *li;
449079697Snon	int fdone;
449179697Snon{
449279697Snon	struct slccb *cb, *ncb, *ecb;
449379697Snon
449479697Snon	if (li == NULL)
449579697Snon		return;
449679697Snon
449779697Snon	ecb = NULL;
449879697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
449979697Snon	{
450079697Snon		ncb = TAILQ_NEXT(cb, ccb_chain);
450179697Snon		cb = scsi_low_revoke_ccb(slp, cb, fdone);
450279697Snon		if (cb != NULL)
450379697Snon		{
450479697Snon			/*
450579697Snon			 * presumely keep ordering of io
450679697Snon			 */
450779697Snon			cb->ccb_flags |= CCB_STARTQ;
450879697Snon			if (ecb == NULL)
450979697Snon			{
451079697Snon				TAILQ_INSERT_HEAD(&slp->sl_start,\
451179697Snon						  cb, ccb_chain);
451279697Snon			}
451379697Snon			else
451479697Snon			{
451579697Snon				TAILQ_INSERT_AFTER(&slp->sl_start,\
451679697Snon						   ecb, cb, ccb_chain);
451779697Snon			}
451879697Snon			ecb = cb;
451979697Snon		}
452079697Snon	}
452179697Snon}
452279697Snon
452367468Snon/**************************************************************
452467468Snon * Qurik setup
452567468Snon **************************************************************/
452667468Snonstatic void
452779697Snonscsi_low_calcf_lun(li)
452867468Snon	struct lun_info *li;
452967468Snon{
453079697Snon	struct targ_info *ti = li->li_ti;
453167468Snon	struct scsi_low_softc *slp = ti->ti_sc;
453279697Snon	u_int cfgflags, diskflags;
453367468Snon
453479697Snon	if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
453579697Snon		cfgflags = li->li_cfgflags;
453679697Snon	else
453779697Snon		cfgflags = 0;
453879697Snon
453979697Snon	diskflags = li->li_diskflags & li->li_quirks;
454079697Snon
454179697Snon	/* disconnect */
454267468Snon	li->li_flags &= ~SCSI_LOW_DISC;
454367468Snon	if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
454479697Snon	    (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
454579697Snon	    (cfgflags & SCSI_LOW_DISC) != 0)
454667468Snon		li->li_flags |= SCSI_LOW_DISC;
454767468Snon
454879697Snon	/* parity */
454967468Snon	li->li_flags |= SCSI_LOW_NOPARITY;
455067468Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
455179697Snon	    (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
455279697Snon	    (cfgflags & SCSI_LOW_NOPARITY) == 0)
455367468Snon		li->li_flags &= ~SCSI_LOW_NOPARITY;
455467468Snon
455579697Snon	/* qtag */
455679697Snon	if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
455779697Snon	    (cfgflags & SCSI_LOW_QTAG) != 0 &&
455879697Snon	    (diskflags & SCSI_LOW_DISK_QTAG) != 0)
455979697Snon	{
456079697Snon		li->li_flags |= SCSI_LOW_QTAG;
456179697Snon		li->li_maxnexus = SCSI_LOW_MAXNEXUS;
456279697Snon		li->li_maxnqio = li->li_maxnexus;
456379697Snon	}
456479697Snon	else
456579697Snon	{
456679697Snon		li->li_flags &= ~SCSI_LOW_QTAG;
456779697Snon		li->li_maxnexus = 0;
456879697Snon		li->li_maxnqio = li->li_maxnexus;
456979697Snon	}
457079697Snon
457179697Snon	/* cmd link */
457279697Snon	li->li_flags &= ~SCSI_LOW_LINK;
457379697Snon	if ((cfgflags & SCSI_LOW_LINK) != 0 &&
457479697Snon	    (diskflags & SCSI_LOW_DISK_LINK) != 0)
457579697Snon		li->li_flags |= SCSI_LOW_LINK;
457679697Snon
457779697Snon	/* compatible flags */
457867468Snon	li->li_flags &= ~SCSI_LOW_SYNC;
457979697Snon	if (ti->ti_maxsynch.offset > 0)
458079697Snon		li->li_flags |= SCSI_LOW_SYNC;
458179697Snon
458279697Snon#ifdef	SCSI_LOW_DEBUG
458379697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
458467468Snon	{
458579697Snon		scsi_low_calcf_show(li);
458667468Snon	}
458779697Snon#endif	/* SCSI_LOW_DEBUG */
458879697Snon}
458979697Snon
459079697Snonstatic void
459179697Snonscsi_low_calcf_target(ti)
459279697Snon	struct targ_info *ti;
459379697Snon{
459479697Snon	struct scsi_low_softc *slp = ti->ti_sc;
459579697Snon	u_int offset, period, diskflags;
459679697Snon
459779697Snon	diskflags = ti->ti_diskflags & ti->ti_quirks;
459879697Snon
459979697Snon	/* synch */
460079697Snon	if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
460179697Snon	    (diskflags & SCSI_LOW_DISK_SYNC) != 0)
460279697Snon	{
460379697Snon		offset = ti->ti_maxsynch.offset;
460479697Snon		period = ti->ti_maxsynch.period;
460579697Snon		if (offset == 0 || period == 0)
460679697Snon			offset = period = 0;
460779697Snon	}
460867468Snon	else
460979697Snon	{
461079697Snon		offset = period = 0;
461179697Snon	}
461267468Snon
461379697Snon	ti->ti_maxsynch.offset = offset;
461479697Snon	ti->ti_maxsynch.period = period;
461579697Snon
461679697Snon	/* wide */
461779697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
461879697Snon	     ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
461979697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
462079697Snon
462179697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
462279697Snon	    ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
462379697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
462479697Snon
462579697Snon	if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
462667468Snon	{
462779697Snon		if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
462879697Snon		    ti->ti_maxsynch.period != ti->ti_osynch.period)
462979697Snon			ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
463079697Snon		if (ti->ti_width != ti->ti_owidth)
463179697Snon			ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
463279697Snon
463379697Snon		ti->ti_osynch = ti->ti_maxsynch;
463479697Snon		ti->ti_owidth = ti->ti_width;
463567468Snon	}
463667468Snon
463779697Snon#ifdef	SCSI_LOW_DEBUG
463879697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
463979697Snon	{
464079697Snon		printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n",
464179697Snon			slp->sl_xname, ti->ti_id,
464279697Snon			ti->ti_maxsynch.period * 4,
464379697Snon			ti->ti_maxsynch.offset,
464479697Snon			ti->ti_width);
464579697Snon	}
464679697Snon#endif	/* SCSI_LOW_DEBUG */
464767468Snon}
464867468Snon
464979697Snonstatic void
465079697Snonscsi_low_calcf_show(li)
465179697Snon	struct lun_info *li;
465279697Snon{
465379697Snon	struct targ_info *ti = li->li_ti;
465479697Snon	struct scsi_low_softc *slp = ti->ti_sc;
465579697Snon
465679697Snon	printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
465779697Snon		slp->sl_xname, ti->ti_id, li->li_lun,
465879697Snon		ti->ti_maxsynch.period * 4,
465979697Snon		ti->ti_maxsynch.offset,
466079697Snon		ti->ti_width,
466179697Snon		li->li_flags, SCSI_LOW_BITS);
466279697Snon}
466379697Snon
466479697Snon#ifdef	SCSI_LOW_START_UP_CHECK
466579697Snon/**************************************************************
466679697Snon * scsi world start up
466779697Snon **************************************************************/
466892770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *);
466979697Snon
467067468Snonstatic int
467179697Snonscsi_low_start_up(slp)
467279697Snon	struct scsi_low_softc *slp;
467367468Snon{
467467468Snon	struct targ_info *ti;
467567468Snon	struct lun_info *li;
467679697Snon	struct slccb *cb;
467779697Snon	int target, lun;
467867468Snon
467979697Snon	printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname);
468067468Snon
468179697Snon	for (target = 0; target < slp->sl_ntargs; target ++)
468279697Snon	{
468379697Snon		if (target == slp->sl_hostid)
468479697Snon		{
468579697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
468679697Snon			{
468779697Snon				printf("%s: scsi_low: target %d (host card)\n",
468879697Snon					slp->sl_xname, target);
468979697Snon			}
469079697Snon			continue;
469179697Snon		}
469267468Snon
469379697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
469479697Snon		{
469579697Snon			printf("%s: scsi_low: target %d lun ",
469679697Snon				slp->sl_xname, target);
469779697Snon		}
469867468Snon
469979697Snon		ti = slp->sl_ti[target];
470079697Snon		for (lun = 0; lun < slp->sl_nluns; lun ++)
470179697Snon		{
470279697Snon			if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
470379697Snon				break;
470479697Snon
470579697Snon			cb->osdep = NULL;
470679697Snon			cb->bp = NULL;
470779697Snon
470879697Snon			li = scsi_low_alloc_li(ti, lun, 1);
470979697Snon
471079697Snon			scsi_low_enqueue(slp, ti, li, cb,
471179697Snon					 CCB_AUTOSENSE | CCB_POLLED, 0);
471279697Snon
471379697Snon			scsi_low_poll(slp, cb);
471479697Snon
471579697Snon			if (li->li_state != SCSI_LOW_LUN_OK)
471679697Snon				break;
471779697Snon
471879697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
471979697Snon			{
472079697Snon				printf("%d ", lun);
472179697Snon			}
472279697Snon		}
472379697Snon
472479697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
472579697Snon		{
472679697Snon			printf("\n");
472779697Snon		}
472879697Snon	}
472967468Snon	return 0;
473067468Snon}
473167468Snon
473279697Snonstatic int
473379697Snonscsi_low_poll(slp, cb)
473479697Snon	struct scsi_low_softc *slp;
473579697Snon	struct slccb *cb;
473679697Snon{
473779697Snon	int tcount;
473879697Snon
473979697Snon	tcount = 0;
474079697Snon	while (slp->sl_nio > 0)
474179697Snon	{
474279697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
474379697Snon
474479697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
474579697Snon		if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
474679697Snon			continue;
474779697Snon
474879697Snon		tcount = 0;
474979697Snon		scsi_low_timeout_check(slp);
475079697Snon	}
475179697Snon
475279697Snon	return 0;
475379697Snon}
475479697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
475579697Snon
475667468Snon/**********************************************************
475767468Snon * DEBUG SECTION
475867468Snon **********************************************************/
475979697Snon#ifdef	SCSI_LOW_DEBUG
476067468Snonstatic void
476179697Snonscsi_low_test_abort(slp, ti, li)
476279697Snon	struct scsi_low_softc *slp;
476379697Snon	struct targ_info *ti;
476479697Snon	struct lun_info *li;
476579697Snon{
476679697Snon	struct slccb *acb;
476779697Snon
476879697Snon	if (li->li_disc > 1)
476979697Snon	{
477079697Snon		acb = TAILQ_FIRST(&li->li_discq);
477179697Snon		if (scsi_low_abort_ccb(slp, acb) == 0)
477279697Snon		{
477379697Snon			printf("%s: aborting ccb(0x%lx) start\n",
477479697Snon				slp->sl_xname, (u_long) acb);
477579697Snon		}
477679697Snon	}
477779697Snon}
477879697Snon
477979697Snonstatic void
478079697Snonscsi_low_test_atten(slp, ti, msg)
478179697Snon	struct scsi_low_softc *slp;
478279697Snon	struct targ_info *ti;
478379697Snon	u_int msg;
478479697Snon{
478579697Snon
478679697Snon	if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
478779697Snon		scsi_low_assert_msg(slp, ti, msg, 0);
478879697Snon	else
478979697Snon		printf("%s: atten check OK\n", slp->sl_xname);
479079697Snon}
479179697Snon
479279697Snonstatic void
479379697Snonscsi_low_test_cmdlnk(slp, cb)
479479697Snon	struct scsi_low_softc *slp;
479579697Snon	struct slccb *cb;
479679697Snon{
479779697Snon#define	SCSI_LOW_CMDLNK_NOK	(CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
479879697Snon
479979697Snon	if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
480079697Snon		return;
480179697Snon
480279697Snon	memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
480379697Snon	       slp->sl_scp.scp_cmdlen);
480479697Snon	cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
480579697Snon	slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
480679697Snon}
480779697Snon#endif	/* SCSI_LOW_DEBUG */
480879697Snon
480979697Snon/* static */ void
481067468Snonscsi_low_info(slp, ti, s)
481167468Snon	struct scsi_low_softc *slp;
481267468Snon	struct targ_info *ti;
481367468Snon	u_char *s;
481467468Snon{
481567468Snon
481679697Snon	if (slp == NULL)
481779697Snon		slp = LIST_FIRST(&sl_tab);
481879697Snon	if (s == NULL)
481979697Snon		s = "no message";
482079697Snon
482179697Snon	printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
482267468Snon	if (ti == NULL)
482367468Snon	{
482479697Snon		for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
482579697Snon		     ti = TAILQ_NEXT(ti, ti_chain))
482679697Snon		{
482767468Snon			scsi_low_print(slp, ti);
482879697Snon		}
482967468Snon	}
483067468Snon	else
483179697Snon	{
483267468Snon		scsi_low_print(slp, ti);
483379697Snon	}
483467468Snon}
483567468Snon
483667468Snonstatic u_char *phase[] =
483767468Snon{
483867468Snon	"FREE", "ARBSTART", "SELSTART", "SELECTED",
483967468Snon	"CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL"
484067468Snon};
484167468Snon
484267468Snonvoid
484367468Snonscsi_low_print(slp, ti)
484467468Snon	struct scsi_low_softc *slp;
484567468Snon	struct targ_info *ti;
484667468Snon{
484779697Snon	struct lun_info *li;
484879697Snon	struct slccb *cb;
484979697Snon	struct sc_p *sp;
485067468Snon
485179697Snon	if (ti == NULL || ti == slp->sl_Tnexus)
485279697Snon	{
485379697Snon		ti = slp->sl_Tnexus;
485479697Snon		li = slp->sl_Lnexus;
485579697Snon		cb = slp->sl_Qnexus;
485679697Snon	}
485779697Snon	else
485879697Snon	{
485979697Snon		li = LIST_FIRST(&ti->ti_litab);
486079697Snon		cb = TAILQ_FIRST(&li->li_discq);
486179697Snon	}
486279697Snon 	sp = &slp->sl_scp;
486367468Snon
486479697Snon	printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
486579697Snon		slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb,
486679697Snon		slp->sl_nio);
486767468Snon
486867468Snon	/* target stat */
486967468Snon	if (ti != NULL)
487067468Snon	{
487179697Snon		u_int flags = 0, maxnqio = 0, nqio = 0;
487267468Snon		int lun = -1;
487367468Snon
487467468Snon		if (li != NULL)
487567468Snon		{
487667468Snon			lun = li->li_lun;
487767468Snon			flags = li->li_flags;
487879697Snon			maxnqio = li->li_maxnqio;
487979697Snon			nqio = li->li_nqio;
488067468Snon		}
488167468Snon
488279697Snon		printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
488379697Snon			slp->sl_xname,
488467468Snon		       ti->ti_id, lun, phase[(int) ti->ti_ophase],
488579697Snon		       phase[(int) ti->ti_phase], ti->ti_disc,
488679697Snon		       nqio, maxnqio);
488767468Snon
488879697Snon		if (cb != NULL)
488979697Snon		{
489079697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
489179697Snon		       (u_int) cb->ccb_scp.scp_cmd[0],
489279697Snon		       cb->ccb_scp.scp_cmdlen,
489379697Snon		       cb->ccb_datalen,
489479697Snon		       cb->ccb_scp.scp_datalen,
489579697Snon		       (u_int) cb->ccb_sscp.scp_status,
489679697Snon		       cb->ccb_error, SCSI_LOW_ERRORBITS);
489779697Snon		}
489867468Snon
489979697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
490079697Snon	       (u_int) (ti->ti_msginptr),
490179697Snon	       (u_int) (ti->ti_msgin[0]),
490279697Snon	       (u_int) (ti->ti_msgin[1]),
490379697Snon	       (u_int) (ti->ti_msgin[2]),
490479697Snon	       (u_int) (ti->ti_msgin[3]),
490579697Snon	       (u_int) (ti->ti_msgin[4]),
490679697Snon	       slp->sl_atten);
490779697Snon
490867468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
490979697Snon		(u_int) ti->ti_msgflags,
491079697Snon		(u_int) (ti->ti_msgoutstr[0]),
491179697Snon		(u_int) (ti->ti_msgoutstr[1]),
491279697Snon		(u_int) (ti->ti_msgoutstr[2]),
491379697Snon		(u_int) (ti->ti_msgoutstr[3]),
491479697Snon		(u_int) (ti->ti_msgoutstr[4]),
491579697Snon		ti->ti_msgoutlen,
491679697Snon		flags, SCSI_LOW_BITS);
491767468Snon
491879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
491979697Snon		scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
492079697Snon		scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
492179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
492267468Snon
492367468Snon	}
492479697Snon
492579697Snon	printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
492679697Snon	       (u_long) sp->scp_data,
492779697Snon	       sp->scp_datalen,
492879697Snon	       (u_int) sp->scp_status,
492979697Snon	       slp->sl_error, SCSI_LOW_ERRORBITS);
493067468Snon}
4931