scsi_low.c revision 163816
179697Snon/*	$NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $	*/
267468Snon/*	$NetBSD$	*/
367468Snon
4116162Sobrien#include <sys/cdefs.h>
5116162Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_low.c 163816 2006-10-31 05:53:29Z mjacob $");
6116162Sobrien
767468Snon#define	SCSI_LOW_STATICS
879697Snon#define	SCSI_LOW_DEBUG
979697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE
1079697Snon#define	SCSI_LOW_START_UP_CHECK
1179697Snon
1279697Snon/* #define	SCSI_LOW_INFO_DETAIL */
13116162Sobrien
1479697Snon/* #define	SCSI_LOW_QCLEAR_AFTER_CA */
1579697Snon/* #define	SCSI_LOW_FLAGS_QUIRKS_OK */
1679697Snon
1767468Snon#ifdef __NetBSD__
1867468Snon#define	SCSI_LOW_TARGET_OPEN
1979697Snon#endif	/* __NetBSD__ */
2067468Snon
2179697Snon#ifdef	__FreeBSD__
2279697Snon#define	SCSI_LOW_FLAGS_QUIRKS_OK
2379697Snon#endif	/* __FreeBSD__ */
2479697Snon
25139743Simp/*-
2667468Snon * [NetBSD for NEC PC-98 series]
2779697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2867468Snon *	NetBSD/pc98 porting staff. All rights reserved.
2979697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
3067468Snon *	Naofumi HONDA. All rights reserved.
3179697Snon *
3279697Snon * [Ported for FreeBSD CAM]
3379697Snon *  Copyright (c) 2000, 2001
3479697Snon *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
3579697Snon *      All rights reserved.
3667468Snon *
3767468Snon *  Redistribution and use in source and binary forms, with or without
3867468Snon *  modification, are permitted provided that the following conditions
3967468Snon *  are met:
4067468Snon *  1. Redistributions of source code must retain the above copyright
4167468Snon *     notice, this list of conditions and the following disclaimer.
4267468Snon *  2. Redistributions in binary form must reproduce the above copyright
4367468Snon *     notice, this list of conditions and the following disclaimer in the
4467468Snon *     documentation and/or other materials provided with the distribution.
4567468Snon *  3. The name of the author may not be used to endorse or promote products
4667468Snon *     derived from this software without specific prior written permission.
4767468Snon *
4867468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4967468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5067468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5167468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
5267468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5367468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5467468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5567468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
5667468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
5767468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5867468Snon * POSSIBILITY OF SUCH DAMAGE.
5967468Snon */
6067468Snon
6167468Snon/* <On the nexus establishment>
6267468Snon * When our host is reselected,
6367468Snon * nexus establish processes are little complicated.
6467468Snon * Normal steps are followings:
6579697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
6679697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
6779697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
6867468Snon */
6967468Snon#include "opt_ddb.h"
7067468Snon
7167468Snon#include <sys/param.h>
7267468Snon#include <sys/systm.h>
7367468Snon#include <sys/kernel.h>
7479697Snon
7573025Snon#ifdef __FreeBSD__
7673025Snon#if __FreeBSD_version >= 500001
7767468Snon#include <sys/bio.h>
7879697Snon#else
7979697Snon#include <machine/clock.h>
8073025Snon#endif
8179697Snon#endif	/* __FreeBSD__ */
8279697Snon
8367468Snon#include <sys/buf.h>
8467468Snon#include <sys/queue.h>
8567468Snon#include <sys/malloc.h>
8667468Snon#include <sys/errno.h>
8767468Snon
8879697Snon#ifdef	__NetBSD__
8979697Snon#include <sys/device.h>
9067468Snon#include <vm/vm.h>
9167468Snon
9267468Snon#include <machine/bus.h>
9367468Snon#include <machine/intr.h>
9467468Snon#include <machine/dvcfg.h>
9567468Snon
9667468Snon#include <dev/cons.h>
9767468Snon
9867468Snon#include <dev/scsipi/scsipi_all.h>
9967468Snon#include <dev/scsipi/scsipiconf.h>
10067468Snon#include <dev/scsipi/scsipi_disk.h>
10167468Snon#include <dev/scsipi/scsi_all.h>
10267468Snon#include <dev/scsipi/scsiconf.h>
10379697Snon#include <sys/scsiio.h>
10467468Snon
10567468Snon#include <i386/Cbus/dev/scsi_low.h>
10679697Snon#endif	/* __NetBSD__ */
10779697Snon
10867468Snon#ifdef __FreeBSD__
10967468Snon#include <cam/cam.h>
11067468Snon#include <cam/cam_ccb.h>
11167468Snon#include <cam/cam_sim.h>
11267468Snon#include <cam/cam_debug.h>
11367468Snon#include <cam/cam_periph.h>
114147723Savatar#include <cam/cam_xpt_periph.h>
11567468Snon
11667468Snon#include <cam/scsi/scsi_all.h>
11773025Snon#include <cam/scsi/scsi_message.h>
11867468Snon
11967468Snon#include <cam/scsi/scsi_low.h>
12067468Snon
12167468Snon#include <sys/cons.h>
12279697Snon#endif	/* __FreeBSD__ */
12367468Snon
12479697Snon/**************************************************************
12579697Snon * Constants
12679697Snon **************************************************************/
12779697Snon#define	SCSI_LOW_POLL_HZ	1000
12867468Snon
12979697Snon/* functions return values */
13079697Snon#define	SCSI_LOW_START_NO_QTAG	0
13179697Snon#define	SCSI_LOW_START_QTAG	1
13279697Snon
13367468Snon#define	SCSI_LOW_DONE_COMPLETE	0
13467468Snon#define	SCSI_LOW_DONE_RETRY	1
13567468Snon
13679697Snon/* internal disk flags */
13779697Snon#define	SCSI_LOW_DISK_DISC	0x00000001
13879697Snon#define	SCSI_LOW_DISK_QTAG	0x00000002
13979697Snon#define	SCSI_LOW_DISK_LINK	0x00000004
14079697Snon#define	SCSI_LOW_DISK_PARITY	0x00000008
14179697Snon#define	SCSI_LOW_DISK_SYNC	0x00010000
14279697Snon#define	SCSI_LOW_DISK_WIDE_16	0x00020000
14379697Snon#define	SCSI_LOW_DISK_WIDE_32	0x00040000
14479697Snon#define	SCSI_LOW_DISK_WIDE	(SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
14579697Snon#define	SCSI_LOW_DISK_LFLAGS	0x0000ffff
14679697Snon#define	SCSI_LOW_DISK_TFLAGS	0xffff0000
14779697Snon
148147723SavatarMALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers");
149147723Savatar
15079697Snon/**************************************************************
15179697Snon * Declarations
15279697Snon **************************************************************/
15392770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *);
15492770Salfredstatic void scsi_low_engage(void *);
15592770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t);
15692770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *);
15792770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *);
15892770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *);
15992770Salfredstatic void scsi_low_twiddle_wait(void);
16092770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int);
16192770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int);
16292770Salfredstatic void scsi_low_calcf_lun(struct lun_info *);
16392770Salfredstatic void scsi_low_calcf_target(struct targ_info *);
16492770Salfredstatic void scsi_low_calcf_show(struct lun_info *);
16592770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int);
16692770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int);
16792770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int);
16892770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int);
16992770Salfredstatic void scsi_low_start(struct scsi_low_softc *);
17092770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *);
17167468Snon
17292770Salfredstatic int scsi_low_alloc_qtag(struct slccb *);
17392770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *);
17492770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int);
17592770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int);
17692770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *);
17792770Salfredstatic void scsi_low_timeout(void *);
17892770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *);
17979697Snon#ifdef	SCSI_LOW_START_UP_CHECK
18092770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *);
18179697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
18292770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *);
18392770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int);
18479697Snon
18579697Snonint scsi_low_version_major = 2;
18679697Snonint scsi_low_version_minor = 17;
18779697Snon
18879697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
18979697Snon
19079697Snon/**************************************************************
19179697Snon * Debug, Run test and Statics
19279697Snon **************************************************************/
19379697Snon#ifdef	SCSI_LOW_INFO_DETAIL
19479697Snon#define	SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
19579697Snon#else	/* !SCSI_LOW_INFO_DETAIL */
19679697Snon#define	SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s))
19779697Snon#endif	/* !SCSI_LOW_INFO_DETAIL */
19879697Snon
19967468Snon#ifdef	SCSI_LOW_STATICS
20089113Smsmithstatic struct scsi_low_statics {
20167468Snon	int nexus_win;
20267468Snon	int nexus_fail;
20367468Snon	int nexus_disconnected;
20467468Snon	int nexus_reselected;
20567468Snon	int nexus_conflict;
20667468Snon} scsi_low_statics;
20767468Snon#endif	/* SCSI_LOW_STATICS */
20879697Snon
20979697Snon#ifdef	SCSI_LOW_DEBUG
21079697Snon#define	SCSI_LOW_DEBUG_DONE	0x00001
21179697Snon#define	SCSI_LOW_DEBUG_DISC	0x00002
21279697Snon#define	SCSI_LOW_DEBUG_SENSE	0x00004
21379697Snon#define	SCSI_LOW_DEBUG_CALCF	0x00008
21479697Snon#define	SCSI_LOW_DEBUG_ACTION	0x10000
21579697Snonint scsi_low_debug = 0;
21679697Snon
21779697Snon#define	SCSI_LOW_MAX_ATTEN_CHECK	32
21879697Snon#define	SCSI_LOW_ATTEN_CHECK	0x0001
21979697Snon#define	SCSI_LOW_CMDLNK_CHECK	0x0002
22079697Snon#define	SCSI_LOW_ABORT_CHECK	0x0004
22179697Snon#define	SCSI_LOW_NEXUS_CHECK	0x0008
22279697Snonint scsi_low_test = 0;
22379697Snonint scsi_low_test_id = 0;
22479697Snon
22592770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *);
22692770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *);
22792770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int);
22879697Snon#define	SCSI_LOW_DEBUG_TEST_GO(fl, id) \
22979697Snon	((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
23079697Snon#define	SCSI_LOW_DEBUG_GO(fl, id) \
23179697Snon	((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
23279697Snon#endif	/* SCSI_LOW_DEBUG */
23379697Snon
23467468Snon/**************************************************************
23579697Snon * CCB
23679697Snon **************************************************************/
23779697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
23879697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain)
23979697Snon
24079697Snon/**************************************************************
24179697Snon * Inline functions
24279697Snon **************************************************************/
24379697Snon#define	SCSI_LOW_INLINE	static __inline
24492770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *);
24592770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *);
24692770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int);
24792770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *);
24892770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *);
24992770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *);
25092770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *);
25179697Snon
25279697SnonSCSI_LOW_INLINE void
25379697Snonscsi_low_activate_qtag(cb)
25479697Snon	struct slccb *cb;
25579697Snon{
25679697Snon	struct lun_info *li = cb->li;
25779697Snon
25879697Snon	if (cb->ccb_tag != SCSI_LOW_UNKTAG)
25979697Snon		return;
26079697Snon
26179697Snon	li->li_nqio ++;
26279697Snon	cb->ccb_tag = cb->ccb_otag;
26379697Snon}
26479697Snon
26579697SnonSCSI_LOW_INLINE void
26679697Snonscsi_low_deactivate_qtag(cb)
26779697Snon	struct slccb *cb;
26879697Snon{
26979697Snon	struct lun_info *li = cb->li;
27079697Snon
27179697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
27279697Snon		return;
27379697Snon
27479697Snon	li->li_nqio --;
27579697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
27679697Snon}
27779697Snon
27879697SnonSCSI_LOW_INLINE void
27979697Snonscsi_low_ccb_message_exec(slp, cb)
28079697Snon	struct scsi_low_softc *slp;
28179697Snon	struct slccb *cb;
28279697Snon{
28379697Snon
28479697Snon	scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
28579697Snon	cb->ccb_msgoutflag = 0;
28679697Snon}
28779697Snon
28879697SnonSCSI_LOW_INLINE void
28979697Snonscsi_low_ccb_message_assert(cb, msg)
29079697Snon	struct slccb *cb;
29179697Snon	u_int msg;
29279697Snon{
29379697Snon
29479697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
29579697Snon}
29679697Snon
29779697SnonSCSI_LOW_INLINE void
29879697Snonscsi_low_ccb_message_retry(cb)
29979697Snon	struct slccb *cb;
30079697Snon{
30179697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
30279697Snon}
30379697Snon
30479697SnonSCSI_LOW_INLINE void
30579697Snonscsi_low_ccb_message_clear(cb)
30679697Snon	struct slccb *cb;
30779697Snon{
30879697Snon	cb->ccb_msgoutflag = 0;
30979697Snon}
31079697Snon
31179697SnonSCSI_LOW_INLINE void
31279697Snonscsi_low_init_msgsys(slp, ti)
31379697Snon	struct scsi_low_softc *slp;
31479697Snon	struct targ_info *ti;
31579697Snon{
31679697Snon
31779697Snon	ti->ti_msginptr = 0;
31879697Snon	ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
31979697Snon	SCSI_LOW_DEASSERT_ATN(slp);
32079697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
32179697Snon}
32279697Snon
32379697Snon/*=============================================================
32479697Snon * START OF OS switch  (All OS depend fucntions should be here)
32579697Snon =============================================================*/
32679697Snon/* common os depend utitlities */
32779697Snon#define	SCSI_LOW_CMD_RESIDUAL_CHK	0x0001
32879697Snon#define	SCSI_LOW_CMD_ORDERED_QTAG	0x0002
32979697Snon#define	SCSI_LOW_CMD_ABORT_WARNING	0x0004
33079697Snon
33179697Snonstatic u_int8_t scsi_low_cmd_flags[256] = {
33279697Snon/*	0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
33379697Snon/*0*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
33479697Snon/*1*/	0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
33579697Snon/*2*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
33679697Snon/*3*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
33779697Snon};
33879697Snon
33979697Snonstruct scsi_low_error_code {
34079697Snon	int error_bits;
34179697Snon	int error_code;
34279697Snon};
34379697Snon
34492770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *);
34592770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *);
34679697Snon
34779697Snonstatic struct slccb *
34879697Snonscsi_low_find_ccb(slp, target, lun, osdep)
34979697Snon	struct scsi_low_softc *slp;
35079697Snon	u_int target, lun;
35179697Snon	void *osdep;
35279697Snon{
35379697Snon	struct targ_info *ti;
35479697Snon	struct lun_info *li;
35579697Snon	struct slccb *cb;
35679697Snon
35779697Snon	ti = slp->sl_ti[target];
35879697Snon	li = scsi_low_alloc_li(ti, lun, 0);
35979697Snon	if (li == NULL)
36079697Snon		return NULL;
36179697Snon
36279697Snon	if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
36379697Snon		return cb;
36479697Snon
36579697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
36679697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
36779697Snon	{
36879697Snon		if (cb->osdep == osdep)
36979697Snon			return cb;
37079697Snon	}
37179697Snon
37279697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL;
37379697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
37479697Snon	{
37579697Snon		if (cb->osdep == osdep)
37679697Snon			return cb;
37779697Snon	}
37879697Snon	return NULL;
37979697Snon}
38079697Snon
38179697Snonstatic int
38279697Snonscsi_low_translate_error_code(cb, tp)
38379697Snon	struct slccb *cb;
38479697Snon	struct scsi_low_error_code *tp;
38579697Snon{
38679697Snon
38779697Snon	if (cb->ccb_error == 0)
38879697Snon		return tp->error_code;
38979697Snon
39079697Snon	for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
39179697Snon		;
39279697Snon	return tp->error_code;
39379697Snon}
39479697Snon
39579697Snon#ifdef SCSI_LOW_INTERFACE_XS
39679697Snon/**************************************************************
39779697Snon * SCSI INTERFACE (XS)
39879697Snon **************************************************************/
39979697Snon#define	SCSI_LOW_MINPHYS		0x10000
400147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
401147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
40279697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb((flags))
40379697Snon#define	SCSI_LOW_XS_POLL_HZ		1000
40479697Snon
40592770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *);
40692770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *);
40779697Snon#ifdef	SCSI_LOW_TARGET_OPEN
40892770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *);
40979697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
41092770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *);
41192770Salfredstatic int scsi_low_enable_xs(void *, int);
41292770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *);
41379697Snon
41492770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *);
41592770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *);
41692770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *);
41792770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *);
41892770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *);
41992770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int);
42092770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int);
42192770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int);
42279697Snon
42379697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = {
42479697Snon	scsi_low_attach_xs,
42579697Snon	scsi_low_world_start_xs,
42679697Snon	scsi_low_dettach_xs,
42779697Snon	scsi_low_ccb_setup_xs,
42879697Snon	scsi_low_done_xs,
42979697Snon	scsi_low_timeout_xs
43079697Snon};
43179697Snon
43279697Snonstruct scsipi_device scsi_low_dev = {
43379697Snon	NULL,	/* Use default error handler */
43479697Snon	NULL,	/* have a queue, served by this */
43579697Snon	NULL,	/* have no async handler */
43679697Snon	NULL,	/* Use default 'done' routine */
43779697Snon};
43879697Snon
43979697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = {
44079697Snon	{0,		XS_NOERROR},
44179697Snon	{SENSEIO,	XS_SENSE},
44279697Snon	{BUSYERR,	XS_BUSY	},
44379697Snon	{SELTIMEOUTIO,	XS_SELTIMEOUT},
44479697Snon	{TIMEOUTIO,	XS_TIMEOUT},
44579697Snon	{-1,		XS_DRIVER_STUFFUP}
44679697Snon};
44779697Snon
44879697Snonstatic int
44979697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p)
45079697Snon	struct scsipi_link *link;
45179697Snon	u_long cmd;
45279697Snon	caddr_t addr;
45379697Snon	int flag;
45479697Snon	struct proc *p;
45579697Snon{
45679697Snon	struct scsi_low_softc *slp;
45779697Snon	int s, error = ENOTTY;
45879697Snon
45979697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
46079697Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
46179697Snon		return ENXIO;
46279697Snon
46379697Snon	if (cmd == SCBUSIORESET)
46479697Snon	{
46579697Snon		s = SCSI_LOW_SPLSCSI();
46679697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
46779697Snon		splx(s);
46879697Snon		error = 0;
46979697Snon	}
47079697Snon	else if (slp->sl_funcs->scsi_low_ioctl != 0)
47179697Snon	{
47279697Snon		error = (*slp->sl_funcs->scsi_low_ioctl)
47379697Snon				(slp, cmd, addr, flag, p);
47479697Snon	}
47579697Snon
47679697Snon	return error;
47779697Snon}
47879697Snon
47979697Snonstatic int
48079697Snonscsi_low_enable_xs(arg, enable)
48179697Snon	void *arg;
48279697Snon	int enable;
48379697Snon{
48479697Snon	struct scsi_low_softc *slp = arg;
48579697Snon
48679697Snon	if (enable != 0)
48779697Snon	{
48879697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0)
48979697Snon			return ENXIO;
49079697Snon	}
49179697Snon	else
49279697Snon	{
49379697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0 ||
49479697Snon		    (slp->sl_flags & HW_POWERCTRL) == 0)
49579697Snon			return 0;
49679697Snon
49779697Snon		slp->sl_flags |= HW_POWDOWN;
49879697Snon		if (slp->sl_funcs->scsi_low_power != NULL)
49979697Snon		{
50079697Snon			(*slp->sl_funcs->scsi_low_power)
50179697Snon					(slp, SCSI_LOW_POWDOWN);
50279697Snon		}
50379697Snon	}
50479697Snon	return 0;
50579697Snon}
50679697Snon
50779697Snonstatic void
50879697Snonscsi_low_scsi_minphys_xs(bp)
50979697Snon	struct buf *bp;
51079697Snon{
51179697Snon
51279697Snon	if (bp->b_bcount > SCSI_LOW_MINPHYS)
51379697Snon		bp->b_bcount = SCSI_LOW_MINPHYS;
51479697Snon	minphys(bp);
51579697Snon}
51679697Snon
51779697Snonstatic int
51879697Snonscsi_low_poll_xs(slp, cb)
51979697Snon	struct scsi_low_softc *slp;
52079697Snon	struct slccb *cb;
52179697Snon{
52279697Snon	struct scsipi_xfer *xs = cb->osdep;
52379697Snon	int tcount;
52479697Snon
52579697Snon	cb->ccb_flags |= CCB_NOSDONE;
52679697Snon	tcount = 0;
52779697Snon
52879697Snon	while (slp->sl_nio > 0)
52979697Snon	{
53079697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ);
53179697Snon
53279697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
53379697Snon
53479697Snon		if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
53579697Snon		{
53679697Snon			cb->ccb_flags |= CCB_NORETRY;
53779697Snon			cb->ccb_error |= FATALIO;
53879697Snon			(void) scsi_low_revoke_ccb(slp, cb, 1);
53979697Snon			printf("%s: hardware inactive in poll mode\n",
54079697Snon				slp->sl_xname);
54179697Snon		}
54279697Snon
54379697Snon		if ((xs->flags & ITSDONE) != 0)
54479697Snon			break;
54579697Snon
54679697Snon		if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
54779697Snon			continue;
54879697Snon
54979697Snon		tcount = 0;
55079697Snon		scsi_low_timeout_check(slp);
55179697Snon	}
55279697Snon
55379697Snon	xs->flags |= ITSDONE;
55479697Snon	scsipi_done(xs);
55579697Snon	return COMPLETE;
55679697Snon}
55779697Snon
55879697Snonstatic int
55979697Snonscsi_low_scsi_cmd_xs(xs)
56079697Snon	struct scsipi_xfer *xs;
56179697Snon{
56279697Snon	struct scsipi_link *splp = xs->sc_link;
56379697Snon	struct scsi_low_softc *slp = splp->adapter_softc;
56479697Snon	struct targ_info *ti;
56579697Snon	struct lun_info *li;
56679697Snon	struct slccb *cb;
56779697Snon	int s, targ, lun, flags, rv;
56879697Snon
56979697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL)
57079697Snon		return TRY_AGAIN_LATER;
57179697Snon
57279697Snon	targ = splp->scsipi_scsi.target,
57379697Snon	lun = splp->scsipi_scsi.lun;
57479697Snon	ti = slp->sl_ti[targ];
57579697Snon
57679697Snon	cb->osdep = xs;
57779697Snon	cb->bp = xs->bp;
57879697Snon
57979697Snon	if ((xs->flags & SCSI_POLL) == 0)
58079697Snon		flags = CCB_AUTOSENSE;
58179697Snon	else
58279697Snon		flags = CCB_AUTOSENSE | CCB_POLLED;
58379697Snon
58479697Snon
58579697Snon	s = SCSI_LOW_SPLSCSI();
58679697Snon	li = scsi_low_alloc_li(ti, lun, 1);
58779697Snon	if ((u_int) splp->quirks != li->li_sloi.sloi_quirks)
58879697Snon	{
58979697Snon		scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks);
59079697Snon	}
59179697Snon
59279697Snon	if ((xs->flags & SCSI_RESET) != 0)
59379697Snon	{
59479697Snon		flags |= CCB_NORETRY | CCB_URGENT;
59579697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET);
59679697Snon	}
59779697Snon	else
59879697Snon	{
59979697Snon		if (ti->ti_setup_msg != 0)
60079697Snon		{
60179697Snon			scsi_low_message_enqueue(slp, ti, li, flags);
60279697Snon		}
60379697Snon
60479697Snon		flags |= CCB_SCSIIO;
60579697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
60679697Snon	}
60779697Snon
60879697Snon#ifdef	SCSI_LOW_DEBUG
60979697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0)
61079697Snon	{
61179697Snon		scsi_low_test_abort(slp, ti, li);
61279697Snon	}
61379697Snon#endif	/* SCSI_LOW_DEBUG */
61479697Snon
61579697Snon	if ((cb->ccb_flags & CCB_POLLED) != 0)
61679697Snon	{
61779697Snon		rv = scsi_low_poll_xs(slp, cb);
61879697Snon	}
61979697Snon	else
62079697Snon	{
62179697Snon		rv = SUCCESSFULLY_QUEUED;
62279697Snon	}
62379697Snon	splx(s);
62479697Snon	return rv;
62579697Snon}
62679697Snon
62779697Snonstatic int
62879697Snonscsi_low_attach_xs(slp)
62979697Snon	struct scsi_low_softc *slp;
63079697Snon{
63179697Snon	struct scsipi_adapter *sap;
63279697Snon	struct scsipi_link *splp;
63379697Snon
63479697Snon	strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16);
63579697Snon
63679697Snon	sap = SCSI_LOW_MALLOC(sizeof(*sap));
63779697Snon	if (sap == NULL)
63879697Snon		return ENOMEM;
63979697Snon	splp = SCSI_LOW_MALLOC(sizeof(*splp));
64079697Snon	if (splp == NULL)
64179697Snon		return ENOMEM;
64279697Snon
64379697Snon	SCSI_LOW_BZERO(sap, sizeof(*sap));
64479697Snon	SCSI_LOW_BZERO(splp, sizeof(*splp));
64579697Snon
64679697Snon	sap->scsipi_cmd = scsi_low_scsi_cmd_xs;
64779697Snon	sap->scsipi_minphys = scsi_low_scsi_minphys_xs;
64879697Snon	sap->scsipi_enable = scsi_low_enable_xs;
64979697Snon	sap->scsipi_ioctl = scsi_low_ioctl_xs;
65079697Snon#ifdef	SCSI_LOW_TARGET_OPEN
65179697Snon	sap->open_target_lu = scsi_low_target_open;
65279697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
65379697Snon
65479697Snon	splp->adapter_softc = slp;
65579697Snon	splp->scsipi_scsi.adapter_target = slp->sl_hostid;
65679697Snon	splp->scsipi_scsi.max_target = slp->sl_ntargs - 1;
65779697Snon	splp->scsipi_scsi.max_lun = slp->sl_nluns - 1;
65879697Snon	splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
65979697Snon	splp->openings = slp->sl_openings;
66079697Snon	splp->type = BUS_SCSI;
66179697Snon	splp->adapter_softc = slp;
66279697Snon	splp->adapter = sap;
66379697Snon	splp->device = &scsi_low_dev;
66479697Snon
66579697Snon	slp->sl_si.si_splp = splp;
66679697Snon	slp->sl_show_result = SHOW_ALL_NEG;
66779697Snon	return 0;
66879697Snon}
66979697Snon
67079697Snonstatic int
67179697Snonscsi_low_world_start_xs(slp)
67279697Snon	struct scsi_low_softc *slp;
67379697Snon{
67479697Snon
67579697Snon	return 0;
67679697Snon}
67779697Snon
67879697Snonstatic int
67979697Snonscsi_low_dettach_xs(slp)
68079697Snon	struct scsi_low_softc *slp;
68179697Snon{
68279697Snon
68379697Snon	/*
68479697Snon	 * scsipi does not have dettach bus fucntion.
68579697Snon	 *
68679697Snon	scsipi_dettach_scsibus(slp->sl_si.si_splp);
68779697Snon	*/
68879697Snon	return 0;
68979697Snon}
69079697Snon
69179697Snonstatic int
69279697Snonscsi_low_ccb_setup_xs(slp, cb)
69379697Snon	struct scsi_low_softc *slp;
69479697Snon	struct slccb *cb;
69579697Snon{
69679697Snon	struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep;
69779697Snon
69879697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
69979697Snon	{
70079697Snon		cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd;
70179697Snon		cb->ccb_scp.scp_cmdlen = xs->cmdlen;
70279697Snon		cb->ccb_scp.scp_data = xs->data;
70379697Snon		cb->ccb_scp.scp_datalen = xs->datalen;
70479697Snon		cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ?
70579697Snon					SCSI_LOW_WRITE : SCSI_LOW_READ;
70679697Snon		cb->ccb_tcmax = xs->timeout / 1000;
70779697Snon	}
70879697Snon	else
70979697Snon	{
71079697Snon		scsi_low_unit_ready_cmd(cb);
71179697Snon	}
71279697Snon	return SCSI_LOW_START_QTAG;
71379697Snon}
71479697Snon
71579697Snonstatic int
71679697Snonscsi_low_done_xs(slp, cb)
71779697Snon	struct scsi_low_softc *slp;
71879697Snon	struct slccb *cb;
71979697Snon{
72079697Snon	struct scsipi_xfer *xs;
72179697Snon
72279697Snon	xs = (struct scsipi_xfer *) cb->osdep;
72379697Snon	if (cb->ccb_error == 0)
72479697Snon	{
72579697Snon		xs->error = XS_NOERROR;
72679697Snon		xs->resid = 0;
72779697Snon	}
72879697Snon	else
72979697Snon	{
73079697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
73179697Snon			cb->ccb_error |= ABORTIO;
73279697Snon
73379697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
73479697Snon		    (cb->ccb_error & ABORTIO) == 0)
73579697Snon			return EJUSTRETURN;
73679697Snon
73779697Snon		if ((cb->ccb_error & SENSEIO) != 0)
73879697Snon		{
73979697Snon			xs->sense.scsi_sense = cb->ccb_sense;
74079697Snon		}
74179697Snon
74279697Snon		xs->error = scsi_low_translate_error_code(cb,
74379697Snon				&scsi_low_error_code_xs[0]);
74479697Snon
74579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
74679697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
74779697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
74879697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
74979697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
75079697Snon		{
75179697Snon			printf("%s: WARNING: scsi_low IO abort\n",
75279697Snon				slp->sl_xname);
75379697Snon			scsi_low_print(slp, NULL);
75479697Snon		}
75579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
75679697Snon	}
75779697Snon
75879697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
75979697Snon		xs->status = 0;	/* XXX */
76079697Snon	else
76179697Snon		xs->status = cb->ccb_scp.scp_status;
76279697Snon
76379697Snon	xs->flags |= ITSDONE;
76479697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
76579697Snon		scsipi_done(xs);
76679697Snon
76779697Snon	return 0;
76879697Snon}
76979697Snon
77079697Snonstatic void
77179697Snonscsi_low_timeout_xs(slp, ch, action)
77279697Snon	struct scsi_low_softc *slp;
77379697Snon	int ch;
77479697Snon	int action;
77579697Snon{
77679697Snon
77779697Snon	switch (ch)
77879697Snon	{
77979697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
78079697Snon		switch (action)
78179697Snon		{
78279697Snon		case SCSI_LOW_TIMEOUT_START:
78379697Snon			timeout(scsi_low_timeout, slp,
78479697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
78579697Snon			break;
78679697Snon		case SCSI_LOW_TIMEOUT_STOP:
78779697Snon			untimeout(scsi_low_timeout, slp);
78879697Snon			break;
78979697Snon		}
79079697Snon		break;
79179697Snon
79279697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
79379697Snon		switch (action)
79479697Snon		{
79579697Snon		case SCSI_LOW_TIMEOUT_START:
79679697Snon			timeout(scsi_low_engage, slp, 1);
79779697Snon			break;
79879697Snon		case SCSI_LOW_TIMEOUT_STOP:
79979697Snon			untimeout(scsi_low_engage, slp);
80079697Snon			break;
80179697Snon		}
80279697Snon		break;
80379697Snon
80479697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
80579697Snon		break;
80679697Snon	}
80779697Snon}
80879697Snon
80979697Snonu_int
81079697Snonscsi_low_translate_quirks_xs(quirks)
81179697Snon	u_int quirks;
81279697Snon{
81379697Snon	u_int flags;
81479697Snon
81579697Snon	flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS;
81679697Snon
81779697Snon#ifdef	SDEV_NODISC
81879697Snon	if (quirks & SDEV_NODISC)
81979697Snon		flags &= ~SCSI_LOW_DISK_DISC;
82079697Snon#endif	/* SDEV_NODISC */
82179697Snon#ifdef	SDEV_NOPARITY
82279697Snon	if (quirks & SDEV_NOPARITY)
82379697Snon		flags &= ~SCSI_LOW_DISK_PARITY;
82479697Snon#endif	/* SDEV_NOPARITY */
82579697Snon#ifdef	SDEV_NOCMDLNK
82679697Snon	if (quirks & SDEV_NOCMDLNK)
82779697Snon		flags &= ~SCSI_LOW_DISK_LINK;
82879697Snon#endif	/* SDEV_NOCMDLNK */
82979697Snon#ifdef	SDEV_NOTAG
83079697Snon	if (quirks & SDEV_NOTAG)
83179697Snon		flags &= ~SCSI_LOW_DISK_QTAG;
83279697Snon#endif	/* SDEV_NOTAG */
83379697Snon#ifdef	SDEV_NOSYNC
83479697Snon	if (quirks & SDEV_NOSYNC)
83579697Snon		flags &= ~SCSI_LOW_DISK_SYNC;
83679697Snon#endif	/* SDEV_NOSYNC */
83779697Snon
83879697Snon	return flags;
83979697Snon}
84079697Snon
84179697Snonstatic void
84279697Snonscsi_low_setup_quirks_xs(ti, li, flags)
84379697Snon	struct targ_info *ti;
84479697Snon	struct lun_info *li;
84579697Snon	u_int flags;
84679697Snon{
84779697Snon	u_int quirks;
84879697Snon
84979697Snon	li->li_sloi.sloi_quirks = flags;
85079697Snon	quirks = scsi_low_translate_quirks_xs(flags);
85179697Snon	ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS;
85279697Snon	li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS;
85379697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
85479697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
85579697Snon	scsi_low_calcf_target(ti);
85679697Snon	scsi_low_calcf_lun(li);
85779697Snon	scsi_low_calcf_show(li);
85879697Snon}
85979697Snon
86079697Snon#ifdef	SCSI_LOW_TARGET_OPEN
86179697Snonstatic int
86279697Snonscsi_low_target_open(link, cf)
86379697Snon	struct scsipi_link *link;
86479697Snon	struct cfdata *cf;
86579697Snon{
86679697Snon	u_int target = link->scsipi_scsi.target;
86779697Snon	u_int lun = link->scsipi_scsi.lun;
86879697Snon	struct scsi_low_softc *slp;
86979697Snon	struct targ_info *ti;
87079697Snon	struct lun_info *li;
87179697Snon
87279697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
87379697Snon	ti = slp->sl_ti[target];
87479697Snon	li = scsi_low_alloc_li(ti, lun, 0);
87579697Snon	if (li == NULL)
87679697Snon		return 0;
87779697Snon
87879697Snon	li->li_cfgflags = cf->cf_flags;
87979697Snon	scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks);
88079697Snon	return 0;
88179697Snon}
88279697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
88379697Snon
88479697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
88579697Snon
88679697Snon#ifdef SCSI_LOW_INTERFACE_CAM
88779697Snon/**************************************************************
88879697Snon * SCSI INTERFACE (CAM)
88979697Snon **************************************************************/
890147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
891147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
89279697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb()
89379697Snon
89492770Salfredstatic void scsi_low_poll_cam(struct cam_sim *);
89592770Salfredstatic void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *);
89692770Salfredstatic void scsi_low_rescan_bus_cam(struct scsi_low_softc *);
89792770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
89879697Snon
89992770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *);
90092770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *);
90192770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *);
90292770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *);
90392770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *);
90492770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int);
90579697Snon
90679697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = {
90779697Snon	scsi_low_attach_cam,
90879697Snon	scsi_low_world_start_cam,
90979697Snon	scsi_low_dettach_cam,
91079697Snon	scsi_low_ccb_setup_cam,
91179697Snon	scsi_low_done_cam,
91279697Snon	scsi_low_timeout_cam
91379697Snon};
91479697Snon
91579697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = {
91679697Snon	{0,			CAM_REQ_CMP},
91779697Snon	{SENSEIO, 		CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
91879697Snon	{SENSEERR,		CAM_AUTOSENSE_FAIL},
91979697Snon	{UACAERR,		CAM_SCSI_STATUS_ERROR},
92079697Snon	{BUSYERR | STATERR,	CAM_SCSI_STATUS_ERROR},
92179697Snon	{SELTIMEOUTIO,		CAM_SEL_TIMEOUT},
92279697Snon	{TIMEOUTIO,		CAM_CMD_TIMEOUT},
92379697Snon	{PDMAERR,		CAM_DATA_RUN_ERR},
92479697Snon	{PARITYERR,		CAM_UNCOR_PARITY},
92579697Snon	{UBFERR,		CAM_UNEXP_BUSFREE},
92679697Snon	{ABORTIO,		CAM_REQ_ABORTED},
92779697Snon	{-1,			CAM_UNREC_HBA_ERROR}
92879697Snon};
92979697Snon
93079697Snon#define	SIM2SLP(sim)	((struct scsi_low_softc *) cam_sim_softc((sim)))
93179697Snon
93279697Snon/* XXX:
93379697Snon * Please check a polling hz, currently we assume scsi_low_poll() is
93479697Snon * called each 1 ms.
93579697Snon */
93679697Snon#define	SCSI_LOW_CAM_POLL_HZ	1000	/* OK ? */
93779697Snon
93879697Snonstatic void
93979697Snonscsi_low_poll_cam(sim)
94079697Snon	struct cam_sim *sim;
94179697Snon{
94279697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
94379697Snon
94479697Snon	(*slp->sl_funcs->scsi_low_poll) (slp);
94579697Snon
94679697Snon	if (slp->sl_si.si_poll_count ++ >=
94779697Snon	    SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
94879697Snon	{
94979697Snon		slp->sl_si.si_poll_count = 0;
95079697Snon		scsi_low_timeout_check(slp);
95179697Snon	}
95279697Snon}
95379697Snon
95479697Snonstatic void
95579697Snonscsi_low_cam_rescan_callback(periph, ccb)
95679697Snon	struct cam_periph *periph;
95779697Snon	union ccb *ccb;
95879697Snon{
95979697Snon
96079697Snon	xpt_free_path(ccb->ccb_h.path);
961147723Savatar	xpt_free_ccb(ccb);
96279697Snon}
96379697Snon
96479697Snonstatic void
96579697Snonscsi_low_rescan_bus_cam(slp)
96679697Snon	struct scsi_low_softc *slp;
96779697Snon{
96879697Snon  	struct cam_path *path;
969147723Savatar	union ccb *ccb = xpt_alloc_ccb();
97079697Snon	cam_status status;
97179697Snon
97279697Snon	bzero(ccb, sizeof(union ccb));
97379697Snon
97479697Snon	status = xpt_create_path(&path, xpt_periph,
97579697Snon				 cam_sim_path(slp->sl_si.sim), -1, 0);
97679697Snon	if (status != CAM_REQ_CMP)
97779697Snon		return;
97879697Snon
97979697Snon	xpt_setup_ccb(&ccb->ccb_h, path, 5);
98079697Snon	ccb->ccb_h.func_code = XPT_SCAN_BUS;
98179697Snon	ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback;
98279697Snon	ccb->crcn.flags = CAM_FLAG_NONE;
98379697Snon	xpt_action(ccb);
98479697Snon}
98579697Snon
98679697Snonvoid
98779697Snonscsi_low_scsi_action_cam(sim, ccb)
98879697Snon	struct cam_sim *sim;
98979697Snon	union ccb *ccb;
99079697Snon{
99179697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
99279697Snon	struct targ_info *ti;
99379697Snon	struct lun_info *li;
99479697Snon	struct slccb *cb;
99579697Snon	u_int lun, flags, msg, target;
99679697Snon	int s, rv;
99779697Snon
99879697Snon	target = (u_int) (ccb->ccb_h.target_id);
99979697Snon	lun = (u_int) ccb->ccb_h.target_lun;
100079697Snon
100179697Snon#ifdef	SCSI_LOW_DEBUG
100279697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
100379697Snon	{
100479697Snon		printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n",
100579697Snon			slp->sl_xname, ccb->ccb_h.func_code, target, lun);
100679697Snon	}
100779697Snon#endif	/* SCSI_LOW_DEBUG */
100879697Snon
100979697Snon	switch (ccb->ccb_h.func_code) {
101079697Snon	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
101179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
101279697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
101379697Snon		{
101479697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
101579697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
101679697Snon			xpt_done(ccb);
101779697Snon			return;
101879697Snon		}
101979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
102079697Snon
102179697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
102279697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
102379697Snon			xpt_done(ccb);
102479697Snon			return;
102579697Snon		}
102679697Snon
102779697Snon		ti = slp->sl_ti[target];
102879697Snon		cb->osdep = ccb;
102979697Snon		cb->bp = NULL;
103079697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
103179697Snon			flags = CCB_AUTOSENSE | CCB_SCSIIO;
103279697Snon		else
103379697Snon			flags = CCB_SCSIIO;
103479697Snon
103579697Snon		s = SCSI_LOW_SPLSCSI();
103679697Snon		li = scsi_low_alloc_li(ti, lun, 1);
103779697Snon
103879697Snon		if (ti->ti_setup_msg != 0)
103979697Snon		{
104079697Snon			scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
104179697Snon		}
104279697Snon
104379697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
104479697Snon
104579697Snon#ifdef	SCSI_LOW_DEBUG
104679697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
104779697Snon		{
104879697Snon			scsi_low_test_abort(slp, ti, li);
104979697Snon		}
105079697Snon#endif	/* SCSI_LOW_DEBUG */
105179697Snon		splx(s);
105279697Snon		break;
105379697Snon
105479697Snon	case XPT_EN_LUN:		/* Enable LUN as a target */
105579697Snon	case XPT_TARGET_IO:		/* Execute target I/O request */
105679697Snon	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
105779697Snon	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
105879697Snon		/* XXX Implement */
105979697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
106079697Snon		xpt_done(ccb);
106179697Snon		break;
106279697Snon
106379697Snon	case XPT_ABORT:			/* Abort the specified CCB */
106479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
106579697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
106679697Snon		{
106779697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
106879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
106979697Snon			xpt_done(ccb);
107079697Snon			return;
107179697Snon		}
107279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
107379697Snon
107479697Snon		s = SCSI_LOW_SPLSCSI();
107579697Snon		cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
107679697Snon		rv = scsi_low_abort_ccb(slp, cb);
107779697Snon		splx(s);
107879697Snon
107979697Snon		if (rv == 0)
108079697Snon			ccb->ccb_h.status = CAM_REQ_CMP;
108179697Snon		else
108279697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
108379697Snon		xpt_done(ccb);
108479697Snon		break;
108579697Snon
108679697Snon	case XPT_SET_TRAN_SETTINGS: {
1087163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
1088163816Smjacob		struct ccb_trans_settings_scsi *scsi;
1089163816Smjacob        	struct ccb_trans_settings_spi *spi;
1090163816Smjacob#endif
109179697Snon		struct ccb_trans_settings *cts;
109279697Snon		u_int val;
109379697Snon
109479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
109579697Snon		if (target == CAM_TARGET_WILDCARD)
109679697Snon		{
109779697Snon			printf("%s: invalid target\n", slp->sl_xname);
109879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
109979697Snon			xpt_done(ccb);
110079697Snon			return;
110179697Snon		}
110279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
110379697Snon		cts = &ccb->cts;
110479697Snon		ti = slp->sl_ti[target];
110579697Snon		if (lun == CAM_LUN_WILDCARD)
110679697Snon			lun = 0;
110779697Snon
110879697Snon		s = SCSI_LOW_SPLSCSI();
1109163816Smjacob#ifndef	CAM_NEW_TRAN_CODE
111079697Snon		if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID |
111179697Snon				   CCB_TRANS_SYNC_RATE_VALID |
111279697Snon				   CCB_TRANS_SYNC_OFFSET_VALID)) != 0)
111379697Snon		{
111479697Snon			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
111579697Snon				val = cts->bus_width;
111679697Snon				if (val < ti->ti_width)
111779697Snon					ti->ti_width = val;
111879697Snon			}
111979697Snon			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
112079697Snon				val = cts->sync_period;
112179697Snon				if (val == 0 || val > ti->ti_maxsynch.period)
112279697Snon					ti->ti_maxsynch.period = val;
112379697Snon			}
112479697Snon			if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
112579697Snon				val = cts->sync_offset;
112679697Snon				if (val < ti->ti_maxsynch.offset)
112779697Snon					ti->ti_maxsynch.offset = val;
112879697Snon			}
112979697Snon
113079697Snon			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
113179697Snon			scsi_low_calcf_target(ti);
113279697Snon		}
113379697Snon
113479697Snon		if ((cts->valid & (CCB_TRANS_DISC_VALID |
113579697Snon				   CCB_TRANS_TQ_VALID)) != 0)
113679697Snon		{
113779697Snon			li = scsi_low_alloc_li(ti, lun, 1);
113879697Snon			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0)
113979697Snon			{
114079697Snon				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
114179697Snon					li->li_quirks |= SCSI_LOW_DISK_DISC;
114279697Snon				else
114379697Snon					li->li_quirks &= ~SCSI_LOW_DISK_DISC;
114479697Snon			}
114579697Snon			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0)
114679697Snon			{
114779697Snon				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
114879697Snon					li->li_quirks |= SCSI_LOW_DISK_QTAG;
114979697Snon				else
115079697Snon					li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
115179697Snon			}
115279697Snon
115379697Snon			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
115479697Snon			scsi_low_calcf_target(ti);
115579697Snon			scsi_low_calcf_lun(li);
115679697Snon			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
115779697Snon				scsi_low_calcf_show(li);
115879697Snon		}
1159163816Smjacob#else
1160163816Smjacob		scsi = &cts->proto_specific.scsi;
1161163816Smjacob		spi = &cts->xport_specific.spi;
1162163816Smjacob		if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH |
1163163816Smjacob				   CTS_SPI_VALID_SYNC_RATE |
1164163816Smjacob				   CTS_SPI_VALID_SYNC_OFFSET)) != 0)
1165163816Smjacob		{
1166163816Smjacob			if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
1167163816Smjacob				val = spi->bus_width;
1168163816Smjacob				if (val < ti->ti_width)
1169163816Smjacob					ti->ti_width = val;
1170163816Smjacob			}
1171163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_RATE) {
1172163816Smjacob				val = spi->sync_period;
1173163816Smjacob				if (val == 0 || val > ti->ti_maxsynch.period)
1174163816Smjacob					ti->ti_maxsynch.period = val;
1175163816Smjacob			}
1176163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
1177163816Smjacob				val = spi->sync_offset;
1178163816Smjacob				if (val < ti->ti_maxsynch.offset)
1179163816Smjacob					ti->ti_maxsynch.offset = val;
1180163816Smjacob			}
1181163816Smjacob			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
1182163816Smjacob			scsi_low_calcf_target(ti);
1183163816Smjacob		}
1184163816Smjacob
1185163816Smjacob		if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 ||
1186163816Smjacob                    (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
1187163816Smjacob
1188163816Smjacob			li = scsi_low_alloc_li(ti, lun, 1);
1189163816Smjacob			if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) {
1190163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_DISC;
1191163816Smjacob			} else {
1192163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_DISC;
1193163816Smjacob			}
1194163816Smjacob
1195163816Smjacob			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
1196163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_QTAG;
1197163816Smjacob			} else {
1198163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
1199163816Smjacob			}
1200163816Smjacob			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
1201163816Smjacob			scsi_low_calcf_target(ti);
1202163816Smjacob			scsi_low_calcf_lun(li);
1203163816Smjacob			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
1204163816Smjacob				scsi_low_calcf_show(li);
1205163816Smjacob		}
1206163816Smjacob#endif
120779697Snon		splx(s);
120879697Snon
120979697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
121079697Snon		xpt_done(ccb);
121179697Snon		break;
121279697Snon	}
121379697Snon
121479697Snon	case XPT_GET_TRAN_SETTINGS: {
121579697Snon		struct ccb_trans_settings *cts;
121679697Snon		u_int diskflags;
121779697Snon
121879697Snon		cts = &ccb->cts;
121979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
122079697Snon		if (target == CAM_TARGET_WILDCARD)
122179697Snon		{
122279697Snon			printf("%s: invalid target\n", slp->sl_xname);
122379697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
122479697Snon			xpt_done(ccb);
122579697Snon			return;
122679697Snon		}
122779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
122879697Snon		ti = slp->sl_ti[target];
122979697Snon		if (lun == CAM_LUN_WILDCARD)
123079697Snon			lun = 0;
123179697Snon
123279697Snon		s = SCSI_LOW_SPLSCSI();
123379697Snon		li = scsi_low_alloc_li(ti, lun, 1);
123479697Snon#ifdef CAM_NEW_TRAN_CODE
123579697Snon		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
123679697Snon			struct ccb_trans_settings_scsi *scsi =
123779697Snon				&cts->proto_specific.scsi;
123879697Snon			struct ccb_trans_settings_spi *spi =
123979697Snon				&cts->xport_specific.spi;
124079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
124179697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
124279697Snon			{
124379697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
124479697Snon				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
124579697Snon					slp->sl_xname);
124679697Snon				goto settings_out;
124779697Snon			}
124879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
124979697Snon			cts->protocol = PROTO_SCSI;
125079697Snon			cts->protocol_version = SCSI_REV_2;
125179697Snon			cts->transport = XPORT_SPI;
125279697Snon			cts->transport_version = 2;
125379697Snon
125479697Snon			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
125579697Snon			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
125679697Snon
125779697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
125879697Snon			if (diskflags & SCSI_LOW_DISK_DISC)
125979697Snon				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
126079697Snon			if (diskflags & SCSI_LOW_DISK_QTAG)
126179697Snon				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
126279697Snon
126379697Snon			spi->sync_period = ti->ti_maxsynch.period;
126479697Snon			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
126579697Snon			spi->sync_offset = ti->ti_maxsynch.offset;
126679697Snon			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
126779697Snon
126879697Snon			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
126979697Snon			spi->bus_width = ti->ti_width;
127079697Snon
127179697Snon			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
127279697Snon				scsi->valid = CTS_SCSI_VALID_TQ;
127379697Snon				spi->valid |= CTS_SPI_VALID_DISC;
127479697Snon			} else
127579697Snon				scsi->valid = 0;
127679697Snon		} else
127779697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
127879697Snon#else
127979697Snon 		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
128079697Snon 		{
128179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
128279697Snon			if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0)
128379697Snon			{
128479697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
128579697Snon				printf("%s: invalid GET_TRANS_USER_SETTINGS call\n",
128679697Snon					slp->sl_xname);
128779697Snon				goto settings_out;
128879697Snon			}
128979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
129079697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
129179697Snon			if ((diskflags & SCSI_LOW_DISK_DISC) != 0)
129279697Snon				cts->flags |= CCB_TRANS_DISC_ENB;
129379697Snon			else
129479697Snon				cts->flags &= ~CCB_TRANS_DISC_ENB;
129579697Snon			if ((diskflags & SCSI_LOW_DISK_QTAG) != 0)
129679697Snon				cts->flags |= CCB_TRANS_TAG_ENB;
129779697Snon			else
129879697Snon				cts->flags &= ~CCB_TRANS_TAG_ENB;
129979697Snon		}
130079697Snon		else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
130179697Snon		{
130279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
130379697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
130479697Snon			{
130579697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
130679697Snon				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
130779697Snon					slp->sl_xname);
130879697Snon				goto settings_out;
130979697Snon			}
131079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
131179697Snon			if ((li->li_flags & SCSI_LOW_DISC) != 0)
131279697Snon				cts->flags |= CCB_TRANS_DISC_ENB;
131379697Snon			else
131479697Snon				cts->flags &= ~CCB_TRANS_DISC_ENB;
131579697Snon			if ((li->li_flags & SCSI_LOW_QTAG) != 0)
131679697Snon				cts->flags |= CCB_TRANS_TAG_ENB;
131779697Snon			else
131879697Snon				cts->flags &= ~CCB_TRANS_TAG_ENB;
131979697Snon		}
132079697Snon		else
132179697Snon		{
132279697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
132379697Snon			goto settings_out;
132479697Snon		}
132579697Snon
132679697Snon		cts->sync_period = ti->ti_maxsynch.period;
132779697Snon		cts->sync_offset = ti->ti_maxsynch.offset;
132879697Snon		cts->bus_width = ti->ti_width;
132979697Snon
133079697Snon		cts->valid = CCB_TRANS_SYNC_RATE_VALID
133179697Snon			   | CCB_TRANS_SYNC_OFFSET_VALID
133279697Snon			   | CCB_TRANS_BUS_WIDTH_VALID
133379697Snon			   | CCB_TRANS_DISC_VALID
133479697Snon			   | CCB_TRANS_TQ_VALID;
133579697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
133679697Snon#endif
133779697Snonsettings_out:
133879697Snon		splx(s);
133979697Snon		xpt_done(ccb);
134079697Snon		break;
134179697Snon	}
134279697Snon
134379697Snon	case XPT_CALC_GEOMETRY: { /* not yet HN2 */
1344116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
134579697Snon		xpt_done(ccb);
134679697Snon		break;
134779697Snon	}
134879697Snon
134979697Snon	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
135079697Snon		s = SCSI_LOW_SPLSCSI();
135179697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
135279697Snon		splx(s);
135379697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
135479697Snon		xpt_done(ccb);
135579697Snon		break;
135679697Snon
135779697Snon	case XPT_TERM_IO:	/* Terminate the I/O process */
135879697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
135979697Snon		xpt_done(ccb);
136079697Snon		break;
136179697Snon
136279697Snon	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
136379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
136479697Snon		if (target == CAM_TARGET_WILDCARD)
136579697Snon		{
136679697Snon			printf("%s: invalid target\n", slp->sl_xname);
136779697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
136879697Snon			xpt_done(ccb);
136979697Snon			return;
137079697Snon		}
137179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
137279697Snon
137379697Snon		msg = SCSI_LOW_MSG_RESET;
137479697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
137579697Snon		{
137679697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
137779697Snon			xpt_done(ccb);
137879697Snon			return;
137979697Snon		}
138079697Snon
138179697Snon		ti = slp->sl_ti[target];
138279697Snon		if (lun == CAM_LUN_WILDCARD)
138379697Snon			lun = 0;
138479697Snon		cb->osdep = ccb;
138579697Snon		cb->bp = NULL;
138679697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
138779697Snon			flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
138879697Snon		else
138979697Snon			flags = CCB_NORETRY | CCB_URGENT;
139079697Snon
139179697Snon		s = SCSI_LOW_SPLSCSI();
139279697Snon		li = scsi_low_alloc_li(ti, lun, 1);
139379697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, msg);
139479697Snon		splx(s);
139579697Snon		break;
139679697Snon
139779697Snon	case XPT_PATH_INQ: {		/* Path routing inquiry */
139879697Snon		struct ccb_pathinq *cpi = &ccb->cpi;
139979697Snon
140079697Snon		cpi->version_num = scsi_low_version_major;
140179697Snon		cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
140279697Snon		ti = slp->sl_ti[slp->sl_hostid];	/* host id */
140379697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
140479697Snon			cpi->hba_inquiry |= PI_WIDE_16;
140579697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
140679697Snon			cpi->hba_inquiry |= PI_WIDE_32;
140779697Snon		if (ti->ti_maxsynch.offset > 0)
140879697Snon			cpi->hba_inquiry |= PI_SDTR_ABLE;
140979697Snon		cpi->target_sprt = 0;
141079697Snon		cpi->hba_misc = 0;
141179697Snon		cpi->hba_eng_cnt = 0;
141279697Snon		cpi->max_target = slp->sl_ntargs - 1;
141379697Snon		cpi->max_lun = slp->sl_nluns - 1;
141479697Snon		cpi->initiator_id = slp->sl_hostid;
141579697Snon		cpi->bus_id = cam_sim_bus(sim);
141679697Snon		cpi->base_transfer_speed = 3300;
141779697Snon#ifdef CAM_NEW_TRAN_CODE
141879697Snon		cpi->transport = XPORT_SPI;
141979697Snon		cpi->transport_version = 2;
142079697Snon		cpi->protocol = PROTO_SCSI;
142179697Snon		cpi->protocol_version = SCSI_REV_2;
142279697Snon#endif
142379697Snon		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
142479697Snon		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
142579697Snon		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
142679697Snon		cpi->unit_number = cam_sim_unit(sim);
142779697Snon		cpi->ccb_h.status = CAM_REQ_CMP;
142879697Snon		xpt_done(ccb);
142979697Snon		break;
143079697Snon	}
143179697Snon
143279697Snon	default:
143379697Snon	        printf("scsi_low: non support func_code = %d ",
143479697Snon			ccb->ccb_h.func_code);
143579697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
143679697Snon		xpt_done(ccb);
143779697Snon		break;
143879697Snon	}
143979697Snon}
144079697Snon
144179697Snonstatic int
144279697Snonscsi_low_attach_cam(slp)
144379697Snon	struct scsi_low_softc *slp;
144479697Snon{
144579697Snon	struct cam_devq *devq;
144679697Snon	int tagged_openings;
144779697Snon
144879697Snon	sprintf(slp->sl_xname, "%s%d",
144979697Snon		DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev));
145079697Snon
145179697Snon	devq = cam_simq_alloc(SCSI_LOW_NCCB);
145279697Snon	if (devq == NULL)
145379697Snon		return (ENOMEM);
145479697Snon
145579697Snon	/*
145679697Snon	 * ask the adapter what subunits are present
145779697Snon	 */
145879697Snon	tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
145979697Snon	slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
146079697Snon				scsi_low_poll_cam,
146179697Snon				DEVPORT_DEVNAME(slp->sl_dev), slp,
146279697Snon				DEVPORT_DEVUNIT(slp->sl_dev),
146379697Snon				slp->sl_openings, tagged_openings, devq);
146479697Snon
146579697Snon	if (slp->sl_si.sim == NULL) {
146679697Snon		cam_simq_free(devq);
146779697Snon	 	return ENODEV;
146879697Snon	}
146979697Snon
147079697Snon	if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) {
1471147723Savatar		free(slp->sl_si.sim, M_SCSILOW);
147279697Snon	 	return ENODEV;
147379697Snon	}
147479697Snon
147579697Snon	if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL,
147679697Snon			cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD,
147779697Snon			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
147879697Snon		xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
147979697Snon		cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE);
148079697Snon		return ENODEV;
148179697Snon	}
148279697Snon
148379697Snon	slp->sl_show_result = SHOW_CALCF_RES;		/* OK ? */
148479697Snon	return 0;
148579697Snon}
148679697Snon
148779697Snonstatic int
148879697Snonscsi_low_world_start_cam(slp)
148979697Snon	struct scsi_low_softc *slp;
149079697Snon{
149179697Snon
149279697Snon	if (!cold)
149379697Snon		scsi_low_rescan_bus_cam(slp);
149479697Snon	return 0;
149579697Snon}
149679697Snon
149779697Snonstatic int
149879697Snonscsi_low_dettach_cam(slp)
149979697Snon	struct scsi_low_softc *slp;
150079697Snon{
150179697Snon
150279697Snon	xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL);
150379697Snon	xpt_free_path(slp->sl_si.path);
150479697Snon	xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
150579697Snon	cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE);
150679697Snon	return 0;
150779697Snon}
150879697Snon
150979697Snonstatic int
151079697Snonscsi_low_ccb_setup_cam(slp, cb)
151179697Snon	struct scsi_low_softc *slp;
151279697Snon	struct slccb *cb;
151379697Snon{
151479697Snon        union ccb *ccb = (union ccb *) cb->osdep;
151579697Snon
151679697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
151779697Snon	{
151879697Snon		cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
151979697Snon		cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
152079697Snon		cb->ccb_scp.scp_data = ccb->csio.data_ptr;
152179697Snon		cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
152279697Snon		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
152379697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
152479697Snon		else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
152579697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_READ;
152679697Snon		cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
152779697Snon	}
152879697Snon	else
152979697Snon	{
153079697Snon		scsi_low_unit_ready_cmd(cb);
153179697Snon	}
153279697Snon	return SCSI_LOW_START_QTAG;
153379697Snon}
153479697Snon
153579697Snonstatic int
153679697Snonscsi_low_done_cam(slp, cb)
153779697Snon	struct scsi_low_softc *slp;
153879697Snon	struct slccb *cb;
153979697Snon{
154079697Snon	union ccb *ccb;
154179697Snon
154279697Snon	ccb = (union ccb *) cb->osdep;
154379697Snon	if (cb->ccb_error == 0)
154479697Snon	{
154579697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
154679697Snon		ccb->csio.resid = 0;
154779697Snon	}
154879697Snon	else
154979697Snon	{
155079697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
155179697Snon			cb->ccb_error |= ABORTIO;
155279697Snon
155379697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
155479697Snon		    (cb->ccb_error & ABORTIO) == 0)
155579697Snon			return EJUSTRETURN;
155679697Snon
155779697Snon		if ((cb->ccb_error & SENSEIO) != 0)
155879697Snon		{
155979697Snon			memcpy(&ccb->csio.sense_data,
156079697Snon			       &cb->ccb_sense,
156179697Snon			       sizeof(ccb->csio.sense_data));
156279697Snon		}
156379697Snon
156479697Snon		ccb->ccb_h.status = scsi_low_translate_error_code(cb,
156579697Snon					&scsi_low_error_code_cam[0]);
156679697Snon
156779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
156879697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
156979697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
157079697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
157179697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
157279697Snon		{
157379697Snon			printf("%s: WARNING: scsi_low IO abort\n",
157479697Snon				slp->sl_xname);
157579697Snon			scsi_low_print(slp, NULL);
157679697Snon		}
157779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
157879697Snon	}
157979697Snon
158079697Snon	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
158179697Snon		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
158279697Snon
158379697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
158479697Snon		ccb->csio.scsi_status = 0;	/* XXX */
158579697Snon	else
158679697Snon		ccb->csio.scsi_status = cb->ccb_scp.scp_status;
158779697Snon
158879697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
158979697Snon		xpt_done(ccb);
159079697Snon	return 0;
159179697Snon}
159279697Snon
159379697Snonstatic void
159479697Snonscsi_low_timeout_cam(slp, ch, action)
159579697Snon	struct scsi_low_softc *slp;
159679697Snon	int ch;
159779697Snon	int action;
159879697Snon{
159979697Snon
160079697Snon	switch (ch)
160179697Snon	{
160279697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
160379697Snon		switch (action)
160479697Snon		{
160579697Snon		case SCSI_LOW_TIMEOUT_START:
160679697Snon			slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp,
160779697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
160879697Snon			break;
160979697Snon		case SCSI_LOW_TIMEOUT_STOP:
161079697Snon			untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch);
161179697Snon			break;
161279697Snon		}
161379697Snon		break;
161479697Snon
161579697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
161679697Snon		switch (action)
161779697Snon		{
161879697Snon		case SCSI_LOW_TIMEOUT_START:
161979697Snon			slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1);
162079697Snon			break;
162179697Snon		case SCSI_LOW_TIMEOUT_STOP:
162279697Snon			untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch);
162379697Snon			break;
162479697Snon		}
162579697Snon		break;
162679697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
162779697Snon		break;
162879697Snon	}
162979697Snon}
163079697Snon
163179697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
163279697Snon
163379697Snon/*=============================================================
163479697Snon * END OF OS switch  (All OS depend fucntions should be above)
163579697Snon =============================================================*/
163679697Snon
163779697Snon/**************************************************************
163879697Snon * scsi low deactivate and activate
163979697Snon **************************************************************/
164079697Snonint
164179697Snonscsi_low_is_busy(slp)
164279697Snon	struct scsi_low_softc *slp;
164379697Snon{
164479697Snon
164579697Snon	if (slp->sl_nio > 0)
164679697Snon		return EBUSY;
164779697Snon	return 0;
164879697Snon}
164979697Snon
165079697Snonint
165179697Snonscsi_low_deactivate(slp)
165279697Snon	struct scsi_low_softc *slp;
165379697Snon{
165479697Snon	int s;
165579697Snon
165679697Snon	s = SCSI_LOW_SPLSCSI();
165779697Snon	slp->sl_flags |= HW_INACTIVE;
165879697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
165979697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP);
166079697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
166179697Snon		(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
166279697Snon	splx(s);
166379697Snon	return 0;
166479697Snon}
166579697Snon
166679697Snonint
166779697Snonscsi_low_activate(slp)
166879697Snon	struct scsi_low_softc *slp;
166979697Snon{
167079697Snon	int error, s;
167179697Snon
167279697Snon	s = SCSI_LOW_SPLSCSI();
167379697Snon	slp->sl_flags &= ~HW_INACTIVE;
167479697Snon	if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
167579697Snon	{
167679697Snon		slp->sl_flags |= HW_INACTIVE;
167779697Snon		splx(s);
167879697Snon		return error;
167979697Snon	}
168079697Snon
168179697Snon	slp->sl_timeout_count = 0;
168279697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
168379697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
168479697Snon	splx(s);
168579697Snon	return 0;
168679697Snon}
168779697Snon
168879697Snon/**************************************************************
168979697Snon * scsi low log
169079697Snon **************************************************************/
169179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
169292770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *);
169392770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int);
169492770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int);
169579697Snon
169679697Snonstatic void
169779697Snonscsi_low_msg_log_init(slmlp)
169879697Snon	struct scsi_low_msg_log *slmlp;
169979697Snon{
170079697Snon
170179697Snon	slmlp->slml_ptr = 0;
170279697Snon}
170379697Snon
170479697Snonstatic void
170579697Snonscsi_low_msg_log_write(slmlp, datap, len)
170679697Snon	struct scsi_low_msg_log *slmlp;
170779697Snon	u_int8_t *datap;
170879697Snon	int len;
170979697Snon{
171079697Snon	int ptr, ind;
171179697Snon
171279697Snon	if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
171379697Snon		return;
171479697Snon
171579697Snon	ptr = slmlp->slml_ptr ++;
171679697Snon	for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
171779697Snon		slmlp->slml_msg[ptr].msg[ind] = datap[ind];
171879697Snon	for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
171979697Snon		slmlp->slml_msg[ptr].msg[ind] = 0;
172079697Snon}
172179697Snon
172279697Snonstatic void
172379697Snonscsi_low_msg_log_show(slmlp, s, len)
172479697Snon	struct scsi_low_msg_log *slmlp;
172579697Snon	char *s;
172679697Snon	int len;
172779697Snon{
172879697Snon	int ptr, ind;
172979697Snon
173079697Snon	printf("%s: (%d) ", s, slmlp->slml_ptr);
173179697Snon	for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
173279697Snon	{
173379697Snon		for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
173479697Snon		     ind ++)
173579697Snon		{
173679697Snon			printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
173779697Snon		}
173879697Snon		printf(">");
173979697Snon	}
174079697Snon	printf("\n");
174179697Snon}
174279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
174379697Snon
174479697Snon/**************************************************************
174567468Snon * power control
174667468Snon **************************************************************/
174767468Snonstatic void
174867468Snonscsi_low_engage(arg)
174967468Snon	void *arg;
175067468Snon{
175167468Snon	struct scsi_low_softc *slp = arg;
175279697Snon	int s = SCSI_LOW_SPLSCSI();
175367468Snon
175467468Snon	switch (slp->sl_rstep)
175567468Snon	{
175667468Snon	case 0:
175767468Snon		slp->sl_rstep ++;
175867468Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
175979697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
176079697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START);
176167468Snon		break;
176267468Snon
176367468Snon	case 1:
176467468Snon		slp->sl_rstep ++;
176567468Snon		slp->sl_flags &= ~HW_RESUME;
176667468Snon		scsi_low_start(slp);
176767468Snon		break;
176867468Snon
176967468Snon	case 2:
177067468Snon		break;
177167468Snon	}
177267468Snon	splx(s);
177367468Snon}
177467468Snon
177567468Snonstatic int
177667468Snonscsi_low_init(slp, flags)
177767468Snon	struct scsi_low_softc *slp;
177867468Snon	u_int flags;
177967468Snon{
178079697Snon	int rv = 0;
178167468Snon
178279697Snon	slp->sl_flags |= HW_INITIALIZING;
178379697Snon
178479697Snon	/* clear power control timeout */
178567468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
178667468Snon	{
178779697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
178879697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
178967468Snon		slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
179067468Snon		slp->sl_active = 1;
179167468Snon		slp->sl_powc = SCSI_LOW_POWDOWN_TC;
179267468Snon	}
179367468Snon
179467468Snon	/* reset current nexus */
179567468Snon	scsi_low_reset_nexus(slp, flags);
179667468Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
179779697Snon	{
179879697Snon		rv = EBUSY;
179979697Snon		goto out;
180079697Snon	}
180167468Snon
180279697Snon	if (flags != SCSI_LOW_RESTART_SOFT)
180379697Snon	{
180479697Snon		rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
180579697Snon	}
180667468Snon
180779697Snonout:
180879697Snon	slp->sl_flags &= ~HW_INITIALIZING;
180979697Snon	return rv;
181067468Snon}
181167468Snon
181267468Snon/**************************************************************
181367468Snon * allocate lun_info
181467468Snon **************************************************************/
181567468Snonstatic struct lun_info *
181667468Snonscsi_low_alloc_li(ti, lun, alloc)
181767468Snon	struct targ_info *ti;
181867468Snon	int lun;
181967468Snon	int alloc;
182067468Snon{
182179697Snon	struct scsi_low_softc *slp = ti->ti_sc;
182267468Snon	struct lun_info *li;
182367468Snon
182467468Snon	li = LIST_FIRST(&ti->ti_litab);
182567468Snon	if (li != NULL)
182667468Snon	{
182767468Snon		if (li->li_lun == lun)
182867468Snon			return li;
182967468Snon
183067468Snon		while ((li = LIST_NEXT(li, lun_chain)) != NULL)
183167468Snon		{
183267468Snon			if (li->li_lun == lun)
183367468Snon			{
183467468Snon				LIST_REMOVE(li, lun_chain);
183567468Snon				LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
183667468Snon				return li;
183767468Snon			}
183867468Snon		}
183967468Snon	}
184067468Snon
184167468Snon	if (alloc == 0)
184267468Snon		return li;
184367468Snon
184479697Snon	li = SCSI_LOW_MALLOC(ti->ti_lunsize);
184567468Snon	if (li == NULL)
1846106890Simp		panic("no lun info mem");
184767468Snon
184879697Snon	SCSI_LOW_BZERO(li, ti->ti_lunsize);
184967468Snon	li->li_lun = lun;
185067468Snon	li->li_ti = ti;
185167468Snon
185279697Snon	li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
185379697Snon			  SCSI_LOW_QTAG;
185479697Snon	li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
185579697Snon	li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
185679697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
185779697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
185879697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
185979697Snon
186079697Snon	li->li_qtagbits = (u_int) -1;
186179697Snon
186279697Snon	TAILQ_INIT(&li->li_discq);
186367468Snon	LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
186467468Snon
186579697Snon	/* host specific structure initialization per lun */
186679697Snon	if (slp->sl_funcs->scsi_low_lun_init != NULL)
186779697Snon		(*slp->sl_funcs->scsi_low_lun_init)
186879697Snon			(slp, ti, li, SCSI_LOW_INFO_ALLOC);
186979697Snon	scsi_low_calcf_lun(li);
187067468Snon	return li;
187167468Snon}
187267468Snon
187367468Snon/**************************************************************
187467468Snon * allocate targ_info
187567468Snon **************************************************************/
187667468Snonstatic struct targ_info *
187779697Snonscsi_low_alloc_ti(slp, targ)
187867468Snon	struct scsi_low_softc *slp;
187979697Snon	int targ;
188067468Snon{
188167468Snon	struct targ_info *ti;
188267468Snon
188371999Sphk	if (TAILQ_FIRST(&slp->sl_titab) == NULL)
188467468Snon		TAILQ_INIT(&slp->sl_titab);
188567468Snon
188679697Snon	ti = SCSI_LOW_MALLOC(slp->sl_targsize);
188767468Snon	if (ti == NULL)
1888106890Simp		panic("%s short of memory", slp->sl_xname);
188967468Snon
189079697Snon	SCSI_LOW_BZERO(ti, slp->sl_targsize);
189167468Snon	ti->ti_id = targ;
189267468Snon	ti->ti_sc = slp;
189367468Snon
189467468Snon	slp->sl_ti[targ] = ti;
189567468Snon	TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
189667468Snon	LIST_INIT(&ti->ti_litab);
189767468Snon
189879697Snon	ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
189979697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
190079697Snon	ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
190179697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
190279697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
190379697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
190473025Snon
190579697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
190679697Snon	{
190779697Snon		(*slp->sl_funcs->scsi_low_targ_init)
190879697Snon			(slp, ti, SCSI_LOW_INFO_ALLOC);
190979697Snon	}
191079697Snon	scsi_low_calcf_target(ti);
191167468Snon	return ti;
191267468Snon}
191367468Snon
191467468Snonstatic void
191567468Snonscsi_low_free_ti(slp)
191667468Snon	struct scsi_low_softc *slp;
191767468Snon{
191867468Snon	struct targ_info *ti, *tib;
191967468Snon	struct lun_info *li, *nli;
192067468Snon
192171999Sphk	for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
192267468Snon	{
192367468Snon		for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
192467468Snon		{
192579697Snon			if (slp->sl_funcs->scsi_low_lun_init != NULL)
192679697Snon			{
192779697Snon				(*slp->sl_funcs->scsi_low_lun_init)
192879697Snon					(slp, ti, li, SCSI_LOW_INFO_DEALLOC);
192979697Snon			}
193067468Snon			nli = LIST_NEXT(li, lun_chain);
193179697Snon			SCSI_LOW_FREE(li);
193267468Snon		}
193379697Snon
193479697Snon		if (slp->sl_funcs->scsi_low_targ_init != NULL)
193579697Snon		{
193679697Snon			(*slp->sl_funcs->scsi_low_targ_init)
193779697Snon				(slp, ti, SCSI_LOW_INFO_DEALLOC);
193879697Snon		}
193979697Snon		tib = TAILQ_NEXT(ti, ti_chain);
194079697Snon		SCSI_LOW_FREE(ti);
194167468Snon	}
194267468Snon}
194367468Snon
194467468Snon/**************************************************************
194567468Snon * timeout
194667468Snon **************************************************************/
194767468Snonvoid
194879697Snonscsi_low_bus_idle(slp)
194979697Snon	struct scsi_low_softc *slp;
195079697Snon{
195179697Snon
195279697Snon	slp->sl_retry_sel = 0;
195379697Snon	if (slp->sl_Tnexus == NULL)
195479697Snon		scsi_low_start(slp);
195579697Snon}
195679697Snon
195779697Snonstatic void
195867468Snonscsi_low_timeout(arg)
195967468Snon	void *arg;
196067468Snon{
196167468Snon	struct scsi_low_softc *slp = arg;
196279697Snon	int s;
196379697Snon
196479697Snon	s = SCSI_LOW_SPLSCSI();
196579697Snon	(void) scsi_low_timeout_check(slp);
196679697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
196779697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
196879697Snon	splx(s);
196979697Snon}
197079697Snon
197179697Snonstatic int
197279697Snonscsi_low_timeout_check(slp)
197379697Snon	struct scsi_low_softc *slp;
197479697Snon{
197567468Snon	struct targ_info *ti;
197679697Snon	struct lun_info *li;
197767468Snon	struct slccb *cb = NULL;		/* XXX */
197867468Snon
197979697Snon	/* selection restart */
198079697Snon	if (slp->sl_retry_sel != 0)
198167468Snon	{
198279697Snon		slp->sl_retry_sel = 0;
198379697Snon		if (slp->sl_Tnexus != NULL)
198479697Snon			goto step1;
198567468Snon
198679697Snon		cb = TAILQ_FIRST(&slp->sl_start);
198779697Snon		if (cb == NULL)
198879697Snon			goto step1;
198979697Snon
199079697Snon		if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
199167468Snon		{
199279697Snon			cb->ccb_flags |= CCB_NORETRY;
199379697Snon			cb->ccb_error |= SELTIMEOUTIO;
199479697Snon			if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1995106890Simp				panic("%s: ccb not finished", slp->sl_xname);
199667468Snon		}
199779697Snon
199879697Snon		if (slp->sl_Tnexus == NULL)
199979697Snon			scsi_low_start(slp);
200067468Snon	}
200179697Snon
200279697Snon	/* call hardware timeout */
200379697Snonstep1:
200479697Snon	if (slp->sl_funcs->scsi_low_timeout != NULL)
200567468Snon	{
200679697Snon		(*slp->sl_funcs->scsi_low_timeout) (slp);
200779697Snon	}
200879697Snon
200979697Snon	if (slp->sl_timeout_count ++ <
201079697Snon	    SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
201179697Snon		return 0;
201279697Snon
201379697Snon	slp->sl_timeout_count = 0;
201479697Snon	if (slp->sl_nio > 0)
201579697Snon	{
201679697Snon		if ((cb = slp->sl_Qnexus) != NULL)
201767468Snon		{
201867468Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
201967468Snon			if (cb->ccb_tc < 0)
202067468Snon				goto bus_reset;
202167468Snon		}
202279697Snon		else if (slp->sl_disc == 0)
202367468Snon		{
202479697Snon		        if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
202579697Snon				return 0;
202667468Snon
202779697Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
202879697Snon			if (cb->ccb_tc < 0)
202979697Snon				goto bus_reset;
203079697Snon		}
203179697Snon		else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
203279697Snon		          ti = TAILQ_NEXT(ti, ti_chain))
203379697Snon		{
203479697Snon			if (ti->ti_disc == 0)
203579697Snon				continue;
203667468Snon
203779697Snon			for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
203879697Snon			     li = LIST_NEXT(li, lun_chain))
203967468Snon			{
204079697Snon				for (cb = TAILQ_FIRST(&li->li_discq);
204179697Snon				     cb != NULL;
204279697Snon				     cb = TAILQ_NEXT(cb, ccb_chain))
204379697Snon				{
204479697Snon					cb->ccb_tc -=
204579697Snon						SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
204679697Snon					if (cb->ccb_tc < 0)
204779697Snon						goto bus_reset;
204879697Snon				}
204967468Snon			}
205067468Snon		}
205179697Snon
205267468Snon	}
205379697Snon	else if ((slp->sl_flags & HW_POWERCTRL) != 0)
205479697Snon	{
205579697Snon		if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
205679697Snon			return 0;
205767468Snon
205879697Snon		if (slp->sl_active != 0)
205979697Snon		{
206079697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
206179697Snon			slp->sl_active = 0;
206279697Snon			return 0;
206379697Snon		}
206467468Snon
206579697Snon		slp->sl_powc --;
206679697Snon		if (slp->sl_powc < 0)
206779697Snon		{
206879697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
206979697Snon			slp->sl_flags |= HW_POWDOWN;
207079697Snon			(*slp->sl_funcs->scsi_low_power)
207179697Snon					(slp, SCSI_LOW_POWDOWN);
207279697Snon		}
207379697Snon	}
207479697Snon	return 0;
207567468Snon
207667468Snonbus_reset:
207767468Snon	cb->ccb_error |= TIMEOUTIO;
207879697Snon	printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb);
207967468Snon	scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
208067468Snon	scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
208167468Snon	scsi_low_start(slp);
208279697Snon	return ERESTART;
208367468Snon}
208467468Snon
208567468Snon
208679697Snonstatic int
208779697Snonscsi_low_abort_ccb(slp, cb)
208879697Snon	struct scsi_low_softc *slp;
208979697Snon	struct slccb *cb;
209079697Snon{
209179697Snon	struct targ_info *ti;
209279697Snon	struct lun_info *li;
209379697Snon	u_int msg;
209467468Snon
209579697Snon	if (cb == NULL)
209679697Snon		return EINVAL;
209779697Snon	if ((cb->ccb_omsgoutflag &
209879697Snon	     (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
209979697Snon		return EBUSY;
210067468Snon
210179697Snon	ti = cb->ti;
210279697Snon	li = cb->li;
210379697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
210479697Snon		msg = SCSI_LOW_MSG_ABORT;
210579697Snon	else
210679697Snon		msg = SCSI_LOW_MSG_ABORT_QTAG;
210767468Snon
210879697Snon	cb->ccb_error |= ABORTIO;
210979697Snon	cb->ccb_flags |= CCB_NORETRY;
211079697Snon	scsi_low_ccb_message_assert(cb, msg);
211167468Snon
211279697Snon	if (cb == slp->sl_Qnexus)
211379697Snon	{
211479697Snon		scsi_low_assert_msg(slp, ti, msg, 1);
211579697Snon	}
211679697Snon	else if ((cb->ccb_flags & CCB_DISCQ) != 0)
211779697Snon	{
211879697Snon		if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
2119106890Simp			panic("%s: revoked ccb done", slp->sl_xname);
212067468Snon
212179697Snon		cb->ccb_flags |= CCB_STARTQ;
212279697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
212367468Snon
212479697Snon		if (slp->sl_Tnexus == NULL)
212579697Snon			scsi_low_start(slp);
212679697Snon	}
212779697Snon	else
212879697Snon	{
212979697Snon		if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
2130106890Simp			panic("%s: revoked ccb retried", slp->sl_xname);
213179697Snon	}
213279697Snon	return 0;
213367468Snon}
213467468Snon
213579697Snon/**************************************************************
213679697Snon * Generic SCSI INTERFACE
213779697Snon **************************************************************/
213867468Snonint
213979697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
214067468Snon	struct scsi_low_softc *slp;
214179697Snon	int openings, ntargs, nluns, targsize, lunsize;
214267468Snon{
214367468Snon	struct targ_info *ti;
214467468Snon	struct lun_info *li;
214579697Snon	int s, i, nccb, rv;
214667468Snon
214779697Snon#ifdef	SCSI_LOW_INTERFACE_XS
214879697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs;
214979697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
215079697Snon#ifdef	SCSI_LOW_INTERFACE_CAM
215179697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam;
215279697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
215379697Snon
215479697Snon	if (slp->sl_osdep_fp == NULL)
2155106890Simp		panic("scsi_low: interface not spcified");
215679697Snon
215767468Snon	if (ntargs > SCSI_LOW_NTARGETS)
215867468Snon	{
215967468Snon		printf("scsi_low: %d targets are too large\n", ntargs);
216067468Snon		printf("change kernel options SCSI_LOW_NTARGETS");
216179697Snon		return EINVAL;
216267468Snon	}
216367468Snon
216479697Snon	if (openings <= 0)
216579697Snon		slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
216679697Snon	else
216779697Snon		slp->sl_openings = openings;
216879697Snon	slp->sl_ntargs = ntargs;
216979697Snon	slp->sl_nluns = nluns;
217079697Snon	slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
217167468Snon
217279697Snon	if (lunsize < sizeof(struct lun_info))
217379697Snon		lunsize = sizeof(struct lun_info);
217479697Snon
217579697Snon	if (targsize < sizeof(struct targ_info))
217679697Snon		targsize = sizeof(struct targ_info);
217779697Snon
217879697Snon	slp->sl_targsize = targsize;
217967468Snon	for (i = 0; i < ntargs; i ++)
218067468Snon	{
218179697Snon		ti = scsi_low_alloc_ti(slp, i);
218279697Snon		ti->ti_lunsize = lunsize;
218367468Snon		li = scsi_low_alloc_li(ti, 0, 1);
218467468Snon	}
218567468Snon
218667468Snon	/* initialize queue */
218779697Snon	nccb = openings * ntargs;
218867468Snon	if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
218967468Snon		nccb = SCSI_LOW_NCCB;
219067468Snon	scsi_low_init_ccbque(nccb);
219167468Snon	TAILQ_INIT(&slp->sl_start);
219267468Snon
219379697Snon	/* call os depend attach */
219479697Snon	s = SCSI_LOW_SPLSCSI();
219579697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp);
219679697Snon	if (rv != 0)
219779697Snon	{
219879697Snon		splx(s);
219979697Snon		printf("%s: scsi_low_attach: osdep attach failed\n",
220079697Snon			slp->sl_xname);
220179697Snon		return EINVAL;
220279697Snon	}
220367468Snon
220479697Snon	/* check hardware */
220579697Snon	SCSI_LOW_DELAY(1000);	/* wait for 1ms */
220679697Snon	if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
220779697Snon	{
220879697Snon		splx(s);
220979697Snon		printf("%s: scsi_low_attach: initialization failed\n",
221079697Snon			slp->sl_xname);
221179697Snon		return EINVAL;
221279697Snon	}
221367468Snon
221467468Snon	/* start watch dog */
221579697Snon	slp->sl_timeout_count = 0;
221679697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
221779697Snon		 (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
221879697Snon	LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
221967468Snon
222079697Snon	/* fake call */
222179697Snon	scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
222267468Snon
222379697Snon#ifdef	SCSI_LOW_START_UP_CHECK
222479697Snon	/* probing devices */
222579697Snon	scsi_low_start_up(slp);
222679697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
222767468Snon
222879697Snon	/* call os depend attach done*/
222979697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp);
223079697Snon	splx(s);
223179697Snon	return 0;
223267468Snon}
223367468Snon
223467468Snonint
223567468Snonscsi_low_dettach(slp)
223667468Snon	struct scsi_low_softc *slp;
223767468Snon{
223879697Snon	int s, rv;
223967468Snon
224079697Snon	s = SCSI_LOW_SPLSCSI();
224179697Snon	if (scsi_low_is_busy(slp) != 0)
224279697Snon	{
224379697Snon		splx(s);
224467468Snon		return EBUSY;
224579697Snon	}
224667468Snon
224779697Snon	scsi_low_deactivate(slp);
224867468Snon
224979697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp);
225079697Snon	if (rv != 0)
225179697Snon	{
225279697Snon		splx(s);
225379697Snon		return EBUSY;
225479697Snon	}
225567468Snon
225667468Snon	scsi_low_free_ti(slp);
225779697Snon	LIST_REMOVE(slp, sl_chain);
225879697Snon	splx(s);
225967468Snon	return 0;
226067468Snon}
226167468Snon
226279697Snon/**************************************************************
226379697Snon * Generic enqueue
226479697Snon **************************************************************/
226579697Snonstatic int
226679697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg)
226779697Snon	struct scsi_low_softc *slp;
226867468Snon	struct targ_info *ti;
226967468Snon	struct lun_info *li;
227067468Snon	struct slccb *cb;
227179697Snon	u_int flags, msg;
227279697Snon{
227367468Snon
227479697Snon	cb->ti = ti;
227579697Snon	cb->li = li;
227667468Snon
227779697Snon	scsi_low_ccb_message_assert(cb, msg);
227867468Snon
227979697Snon	cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
228079697Snon	scsi_low_alloc_qtag(cb);
228167468Snon
228279697Snon	cb->ccb_flags = flags | CCB_STARTQ;
228379697Snon	cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
228479697Snon	cb->ccb_error |= PENDINGIO;
228579697Snon
228679697Snon	if ((flags & CCB_URGENT) != 0)
228779697Snon	{
228879697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
228979697Snon	}
229079697Snon	else
229179697Snon	{
229267468Snon		TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
229379697Snon	}
229467468Snon
229579697Snon	slp->sl_nio ++;
229667468Snon
229779697Snon	if (slp->sl_Tnexus == NULL)
229879697Snon		scsi_low_start(slp);
229979697Snon	return 0;
230079697Snon}
230167468Snon
230279697Snonstatic int
230379697Snonscsi_low_message_enqueue(slp, ti, li, flags)
230479697Snon	struct scsi_low_softc *slp;
230579697Snon	struct targ_info *ti;
230679697Snon	struct lun_info *li;
230779697Snon	u_int flags;
230879697Snon{
230979697Snon	struct slccb *cb;
231079697Snon	u_int tmsgflags;
231167468Snon
231279697Snon	tmsgflags = ti->ti_setup_msg;
231379697Snon	ti->ti_setup_msg = 0;
231467468Snon
231579697Snon	flags |= CCB_NORETRY;
231679697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
231779697Snon		return ENOMEM;
231867468Snon
231979697Snon	cb->osdep = NULL;
232079697Snon	cb->bp = NULL;
232179697Snon	scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
232279697Snon	return 0;
232379697Snon}
232467468Snon
232579697Snon/**************************************************************
232679697Snon * Generic Start & Done
232779697Snon **************************************************************/
232879697Snon#define	SLSC_MODE_SENSE_SHORT   0x1a
232979697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
233079697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
233179697Snon			      sizeof(struct scsi_low_mode_sense_data), 0};
233279697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
233379697Snon			      sizeof(struct scsi_low_inq_data), 0};
233479697Snonstatic u_int8_t unit_ready_cmd[6];
233592770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
233692770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
233792770Salfredstatic int scsi_low_resume(struct scsi_low_softc *);
233879697Snon
233979697Snonstatic void
234079697Snonscsi_low_unit_ready_cmd(cb)
234179697Snon	struct slccb *cb;
234279697Snon{
234379697Snon
234479697Snon	cb->ccb_scp.scp_cmd = unit_ready_cmd;
234579697Snon	cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
234679697Snon	cb->ccb_scp.scp_datalen = 0;
234779697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
234879697Snon	cb->ccb_tcmax = 15;
234967468Snon}
235079697Snon
235167468Snonstatic int
235279697Snonscsi_low_sense_abort_start(slp, ti, li, cb)
235379697Snon	struct scsi_low_softc *slp;
235467468Snon	struct targ_info *ti;
235579697Snon	struct lun_info *li;
235667468Snon	struct slccb *cb;
235779697Snon{
235867468Snon
235979697Snon	cb->ccb_scp.scp_cmdlen = 6;
236079697Snon	SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
236179697Snon	cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
236279697Snon	cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
236379697Snon	cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
236479697Snon	cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
236579697Snon	cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
236679697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
236779697Snon	cb->ccb_tcmax = 15;
236879697Snon	scsi_low_ccb_message_clear(cb);
236979697Snon	if ((cb->ccb_flags & CCB_CLEARQ) != 0)
237067468Snon	{
237179697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
237267468Snon	}
237379697Snon	else
237479697Snon	{
237579697Snon		SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense));
237679697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
237779697Snon		scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
237879697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
237979697Snon	}
238067468Snon
238179697Snon	return SCSI_LOW_START_NO_QTAG;
238279697Snon}
238367468Snon
238479697Snonstatic int
238579697Snonscsi_low_setup_start(slp, ti, li, cb)
238679697Snon	struct scsi_low_softc *slp;
238779697Snon	struct targ_info *ti;
238879697Snon	struct lun_info *li;
238979697Snon	struct slccb *cb;
239079697Snon{
239167468Snon
239279697Snon	switch(li->li_state)
239379697Snon	{
239479697Snon	case SCSI_LOW_LUN_SLEEP:
239579697Snon		scsi_low_unit_ready_cmd(cb);
239679697Snon		break;
239767468Snon
239879697Snon	case SCSI_LOW_LUN_START:
239979697Snon		cb->ccb_scp.scp_cmd = ss_cmd;
240079697Snon		cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
240179697Snon		cb->ccb_scp.scp_datalen = 0;
240279697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
240379697Snon		cb->ccb_tcmax = 30;
240479697Snon		break;
240567468Snon
240679697Snon	case SCSI_LOW_LUN_INQ:
240779697Snon		cb->ccb_scp.scp_cmd = inq_cmd;
240879697Snon		cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
240979697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
241079697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
241179697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
241279697Snon		cb->ccb_tcmax = 15;
241379697Snon		break;
241467468Snon
241579697Snon	case SCSI_LOW_LUN_MODEQ:
241679697Snon		cb->ccb_scp.scp_cmd = sms_cmd;
241779697Snon		cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
241879697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
241979697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
242079697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
242179697Snon		cb->ccb_tcmax = 15;
242279697Snon		return SCSI_LOW_START_QTAG;
242367468Snon
242479697Snon	default:
2425106890Simp		panic("%s: no setup phase", slp->sl_xname);
242667468Snon	}
242767468Snon
242879697Snon	return SCSI_LOW_START_NO_QTAG;
242967468Snon}
243067468Snon
243179697Snonstatic int
243279697Snonscsi_low_resume(slp)
243379697Snon	struct scsi_low_softc *slp;
243467468Snon{
243567468Snon
243679697Snon	if (slp->sl_flags & HW_RESUME)
243779697Snon		return EJUSTRETURN;
243879697Snon	slp->sl_flags &= ~HW_POWDOWN;
243979697Snon	if (slp->sl_funcs->scsi_low_power != NULL)
244079697Snon	{
244179697Snon		slp->sl_flags |= HW_RESUME;
244279697Snon		slp->sl_rstep = 0;
244379697Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
244479697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
244579697Snon					(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE,
244679697Snon				         SCSI_LOW_TIMEOUT_START);
244779697Snon		return EJUSTRETURN;
244879697Snon	}
244979697Snon	return 0;
245067468Snon}
245167468Snon
245267468Snonstatic void
245367468Snonscsi_low_start(slp)
245467468Snon	struct scsi_low_softc *slp;
245567468Snon{
245667468Snon	struct targ_info *ti;
245767468Snon	struct lun_info *li;
245867468Snon	struct slccb *cb;
245967468Snon	int rv;
246067468Snon
246179697Snon	/* check hardware exists or under initializations ? */
246279697Snon	if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
246367468Snon		return;
246467468Snon
246567468Snon	/* check hardware power up ? */
246667468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
246767468Snon	{
246867468Snon		slp->sl_active ++;
246967468Snon		if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
247067468Snon		{
247179697Snon			if (scsi_low_resume(slp) == EJUSTRETURN)
247267468Snon				return;
247367468Snon		}
247467468Snon	}
247567468Snon
247667468Snon	/* setup nexus */
247767468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
247879697Snon	if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
247967468Snon	{
248067468Snon		scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
2481106890Simp		panic("%s: inconsistent", slp->sl_xname);
248267468Snon	}
248367468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
248467468Snon
248579697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
248679697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
248767468Snon	{
248867468Snon		li = cb->li;
248979697Snon
249079697Snon		if (li->li_disc == 0)
249179697Snon		{
249267468Snon			goto scsi_low_cmd_start;
249379697Snon		}
249479697Snon		else if (li->li_nqio > 0)
249579697Snon		{
249679697Snon			if (li->li_nqio < li->li_maxnqio ||
249779697Snon		            (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
249879697Snon				goto scsi_low_cmd_start;
249979697Snon		}
250067468Snon	}
250167468Snon	return;
250267468Snon
250367468Snonscsi_low_cmd_start:
250479697Snon	cb->ccb_flags &= ~CCB_STARTQ;
250579697Snon	TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
250679697Snon	ti = cb->ti;
250767468Snon
250867468Snon	/* clear all error flag bits (for restart) */
250967468Snon	cb->ccb_error = 0;
251079697Snon	cb->ccb_datalen = -1;
251179697Snon	cb->ccb_scp.scp_status = ST_UNKNOWN;
251267468Snon
251367468Snon	/* setup nexus pointer */
251479697Snon	slp->sl_Qnexus = cb;
251579697Snon	slp->sl_Lnexus = li;
251679697Snon	slp->sl_Tnexus = ti;
251767468Snon
251867468Snon	/* initialize msgsys */
251967468Snon	scsi_low_init_msgsys(slp, ti);
252067468Snon
252179697Snon	/* exec cmd */
252279697Snon	if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
252367468Snon	{
252479697Snon		/* CA state or forced abort */
252579697Snon		rv = scsi_low_sense_abort_start(slp, ti, li, cb);
252667468Snon	}
252779697Snon	else if (li->li_state >= SCSI_LOW_LUN_OK)
252867468Snon	{
252979697Snon		cb->ccb_flags &= ~CCB_INTERNAL;
253079697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb);
253179697Snon		if (cb->ccb_msgoutflag != 0)
253279697Snon		{
253379697Snon			scsi_low_ccb_message_exec(slp, cb);
253479697Snon		}
253567468Snon	}
253679697Snon	else
253767468Snon	{
253879697Snon		cb->ccb_flags |= CCB_INTERNAL;
253979697Snon		rv = scsi_low_setup_start(slp, ti, li, cb);
254079697Snon	}
254167468Snon
254279697Snon	/* allocate qtag */
254379697Snon#define	SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
254467468Snon
254579697Snon	if (rv == SCSI_LOW_START_QTAG &&
254679697Snon	    (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
254779697Snon	    li->li_maxnqio > 0)
254879697Snon	{
254979697Snon		u_int qmsg;
255067468Snon
255179697Snon		scsi_low_activate_qtag(cb);
255279697Snon		if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
255379697Snon		     SCSI_LOW_CMD_ORDERED_QTAG) != 0)
255479697Snon			qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
255579697Snon		else if ((cb->ccb_flags & CCB_URGENT) != 0)
255679697Snon			qmsg = SCSI_LOW_MSG_HEAD_QTAG;
255779697Snon		else
255879697Snon			qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
255979697Snon		scsi_low_assert_msg(slp, ti, qmsg, 0);
256067468Snon	}
256167468Snon
256267468Snon	/* timeout */
256367468Snon	if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
256467468Snon		cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
256567468Snon	cb->ccb_tc = cb->ccb_tcmax;
256667468Snon
256767468Snon	/* setup saved scsi data pointer */
256867468Snon	cb->ccb_sscp = cb->ccb_scp;
256967468Snon
257067468Snon	/* setup current scsi pointer */
257167468Snon	slp->sl_scp = cb->ccb_sscp;
257267468Snon	slp->sl_error = cb->ccb_error;
257367468Snon
257479697Snon	/* assert always an identify msg */
257579697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
257679697Snon
257779697Snon	/* debug section */
257879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
257979697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
258079697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
258179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
258279697Snon
258367468Snon	/* selection start */
258479697Snon	slp->sl_selid = cb;
258567468Snon	rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
258667468Snon	if (rv == SCSI_LOW_START_OK)
258767468Snon	{
258867468Snon#ifdef	SCSI_LOW_STATICS
258967468Snon		scsi_low_statics.nexus_win ++;
259067468Snon#endif	/* SCSI_LOW_STATICS */
259167468Snon		return;
259267468Snon	}
259367468Snon
259479697Snon	scsi_low_arbit_fail(slp, cb);
259567468Snon#ifdef	SCSI_LOW_STATICS
259667468Snon	scsi_low_statics.nexus_fail ++;
259767468Snon#endif	/* SCSI_LOW_STATICS */
259867468Snon}
259967468Snon
260067468Snonvoid
260179697Snonscsi_low_arbit_fail(slp, cb)
260267468Snon	struct scsi_low_softc *slp;
260379697Snon	struct slccb *cb;
260479697Snon{
260579697Snon	struct targ_info *ti = cb->ti;
260679697Snon
260779697Snon	scsi_low_deactivate_qtag(cb);
260879697Snon	scsi_low_ccb_message_retry(cb);
260979697Snon	cb->ccb_flags |= CCB_STARTQ;
261079697Snon	TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
261179697Snon
261279697Snon	scsi_low_bus_release(slp, ti);
261379697Snon
261479697Snon	cb->ccb_selrcnt ++;
261579697Snon	if (slp->sl_disc == 0)
261679697Snon	{
261779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
261879697Snon		printf("%s: try selection again\n", slp->sl_xname);
261979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
262079697Snon		slp->sl_retry_sel = 1;
262179697Snon	}
262279697Snon}
262379697Snon
262479697Snonstatic void
262579697Snonscsi_low_bus_release(slp, ti)
262679697Snon	struct scsi_low_softc *slp;
262767468Snon	struct targ_info *ti;
262867468Snon{
262967468Snon
263079697Snon	if (ti->ti_disc > 0)
263179697Snon	{
263279697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
263379697Snon	}
263479697Snon	else
263579697Snon	{
263679697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
263779697Snon	}
263879697Snon
263967468Snon	/* clear all nexus pointer */
264079697Snon	slp->sl_Qnexus = NULL;
264179697Snon	slp->sl_Lnexus = NULL;
264279697Snon	slp->sl_Tnexus = NULL;
264367468Snon
264467468Snon	/* clear selection assert */
264567468Snon	slp->sl_selid = NULL;
264667468Snon
264767468Snon	/* clear nexus data */
264867468Snon	slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
264979697Snon
265079697Snon	/* clear phase change counter */
265179697Snon	slp->sl_ph_count = 0;
265267468Snon}
265367468Snon
265467468Snonstatic int
265579697Snonscsi_low_setup_done(slp, cb)
265667468Snon	struct scsi_low_softc *slp;
265767468Snon	struct slccb *cb;
265867468Snon{
265967468Snon	struct targ_info *ti;
266067468Snon	struct lun_info *li;
266167468Snon
266267468Snon	ti = cb->ti;
266367468Snon	li = cb->li;
266479697Snon
266579697Snon	if (cb->ccb_rcnt >= slp->sl_max_retry)
266667468Snon	{
266779697Snon		cb->ccb_error |= ABORTIO;
266879697Snon		return SCSI_LOW_DONE_COMPLETE;
266979697Snon	}
267079697Snon
267179697Snon	/* XXX: special huck for selection timeout */
267279697Snon	if (li->li_state == SCSI_LOW_LUN_SLEEP &&
267379697Snon	    (cb->ccb_error & SELTIMEOUTIO) != 0)
267479697Snon	{
267579697Snon		cb->ccb_error |= ABORTIO;
267679697Snon		return SCSI_LOW_DONE_COMPLETE;
267779697Snon	}
267879697Snon
267979697Snon	switch(li->li_state)
268079697Snon	{
268179697Snon	case SCSI_LOW_LUN_INQ:
268279697Snon		if (cb->ccb_error != 0)
268367468Snon		{
268479697Snon			li->li_diskflags &=
268579697Snon				~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
268679697Snon			if (li->li_lun > 0)
268779697Snon				goto resume;
268879697Snon			ti->ti_diskflags &=
268979697Snon				~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
269067468Snon		}
269179697Snon		else if ((li->li_inq.sd_version & 7) >= 2 ||
269279697Snon		         (li->li_inq.sd_len >= 4))
269367468Snon		{
269479697Snon			if ((li->li_inq.sd_support & 0x2) == 0)
269579697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
269679697Snon			if ((li->li_inq.sd_support & 0x8) == 0)
269779697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
269879697Snon			if (li->li_lun > 0)
269979697Snon				goto resume;
270079697Snon			if ((li->li_inq.sd_support & 0x10) == 0)
270179697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
270279697Snon			if ((li->li_inq.sd_support & 0x20) == 0)
270379697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
270479697Snon			if ((li->li_inq.sd_support & 0x40) == 0)
270579697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
270679697Snon		}
270779697Snon		else
270879697Snon		{
270979697Snon			li->li_diskflags &=
271079697Snon				~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
271179697Snon			if (li->li_lun > 0)
271279697Snon				goto resume;
271379697Snon			ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
271479697Snon		}
271579697Snon		ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
271679697Snonresume:
271779697Snon		scsi_low_calcf_target(ti);
271879697Snon		scsi_low_calcf_lun(li);
271979697Snon		break;
272079697Snon
272179697Snon	case SCSI_LOW_LUN_MODEQ:
272279697Snon		if (cb->ccb_error != 0)
272379697Snon		{
272479697Snon			if (cb->ccb_error & SENSEIO)
272567468Snon			{
272679697Snon#ifdef	SCSI_LOW_DEBUG
272779697Snon				if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
272879697Snon				{
272979697Snon					printf("SENSE: [%x][%x][%x][%x][%x]\n",
273079697Snon					(u_int) cb->ccb_sense.error_code,
273179697Snon					(u_int) cb->ccb_sense.segment,
273279697Snon					(u_int) cb->ccb_sense.flags,
273379697Snon					(u_int) cb->ccb_sense.add_sense_code,
273479697Snon					(u_int) cb->ccb_sense.add_sense_code_qual);
273579697Snon				}
273679697Snon#endif	/* SCSI_LOW_DEBUG */
273767468Snon			}
273879697Snon			else
273979697Snon			{
274079697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
274179697Snon			}
274279697Snon		}
274379697Snon		else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
274479697Snon		{
274579697Snon			if (li->li_sms.sms_cmp.cmp_qc & 0x02)
274679697Snon				li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
274779697Snon			else
274879697Snon				li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
274979697Snon			if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
275079697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
275179697Snon		}
275279697Snon		li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
275379697Snon		scsi_low_calcf_lun(li);
275479697Snon		break;
275567468Snon
275679697Snon	default:
275779697Snon		break;
275879697Snon	}
275979697Snon
276079697Snon	li->li_state ++;
276179697Snon	if (li->li_state == SCSI_LOW_LUN_OK)
276279697Snon	{
276379697Snon		scsi_low_calcf_target(ti);
276479697Snon		scsi_low_calcf_lun(li);
276579697Snon		if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
276679697Snon	            (slp->sl_show_result & SHOW_CALCF_RES) != 0)
276779697Snon		{
276879697Snon			scsi_low_calcf_show(li);
276979697Snon		}
277079697Snon	}
277179697Snon
277279697Snon	cb->ccb_rcnt --;
277379697Snon	return SCSI_LOW_DONE_RETRY;
277479697Snon}
277579697Snon
277679697Snonstatic int
277779697Snonscsi_low_done(slp, cb)
277879697Snon	struct scsi_low_softc *slp;
277979697Snon	struct slccb *cb;
278079697Snon{
278179697Snon	int rv;
278279697Snon
278379697Snon	if (cb->ccb_error == 0)
278479697Snon	{
278579697Snon		if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
278679697Snon		{
278779697Snon#ifdef	SCSI_LOW_QCLEAR_AFTER_CA
278879697Snon			/* XXX:
278979697Snon			 * SCSI-2 draft suggests
279079697Snon			 * page 0x0a QErr bit determins if
279179697Snon			 * the target aborts or continues
279279697Snon			 * the queueing io's after CA state resolved.
279379697Snon			 * However many targets seem not to support
279479697Snon			 * the page 0x0a. Thus we should manually clear the
279579697Snon			 * queuing io's after CA state.
279679697Snon			 */
279779697Snon			if ((cb->ccb_flags & CCB_CLEARQ) == 0)
279867468Snon			{
279979697Snon				cb->ccb_rcnt --;
280079697Snon				cb->ccb_flags |= CCB_CLEARQ;
280179697Snon				goto retry;
280279697Snon			}
280379697Snon#endif	/* SCSI_LOW_QCLEAR_AFTER_CA */
280479697Snon
280579697Snon			if ((cb->ccb_flags & CCB_SENSE) != 0)
280679697Snon				cb->ccb_error |= (SENSEIO | ABORTIO);
280779697Snon			cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
280879697Snon		}
280979697Snon		else switch (cb->ccb_sscp.scp_status)
281079697Snon		{
281179697Snon		case ST_GOOD:
281279697Snon		case ST_MET:
281379697Snon		case ST_INTERGOOD:
281479697Snon		case ST_INTERMET:
281579697Snon			if (cb->ccb_datalen == 0 ||
281679697Snon			    cb->ccb_scp.scp_datalen == 0)
281767468Snon				break;
281867468Snon
281979697Snon			if (cb->ccb_scp.scp_cmdlen > 0 &&
282079697Snon			    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
282179697Snon			     SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
282279697Snon				break;
282379697Snon
282467468Snon			cb->ccb_error |= PDMAERR;
282567468Snon			break;
282667468Snon
282779697Snon		case ST_BUSY:
282879697Snon		case ST_QUEFULL:
282979697Snon			cb->ccb_error |= (BUSYERR | STATERR);
283079697Snon			break;
283179697Snon
283279697Snon		case ST_CONFLICT:
283379697Snon			cb->ccb_error |= (STATERR | ABORTIO);
283479697Snon			break;
283579697Snon
283667468Snon		case ST_CHKCOND:
283779697Snon		case ST_CMDTERM:
283879697Snon			if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
283979697Snon			{
284079697Snon				cb->ccb_rcnt --;
284173025Snon				cb->ccb_flags |= CCB_SENSE;
284273025Snon				goto retry;
284373025Snon			}
284479697Snon			cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
284573025Snon			break;
284667468Snon
284779697Snon		case ST_UNKNOWN:
284867468Snon		default:
284967468Snon			cb->ccb_error |= FATALIO;
285067468Snon			break;
285167468Snon		}
285267468Snon	}
285367468Snon	else
285467468Snon	{
285579697Snon		if (cb->ccb_flags & CCB_SENSE)
285667468Snon		{
285779697Snon			cb->ccb_error |= (SENSEERR | ABORTIO);
285867468Snon		}
285979697Snon		cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
286079697Snon	}
286167468Snon
286279697Snon	/* internal ccb */
286379697Snon	if ((cb->ccb_flags & CCB_INTERNAL) != 0)
286479697Snon	{
286579697Snon		if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
286679697Snon			goto retry;
286767468Snon	}
286867468Snon
286979697Snon	/* check a ccb msgout flag */
287079697Snon	if (cb->ccb_omsgoutflag != 0)
287167468Snon	{
287279697Snon#define	SCSI_LOW_MSG_ABORT_OK	(SCSI_LOW_MSG_ABORT | \
287379697Snon				 SCSI_LOW_MSG_ABORT_QTAG | \
287479697Snon				 SCSI_LOW_MSG_CLEAR_QTAG | \
287579697Snon				 SCSI_LOW_MSG_TERMIO)
287679697Snon
287779697Snon		if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
287867468Snon		{
287979697Snon			cb->ccb_error |= ABORTIO;
288067468Snon		}
288167468Snon	}
288267468Snon
288379697Snon	/* call OS depend done */
288479697Snon	if (cb->osdep != NULL)
288567468Snon	{
288679697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb);
288779697Snon		if (rv == EJUSTRETURN)
288879697Snon			goto retry;
288967468Snon	}
289079697Snon	else if (cb->ccb_error != 0)
289167468Snon	{
289279697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
289379697Snon			cb->ccb_error |= ABORTIO;
289479697Snon
289579697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
289679697Snon		    (cb->ccb_error & ABORTIO) == 0)
289767468Snon			goto retry;
289867468Snon	}
289979697Snon
290079697Snon	/* free our target */
290179697Snon#ifdef	SCSI_LOW_DEBUG
290279697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
290367468Snon	{
290479697Snon		printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
290579697Snon		scsi_low_print(slp, NULL);
290667468Snon	}
290779697Snon#endif	/* SCSI_LOW_DEBUG */
290867468Snon
290979697Snon	scsi_low_deactivate_qtag(cb);
291079697Snon	scsi_low_dealloc_qtag(cb);
291167468Snon	scsi_low_free_ccb(cb);
291279697Snon	slp->sl_nio --;
291367468Snon	return SCSI_LOW_DONE_COMPLETE;
291467468Snon
291567468Snonretry:
291679697Snon#ifdef	SCSI_LOW_DEBUG
291779697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
291867468Snon	{
291979697Snon		printf("** SCSI_LOW_DONE_RETRY ===============\n");
292079697Snon		scsi_low_print(slp, NULL);
292167468Snon	}
292279697Snon#endif	/* SCSI_LOW_DEBUG */
292379697Snon
292479697Snon	cb->ccb_rcnt ++;
292579697Snon	scsi_low_deactivate_qtag(cb);
292679697Snon	scsi_low_ccb_message_retry(cb);
292767468Snon	return SCSI_LOW_DONE_RETRY;
292867468Snon}
292967468Snon
293067468Snon/**************************************************************
293167468Snon * Reset
293267468Snon **************************************************************/
293367468Snonstatic void
293479697Snonscsi_low_reset_nexus_target(slp, ti, fdone)
293579697Snon	struct scsi_low_softc *slp;
293679697Snon	struct targ_info *ti;
293779697Snon	int fdone;
293867468Snon{
293979697Snon	struct lun_info *li;
294067468Snon
294179697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
294279697Snon	     li = LIST_NEXT(li, lun_chain))
294379697Snon	{
294479697Snon		scsi_low_reset_nexus_lun(slp, li, fdone);
294579697Snon		li->li_state = SCSI_LOW_LUN_SLEEP;
294679697Snon		li->li_maxnqio = 0;
294779697Snon	}
294879697Snon
294979697Snon	ti->ti_disc = 0;
295079697Snon	ti->ti_setup_msg = 0;
295179697Snon	ti->ti_setup_msg_done = 0;
295279697Snon
295379697Snon	ti->ti_osynch.offset = ti->ti_osynch.period = 0;
295479697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
295579697Snon
295679697Snon	ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
295779697Snon	ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
295879697Snon
295979697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
296079697Snon	{
296179697Snon		((*slp->sl_funcs->scsi_low_targ_init)
296279697Snon			(slp, ti, SCSI_LOW_INFO_REVOKE));
296379697Snon	}
296479697Snon	scsi_low_calcf_target(ti);
296579697Snon
296679697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
296779697Snon	     li = LIST_NEXT(li, lun_chain))
296879697Snon	{
296979697Snon		li->li_flags = 0;
297079697Snon
297179697Snon		li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
297279697Snon		li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
297379697Snon
297479697Snon		if (slp->sl_funcs->scsi_low_lun_init != NULL)
297579697Snon		{
297679697Snon			((*slp->sl_funcs->scsi_low_lun_init)
297779697Snon				(slp, ti, li, SCSI_LOW_INFO_REVOKE));
297879697Snon		}
297979697Snon		scsi_low_calcf_lun(li);
298079697Snon	}
298167468Snon}
298267468Snon
298367468Snonstatic void
298467468Snonscsi_low_reset_nexus(slp, fdone)
298567468Snon	struct scsi_low_softc *slp;
298667468Snon	int fdone;
298767468Snon{
298867468Snon	struct targ_info *ti;
298979697Snon	struct slccb *cb, *topcb;
299067468Snon
299179697Snon	if ((cb = slp->sl_Qnexus) != NULL)
299267468Snon	{
299379697Snon		topcb = scsi_low_revoke_ccb(slp, cb, fdone);
299467468Snon	}
299579697Snon	else
299679697Snon	{
299779697Snon		topcb = NULL;
299879697Snon	}
299967468Snon
300079697Snon	for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
300179697Snon	     ti = TAILQ_NEXT(ti, ti_chain))
300267468Snon	{
300379697Snon		scsi_low_reset_nexus_target(slp, ti, fdone);
300479697Snon		scsi_low_bus_release(slp, ti);
300567468Snon		scsi_low_init_msgsys(slp, ti);
300667468Snon	}
300767468Snon
300879697Snon	if (topcb != NULL)
300979697Snon	{
301079697Snon		topcb->ccb_flags |= CCB_STARTQ;
301179697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
301279697Snon	}
301379697Snon
301479697Snon	slp->sl_disc = 0;
301579697Snon	slp->sl_retry_sel = 0;
301667468Snon	slp->sl_flags &= ~HW_PDMASTART;
301767468Snon}
301867468Snon
301967468Snon/* misc */
302067468Snonstatic int tw_pos;
302167468Snonstatic char tw_chars[] = "|/-\\";
302279697Snon#define	TWIDDLEWAIT		10000
302367468Snon
302467468Snonstatic void
302567468Snonscsi_low_twiddle_wait(void)
302667468Snon{
302767468Snon
302867468Snon	cnputc('\b');
302967468Snon	cnputc(tw_chars[tw_pos++]);
303067468Snon	tw_pos %= (sizeof(tw_chars) - 1);
303179697Snon	SCSI_LOW_DELAY(TWIDDLEWAIT);
303267468Snon}
303367468Snon
303467468Snonvoid
303567468Snonscsi_low_bus_reset(slp)
303667468Snon	struct scsi_low_softc *slp;
303767468Snon{
303867468Snon	int i;
303967468Snon
304067468Snon	(*slp->sl_funcs->scsi_low_bus_reset) (slp);
304167468Snon
304267468Snon	printf("%s: try to reset scsi bus  ", slp->sl_xname);
304367468Snon	for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++)
304467468Snon		scsi_low_twiddle_wait();
304567468Snon	cnputc('\b');
304667468Snon	printf("\n");
304767468Snon}
304867468Snon
304967468Snonint
305067468Snonscsi_low_restart(slp, flags, s)
305167468Snon	struct scsi_low_softc *slp;
305267468Snon	int flags;
305367468Snon	u_char *s;
305467468Snon{
305567468Snon	int error;
305667468Snon
305767468Snon	if (s != NULL)
305867468Snon		printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s);
305967468Snon
306067468Snon	if ((error = scsi_low_init(slp, flags)) != 0)
306167468Snon		return error;
306267468Snon
306367468Snon	scsi_low_start(slp);
306467468Snon	return 0;
306567468Snon}
306667468Snon
306767468Snon/**************************************************************
306867468Snon * disconnect and reselect
306967468Snon **************************************************************/
307067468Snon#define	MSGCMD_LUN(msg)	(msg & 0x07)
307167468Snon
307267468Snonstatic struct slccb *
307367468Snonscsi_low_establish_ccb(ti, li, tag)
307467468Snon	struct targ_info *ti;
307567468Snon	struct lun_info *li;
307667468Snon	scsi_low_tag_t tag;
307767468Snon{
307867468Snon	struct scsi_low_softc *slp = ti->ti_sc;
307967468Snon	struct slccb *cb;
308067468Snon
308179697Snon	if (li == NULL)
308279697Snon		return NULL;
308379697Snon
308479697Snon	cb = TAILQ_FIRST(&li->li_discq);
308571999Sphk	for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
308679697Snon		if (cb->ccb_tag == tag)
308767468Snon			goto found;
308867468Snon	return cb;
308967468Snon
309067468Snon	/*
309167468Snon	 * establish our ccb nexus
309267468Snon	 */
309367468Snonfound:
309479697Snon#ifdef	SCSI_LOW_DEBUG
309579697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
309679697Snon	{
309779697Snon		printf("%s: nexus(0x%lx) abort check start\n",
309879697Snon			slp->sl_xname, (u_long) cb);
309979697Snon		cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
310079697Snon		scsi_low_revoke_ccb(slp, cb, 1);
310179697Snon		return NULL;
310279697Snon	}
310367468Snon
310479697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
310579697Snon	{
310679697Snon		if (cb->ccb_omsgoutflag == 0)
310779697Snon			scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
310879697Snon	}
310979697Snon#endif	/* SCSI_LOW_DEBUG */
311079697Snon
311179697Snon	TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
311279697Snon	cb->ccb_flags &= ~CCB_DISCQ;
311379697Snon	slp->sl_Qnexus = cb;
311479697Snon
311567468Snon	slp->sl_scp = cb->ccb_sscp;
311667468Snon	slp->sl_error |= cb->ccb_error;
311767468Snon
311867468Snon	slp->sl_disc --;
311979697Snon	ti->ti_disc --;
312067468Snon	li->li_disc --;
312167468Snon
312267468Snon	/* inform "ccb nexus established" to the host driver */
312379697Snon	(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
312479697Snon
312579697Snon	/* check msg */
312679697Snon	if (cb->ccb_msgoutflag != 0)
312779697Snon	{
312879697Snon		scsi_low_ccb_message_exec(slp, cb);
312979697Snon	}
313079697Snon
313167468Snon	return cb;
313267468Snon}
313367468Snon
313467468Snonstruct targ_info *
313567468Snonscsi_low_reselected(slp, targ)
313667468Snon	struct scsi_low_softc *slp;
313767468Snon	u_int targ;
313867468Snon{
313967468Snon	struct targ_info *ti;
314079697Snon	struct slccb *cb;
314167468Snon	u_char *s;
314267468Snon
314367468Snon	/*
314467468Snon	 * Check select vs reselected collision.
314567468Snon	 */
314667468Snon
314779697Snon	if ((cb = slp->sl_selid) != NULL)
314867468Snon	{
314979697Snon		scsi_low_arbit_fail(slp, cb);
315067468Snon#ifdef	SCSI_LOW_STATICS
315167468Snon		scsi_low_statics.nexus_conflict ++;
315267468Snon#endif	/* SCSI_LOW_STATICS */
315367468Snon	}
315479697Snon
315579697Snon	/*
315679697Snon	 * Check if no current active nexus.
315779697Snon	 */
315879697Snon	if (slp->sl_Tnexus != NULL)
315967468Snon	{
316067468Snon		s = "host busy";
316167468Snon		goto world_restart;
316267468Snon	}
316367468Snon
316467468Snon	/*
316567468Snon	 * Check a valid target id asserted ?
316667468Snon	 */
316767468Snon	if (targ >= slp->sl_ntargs || targ == slp->sl_hostid)
316867468Snon	{
316967468Snon		s = "scsi id illegal";
317067468Snon		goto world_restart;
317167468Snon	}
317267468Snon
317367468Snon	/*
317467468Snon	 * Check the target scsi status.
317567468Snon	 */
317667468Snon	ti = slp->sl_ti[targ];
317779697Snon	if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
317867468Snon	{
317967468Snon		s = "phase mismatch";
318067468Snon		goto world_restart;
318167468Snon	}
318267468Snon
318367468Snon	/*
318479697Snon	 * Setup init msgsys
318567468Snon	 */
318667468Snon	slp->sl_error = 0;
318767468Snon	scsi_low_init_msgsys(slp, ti);
318867468Snon
318967468Snon	/*
319067468Snon	 * Establish our target nexus
319167468Snon	 */
319267468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
319379697Snon	slp->sl_Tnexus = ti;
319467468Snon#ifdef	SCSI_LOW_STATICS
319567468Snon	scsi_low_statics.nexus_reselected ++;
319667468Snon#endif	/* SCSI_LOW_STATICS */
319767468Snon	return ti;
319867468Snon
319967468Snonworld_restart:
320067468Snon	printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s);
320167468Snon	scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
320267468Snon		         "reselect: scsi world confused");
320367468Snon	return NULL;
320467468Snon}
320567468Snon
320667468Snon/**************************************************************
320767468Snon * cmd out pointer setup
320867468Snon **************************************************************/
320967468Snonint
321067468Snonscsi_low_cmd(slp, ti)
321167468Snon	struct scsi_low_softc *slp;
321267468Snon	struct targ_info *ti;
321367468Snon{
321479697Snon	struct slccb *cb = slp->sl_Qnexus;
321567468Snon
321679697Snon	slp->sl_ph_count ++;
321767468Snon	if (cb == NULL)
321867468Snon	{
321967468Snon		/*
322079697Snon		 * no ccb, abort!
322167468Snon		 */
322267468Snon		slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
322367468Snon		slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
322467468Snon		slp->sl_scp.scp_datalen = 0;
322567468Snon		slp->sl_scp.scp_direction = SCSI_LOW_READ;
322679697Snon		slp->sl_error |= FATALIO;
322779697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
322879697Snon		SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
322979697Snon		return EINVAL;
323067468Snon	}
323179697Snon	else
323267468Snon	{
323379697Snon#ifdef	SCSI_LOW_DEBUG
323479697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
323579697Snon		{
323679697Snon			scsi_low_test_cmdlnk(slp, cb);
323779697Snon		}
323879697Snon#endif	/* SCSI_LOW_DEBUG */
323967468Snon	}
324067468Snon	return 0;
324167468Snon}
324267468Snon
324367468Snon/**************************************************************
324467468Snon * data out pointer setup
324567468Snon **************************************************************/
324667468Snonint
324767468Snonscsi_low_data(slp, ti, bp, direction)
324867468Snon	struct scsi_low_softc *slp;
324967468Snon	struct targ_info *ti;
325067468Snon	struct buf **bp;
325167468Snon	int direction;
325267468Snon{
325379697Snon	struct slccb *cb = slp->sl_Qnexus;
325467468Snon
325579697Snon	if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
325667468Snon	{
325779697Snon		*bp = cb->bp;
325879697Snon		return 0;
325967468Snon	}
326067468Snon
326179697Snon	slp->sl_error |= (FATALIO | PDMAERR);
326279697Snon	slp->sl_scp.scp_datalen = 0;
326379697Snon	slp->sl_scp.scp_direction = direction;
326479697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
326579697Snon	if (ti->ti_ophase != ti->ti_phase)
326667468Snon	{
326779697Snon		char *s;
326879697Snon
326979697Snon		if (cb == NULL)
327079697Snon			s = "DATA PHASE: ccb nexus not found";
327179697Snon		else
327279697Snon			s = "DATA PHASE: xfer direction mismatch";
327379697Snon		SCSI_LOW_INFO(slp, ti, s);
327467468Snon	}
327567468Snon
327679697Snon	*bp = NULL;
327779697Snon	return EINVAL;
327867468Snon}
327967468Snon
328067468Snon/**************************************************************
328167468Snon * MSG_SYS
328267468Snon **************************************************************/
328367468Snon#define	MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
328467468Snon#define	MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
328567468Snon#define	MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
328679697Snon#define	MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
328767468Snon#define	MSGIN_DATA_LAST	0x30
328867468Snon
328992770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int);
329092770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int);
329192770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int);
329292770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int);
329367468Snon
329492770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *);
329592770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *);
329692770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *);
329792770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *);
329892770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *);
329992770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *);
330092770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *);
330167468Snon
330267468Snonstruct scsi_low_msgout_data {
330367468Snon	u_int	md_flags;
330467468Snon	u_int8_t md_msg;
330592770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
330692770Salfred	int (*md_errfunc)(struct scsi_low_softc *, u_int);
330779697Snon#define	MSG_RELEASE_ATN	0x0001
330879697Snon	u_int md_condition;
330967468Snon};
331067468Snon
331167468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = {
331279697Snon/* 0 */	{SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
331379697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
331479697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
331579697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
331679697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
331779697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
331879697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
331979697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG,  MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
332079697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
332179697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG,  MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
332279697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL,  MSG_RELEASE_ATN},
332379697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
332479697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
332579697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
332679697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
332779697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0},
332867468Snon};
332967468Snon
333092770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *);
333192770Salfredstatic int scsi_low_synch(struct scsi_low_softc *);
333292770Salfredstatic int scsi_low_wide(struct scsi_low_softc *);
333392770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *);
333492770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *);
333592770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *);
333692770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *);
333792770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *);
333892770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *);
333992770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *);
334092770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *);
334192770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *);
334292770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *);
334392770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *);
334467468Snon
334567468Snonstruct scsi_low_msgin_data {
334667468Snon	u_int md_len;
334792770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
334867468Snon};
334967468Snon
335067468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = {
335167468Snon/* 0 */	{1,	scsi_low_msginfunc_cc},
335267468Snon/* 1 */ {2,	scsi_low_msginfunc_ext},
335367468Snon/* 2 */ {1,	scsi_low_msginfunc_sdp},
335479697Snon/* 3 */ {1,	scsi_low_msginfunc_rp},
335567468Snon/* 4 */ {1,	scsi_low_msginfunc_disc},
335667468Snon/* 5 */ {1,	scsi_low_msginfunc_rejop},
335767468Snon/* 6 */ {1,	scsi_low_msginfunc_rejop},
335867468Snon/* 7 */ {1,	scsi_low_msginfunc_msg_reject},
335967468Snon/* 8 */ {1,	scsi_low_msginfunc_noop},
336067468Snon/* 9 */ {1,	scsi_low_msginfunc_parity},
336179697Snon/* a */ {1,	scsi_low_msginfunc_lcc},
336279697Snon/* b */ {1,	scsi_low_msginfunc_lcc},
336367468Snon/* c */ {1,	scsi_low_msginfunc_rejop},
336467468Snon/* d */ {2,	scsi_low_msginfunc_rejop},
336567468Snon/* e */ {1,	scsi_low_msginfunc_rejop},
336667468Snon/* f */ {1,	scsi_low_msginfunc_rejop},
336767468Snon/* 0x10 */ {1,	scsi_low_msginfunc_rejop},
336867468Snon/* 0x11 */ {1,	scsi_low_msginfunc_rejop},
336967468Snon/* 0x12 */ {1,	scsi_low_msginfunc_rejop},
337067468Snon/* 0x13 */ {1,	scsi_low_msginfunc_rejop},
337167468Snon/* 0x14 */ {1,	scsi_low_msginfunc_rejop},
337267468Snon/* 0x15 */ {1,	scsi_low_msginfunc_rejop},
337367468Snon/* 0x16 */ {1,	scsi_low_msginfunc_rejop},
337467468Snon/* 0x17 */ {1,	scsi_low_msginfunc_rejop},
337567468Snon/* 0x18 */ {1,	scsi_low_msginfunc_rejop},
337667468Snon/* 0x19 */ {1,	scsi_low_msginfunc_rejop},
337767468Snon/* 0x1a */ {1,	scsi_low_msginfunc_rejop},
337867468Snon/* 0x1b */ {1,	scsi_low_msginfunc_rejop},
337967468Snon/* 0x1c */ {1,	scsi_low_msginfunc_rejop},
338067468Snon/* 0x1d */ {1,	scsi_low_msginfunc_rejop},
338167468Snon/* 0x1e */ {1,	scsi_low_msginfunc_rejop},
338267468Snon/* 0x1f */ {1,	scsi_low_msginfunc_rejop},
338379697Snon/* 0x20 */ {2,	scsi_low_msginfunc_simple_qtag},
338467468Snon/* 0x21 */ {2,	scsi_low_msginfunc_rejop},
338567468Snon/* 0x22 */ {2,	scsi_low_msginfunc_rejop},
338679697Snon/* 0x23 */ {2,	scsi_low_msginfunc_i_wide_residue},
338767468Snon/* 0x24 */ {2,	scsi_low_msginfunc_rejop},
338867468Snon/* 0x25 */ {2,	scsi_low_msginfunc_rejop},
338967468Snon/* 0x26 */ {2,	scsi_low_msginfunc_rejop},
339067468Snon/* 0x27 */ {2,	scsi_low_msginfunc_rejop},
339167468Snon/* 0x28 */ {2,	scsi_low_msginfunc_rejop},
339267468Snon/* 0x29 */ {2,	scsi_low_msginfunc_rejop},
339367468Snon/* 0x2a */ {2,	scsi_low_msginfunc_rejop},
339467468Snon/* 0x2b */ {2,	scsi_low_msginfunc_rejop},
339567468Snon/* 0x2c */ {2,	scsi_low_msginfunc_rejop},
339667468Snon/* 0x2d */ {2,	scsi_low_msginfunc_rejop},
339767468Snon/* 0x2e */ {2,	scsi_low_msginfunc_rejop},
339867468Snon/* 0x2f */ {2,	scsi_low_msginfunc_rejop},
339967468Snon/* 0x30 */ {1,	scsi_low_msginfunc_rejop}	/* default rej op */
340067468Snon};
340167468Snon
340267468Snon/**************************************************************
340367468Snon * msgout
340467468Snon **************************************************************/
340567468Snonstatic int
340679697Snonscsi_low_msgfunc_synch(slp)
340779697Snon	struct scsi_low_softc *slp;
340867468Snon{
340979697Snon	struct targ_info *ti = slp->sl_Tnexus;
341067468Snon	int ptr = ti->ti_msgoutlen;
341167468Snon
341267468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
341367468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
341473025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
341573025Snon	ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset;
341667468Snon	return MSG_EXTEND_SYNCHLEN + 2;
341767468Snon}
341867468Snon
341967468Snonstatic int
342079697Snonscsi_low_msgfunc_wide(slp)
342179697Snon	struct scsi_low_softc *slp;
342267468Snon{
342379697Snon	struct targ_info *ti = slp->sl_Tnexus;
342467468Snon	int ptr = ti->ti_msgoutlen;
342567468Snon
342667468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
342767468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
342873025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
342967468Snon	return MSG_EXTEND_WIDELEN + 2;
343067468Snon}
343167468Snon
343267468Snonstatic int
343379697Snonscsi_low_msgfunc_identify(slp)
343479697Snon	struct scsi_low_softc *slp;
343567468Snon{
343679697Snon	struct targ_info *ti = slp->sl_Tnexus;
343779697Snon	struct lun_info *li = slp->sl_Lnexus;
343879697Snon	struct slccb *cb = slp->sl_Qnexus;
343979697Snon	int ptr = ti->ti_msgoutlen;
344079697Snon	u_int8_t msg;
344167468Snon
344279697Snon	msg = MSG_IDENTIFY;
344379697Snon	if (cb == NULL)
344467468Snon	{
344579697Snon		slp->sl_error |= FATALIO;
344679697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
344779697Snon		SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
344867468Snon	}
344967468Snon	else
345067468Snon	{
345179697Snon		if (scsi_low_is_disconnect_ok(cb) != 0)
345279697Snon			msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
345379697Snon		else
345479697Snon			msg |= li->li_lun;
345579697Snon
345679697Snon		if (ti->ti_phase == PH_MSGOUT)
345779697Snon		{
345879697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
345979697Snon			if (cb->ccb_tag == SCSI_LOW_UNKTAG)
346079697Snon			{
346179697Snon				(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
346279697Snon			}
346379697Snon		}
346467468Snon	}
346579697Snon	ti->ti_msgoutstr[ptr + 0] = msg;
346667468Snon	return 1;
346767468Snon}
346867468Snon
346967468Snonstatic int
347079697Snonscsi_low_msgfunc_abort(slp)
347179697Snon	struct scsi_low_softc *slp;
347267468Snon{
347367468Snon
347479697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
347579697Snon	return 1;
347679697Snon}
347779697Snon
347879697Snonstatic int
347979697Snonscsi_low_msgfunc_qabort(slp)
348079697Snon	struct scsi_low_softc *slp;
348179697Snon{
348279697Snon
348379697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
348479697Snon	return 1;
348579697Snon}
348679697Snon
348779697Snonstatic int
348879697Snonscsi_low_msgfunc_reset(slp)
348979697Snon	struct scsi_low_softc *slp;
349079697Snon{
349179697Snon
349279697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
349379697Snon	return 1;
349479697Snon}
349579697Snon
349679697Snonstatic int
349779697Snonscsi_low_msgfunc_qtag(slp)
349879697Snon	struct scsi_low_softc *slp;
349979697Snon{
350079697Snon	struct targ_info *ti = slp->sl_Tnexus;
350179697Snon	struct slccb *cb = slp->sl_Qnexus;
350279697Snon	int ptr = ti->ti_msgoutlen;
350379697Snon
350479697Snon	if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
350567468Snon	{
350667468Snon		ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
350767468Snon		return 1;
350867468Snon	}
350967468Snon	else
351067468Snon	{
351179697Snon		ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
351279697Snon		if (ti->ti_phase == PH_MSGOUT)
351379697Snon		{
351479697Snon			(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
351579697Snon		}
351667468Snon	}
351779697Snon	return 2;
351867468Snon}
351967468Snon
352067468Snon/*
352167468Snon * The following functions are called when targets give unexpected
352267468Snon * responces in msgin (after msgout).
352367468Snon */
352467468Snonstatic int
352579697Snonscsi_low_errfunc_identify(slp, msgflags)
352679697Snon	struct scsi_low_softc *slp;
352767468Snon	u_int msgflags;
352867468Snon{
352967468Snon
353079697Snon	if (slp->sl_Lnexus != NULL)
353179697Snon	{
353279697Snon	        slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
353379697Snon		scsi_low_calcf_lun(slp->sl_Lnexus);
353479697Snon	}
353567468Snon	return 0;
353667468Snon}
353767468Snon
353867468Snonstatic int
353979697Snonscsi_low_errfunc_synch(slp, msgflags)
354079697Snon	struct scsi_low_softc *slp;
354167468Snon	u_int msgflags;
354267468Snon{
354379697Snon	struct targ_info *ti = slp->sl_Tnexus;
354467468Snon
354567468Snon	MSGIN_PERIOD(ti) = 0;
354667468Snon	MSGIN_OFFSET(ti) = 0;
354779697Snon	scsi_low_synch(slp);
354867468Snon	return 0;
354967468Snon}
355067468Snon
355167468Snonstatic int
355279697Snonscsi_low_errfunc_wide(slp, msgflags)
355379697Snon	struct scsi_low_softc *slp;
355467468Snon	u_int msgflags;
355567468Snon{
355679697Snon	struct targ_info *ti = slp->sl_Tnexus;
355779697Snon
355879697Snon	MSGIN_WIDTHP(ti) = 0;
355979697Snon	scsi_low_wide(slp);
356067468Snon	return 0;
356167468Snon}
356267468Snon
356379697Snonstatic int
356479697Snonscsi_low_errfunc_qtag(slp, msgflags)
356579697Snon	struct scsi_low_softc *slp;
356679697Snon	u_int msgflags;
356779697Snon{
356879697Snon
356979697Snon	if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
357079697Snon	{
357179697Snon		if (slp->sl_Qnexus != NULL)
357279697Snon		{
357379697Snon			scsi_low_deactivate_qtag(slp->sl_Qnexus);
357479697Snon		}
357579697Snon		if (slp->sl_Lnexus != NULL)
357679697Snon		{
357779697Snon			slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
357879697Snon			scsi_low_calcf_lun(slp->sl_Lnexus);
357979697Snon		}
358079697Snon		printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname);
358179697Snon	}
358279697Snon	return 0;
358379697Snon}
358479697Snon
358579697Snon
358667468Snonint
358779697Snonscsi_low_msgout(slp, ti, fl)
358867468Snon	struct scsi_low_softc *slp;
358967468Snon	struct targ_info *ti;
359079697Snon	u_int fl;
359167468Snon{
359267468Snon	struct scsi_low_msgout_data *mdp;
359367468Snon	int len = 0;
359467468Snon
359579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
359679697Snon	if (ti != slp->sl_Tnexus)
359779697Snon	{
359879697Snon		scsi_low_print(slp, NULL);
359979697Snon		panic("scsi_low_msgout: Target nexus inconsistent");
360079697Snon	}
360179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
360279697Snon
360379697Snon	slp->sl_ph_count ++;
360479697Snon	if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
360579697Snon	{
360679697Snon		printf("%s: too many phase changes\n", slp->sl_xname);
360779697Snon		slp->sl_error |= FATALIO;
360879697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
360979697Snon	}
361079697Snon
361167468Snon	/* STEP I.
361267468Snon	 * Scsi phase changes.
361367468Snon	 * Previously msgs asserted are accepted by our target or
361467468Snon	 * processed by scsi_low_msgin.
361567468Snon	 * Thus clear all saved informations.
361667468Snon	 */
361779697Snon	if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
361867468Snon	{
361967468Snon		ti->ti_omsgflags = 0;
362067468Snon		ti->ti_emsgflags = 0;
362167468Snon	}
362279697Snon	else if (slp->sl_atten == 0)
362379697Snon	{
362467468Snon	/* STEP II.
362567468Snon	 * We did not assert attention, however still our target required
362667468Snon	 * msgs. Resend previous msgs.
362767468Snon	 */
362867468Snon		ti->ti_msgflags |= ti->ti_omsgflags;
362979697Snon		ti->ti_omsgflags = 0;
363067468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
363167468Snon		printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname);
363267468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
363367468Snon	}
363467468Snon
363567468Snon	/* STEP III.
363679697Snon	 * We have no msgs. send MSG_NOOP (OK?)
363767468Snon	 */
363879697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
363967468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
364067468Snon
364167468Snon	/* STEP IV.
364267468Snon	 * Process all msgs
364367468Snon	 */
364467468Snon	ti->ti_msgoutlen = 0;
364579697Snon	slp->sl_clear_atten = 0;
364667468Snon	mdp = &scsi_low_msgout_data[0];
364767468Snon	for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
364867468Snon	{
364967468Snon		if ((ti->ti_msgflags & mdp->md_flags) != 0)
365067468Snon		{
365167468Snon			ti->ti_omsgflags |= mdp->md_flags;
365267468Snon			ti->ti_msgflags &= ~mdp->md_flags;
365367468Snon			ti->ti_emsgflags = mdp->md_flags;
365467468Snon
365567468Snon			ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
365667468Snon			if (mdp->md_msgfunc != NULL)
365779697Snon				len = (*mdp->md_msgfunc) (slp);
365867468Snon			else
365967468Snon				len = 1;
366067468Snon
366179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
366279697Snon			scsi_low_msg_log_write(&ti->ti_log_msgout,
366379697Snon			       &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
366479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
366579697Snon
366667468Snon			ti->ti_msgoutlen += len;
366779697Snon			if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
366879697Snon			{
366979697Snon				slp->sl_clear_atten = 1;
367079697Snon				break;
367179697Snon			}
367279697Snon
367379697Snon			if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
367467468Snon			    ti->ti_msgflags == 0)
367567468Snon				break;
367679697Snon
367767468Snon			if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
367867468Snon				break;
367967468Snon		}
368067468Snon	}
368167468Snon
368279697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
368379697Snon		slp->sl_clear_atten = 1;
368467468Snon
368567468Snon	return ti->ti_msgoutlen;
368667468Snon}
368767468Snon
368867468Snon/**************************************************************
368967468Snon * msgin
369067468Snon **************************************************************/
369167468Snonstatic int
369279697Snonscsi_low_msginfunc_noop(slp)
369379697Snon	struct scsi_low_softc *slp;
369467468Snon{
369567468Snon
369667468Snon	return 0;
369767468Snon}
369867468Snon
369967468Snonstatic int
370079697Snonscsi_low_msginfunc_rejop(slp)
370179697Snon	struct scsi_low_softc *slp;
370267468Snon{
370379697Snon	struct targ_info *ti = slp->sl_Tnexus;
370467468Snon	u_int8_t msg = ti->ti_msgin[0];
370567468Snon
370679697Snon	printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg);
370767468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
370867468Snon	return 0;
370967468Snon}
371067468Snon
371167468Snonstatic int
371279697Snonscsi_low_msginfunc_cc(slp)
371379697Snon	struct scsi_low_softc *slp;
371467468Snon{
371579697Snon	struct lun_info *li;
371667468Snon
371767468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
371879697Snon
371979697Snon	/* validate status */
372079697Snon	if (slp->sl_Qnexus == NULL)
372179697Snon		return ENOENT;
372279697Snon
372379697Snon	slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
372479697Snon 	li = slp->sl_Lnexus;
372579697Snon	switch (slp->sl_scp.scp_status)
372679697Snon	{
372779697Snon	case ST_GOOD:
372879697Snon		li->li_maxnqio = li->li_maxnexus;
372979697Snon		break;
373079697Snon
373179697Snon	case ST_CHKCOND:
373279697Snon		li->li_maxnqio = 0;
373379697Snon		if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
373479697Snon			scsi_low_reset_nexus_lun(slp, li, 0);
373579697Snon		break;
373679697Snon
373779697Snon	case ST_BUSY:
373879697Snon		li->li_maxnqio = 0;
373979697Snon		break;
374079697Snon
374179697Snon	case ST_QUEFULL:
374279697Snon		if (li->li_maxnexus >= li->li_nqio)
374379697Snon			li->li_maxnexus = li->li_nqio - 1;
374479697Snon		li->li_maxnqio = li->li_maxnexus;
374579697Snon		break;
374679697Snon
374779697Snon	case ST_INTERGOOD:
374879697Snon	case ST_INTERMET:
374979697Snon		slp->sl_error |= MSGERR;
375079697Snon		break;
375179697Snon
375279697Snon	default:
375379697Snon		break;
375479697Snon	}
375567468Snon	return 0;
375667468Snon}
375767468Snon
375867468Snonstatic int
375979697Snonscsi_low_msginfunc_lcc(slp)
376079697Snon	struct scsi_low_softc *slp;
376179697Snon{
376267468Snon	struct targ_info *ti;
376379697Snon	struct lun_info *li;
376479697Snon	struct slccb *ncb, *cb;
376579697Snon
376679697Snon	ti = slp->sl_Tnexus;
376779697Snon 	li = slp->sl_Lnexus;
376879697Snon	if ((cb = slp->sl_Qnexus) == NULL)
376979697Snon		goto bad;
377079697Snon
377179697Snon	cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
377279697Snon	switch (slp->sl_scp.scp_status)
377379697Snon	{
377479697Snon	case ST_INTERGOOD:
377579697Snon	case ST_INTERMET:
377679697Snon		li->li_maxnqio = li->li_maxnexus;
377779697Snon		break;
377879697Snon
377979697Snon	default:
378079697Snon		slp->sl_error |= MSGERR;
378179697Snon		break;
378279697Snon	}
378379697Snon
378479697Snon	if ((li->li_flags & SCSI_LOW_LINK) == 0)
378579697Snon		goto bad;
378679697Snon
378779697Snon	cb->ccb_error |= slp->sl_error;
378879697Snon	if (cb->ccb_error != 0)
378979697Snon		goto bad;
379079697Snon
379179697Snon	for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
379279697Snon	     ncb = TAILQ_NEXT(ncb, ccb_chain))
379379697Snon	{
379479697Snon		if (ncb->li == li)
379579697Snon			goto cmd_link_start;
379679697Snon	}
379779697Snon
379879697Snon
379979697Snonbad:
380079697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
380179697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
380279697Snon	return EIO;
380379697Snon
380479697Snoncmd_link_start:
380579697Snon	ncb->ccb_flags &= ~CCB_STARTQ;
380679697Snon	TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
380779697Snon
380879697Snon	scsi_low_dealloc_qtag(ncb);
380979697Snon	ncb->ccb_tag = cb->ccb_tag;
381079697Snon	ncb->ccb_otag = cb->ccb_otag;
381179697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
381279697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
381379697Snon	if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
3814106890Simp		panic("%s: linked ccb retried", slp->sl_xname);
381579697Snon
381679697Snon	slp->sl_Qnexus = ncb;
381779697Snon	slp->sl_ph_count = 0;
381879697Snon
381979697Snon	ncb->ccb_error = 0;
382079697Snon	ncb->ccb_datalen = -1;
382179697Snon	ncb->ccb_scp.scp_status = ST_UNKNOWN;
382279697Snon	ncb->ccb_flags &= ~CCB_INTERNAL;
382379697Snon
382479697Snon	scsi_low_init_msgsys(slp, ti);
382579697Snon
382679697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb);
382779697Snon
382879697Snon	if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
382979697Snon		ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
383079697Snon	ncb->ccb_tc = ncb->ccb_tcmax;
383179697Snon
383279697Snon	/* setup saved scsi data pointer */
383379697Snon	ncb->ccb_sscp = ncb->ccb_scp;
383479697Snon	slp->sl_scp = ncb->ccb_sscp;
383579697Snon	slp->sl_error = ncb->ccb_error;
383679697Snon
383779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
383879697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
383979697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
384079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
384179697Snon	return EJUSTRETURN;
384279697Snon}
384379697Snon
384479697Snonstatic int
384579697Snonscsi_low_msginfunc_disc(slp)
384679697Snon	struct scsi_low_softc *slp;
384767468Snon{
384867468Snon
384967468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
385067468Snon	return 0;
385167468Snon}
385267468Snon
385367468Snonstatic int
385479697Snonscsi_low_msginfunc_sdp(slp)
385579697Snon	struct scsi_low_softc *slp;
385667468Snon{
385779697Snon	struct slccb *cb = slp->sl_Qnexus;
385867468Snon
385979697Snon	if (cb != NULL)
386079697Snon	{
386179697Snon		cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
386279697Snon		cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
386379697Snon	}
386467468Snon	else
386579697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
386667468Snon	return 0;
386767468Snon}
386867468Snon
386967468Snonstatic int
387079697Snonscsi_low_msginfunc_rp(slp)
387179697Snon	struct scsi_low_softc *slp;
387267468Snon{
387367468Snon
387479697Snon	if (slp->sl_Qnexus != NULL)
387579697Snon		slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
387667468Snon	else
387779697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
387867468Snon	return 0;
387967468Snon}
388067468Snon
388167468Snonstatic int
388279697Snonscsi_low_synch(slp)
388379697Snon	struct scsi_low_softc *slp;
388467468Snon{
388579697Snon	struct targ_info *ti = slp->sl_Tnexus;
388679697Snon	u_int period = 0, offset = 0, speed;
388767468Snon	u_char *s;
388867468Snon	int error;
388967468Snon
389079697Snon	if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
389179697Snon	     MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
389279697Snon	     MSGIN_OFFSET(ti) == 0)
389367468Snon	{
389467468Snon		if ((offset = MSGIN_OFFSET(ti)) != 0)
389567468Snon			period = MSGIN_PERIOD(ti);
389667468Snon		s = offset ? "synchronous" : "async";
389767468Snon	}
389867468Snon	else
389967468Snon	{
390067468Snon		/* XXX:
390167468Snon		 * Target seems to be brain damaged.
390267468Snon		 * Force async transfer.
390367468Snon		 */
390473025Snon		ti->ti_maxsynch.period = 0;
390573025Snon		ti->ti_maxsynch.offset = 0;
390667468Snon		printf("%s: target brain damaged. async transfer\n",
390767468Snon			slp->sl_xname);
390867468Snon		return EINVAL;
390967468Snon	}
391067468Snon
391173025Snon	ti->ti_maxsynch.period = period;
391273025Snon	ti->ti_maxsynch.offset = offset;
391367468Snon
391467468Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH);
391567468Snon	if (error != 0)
391667468Snon	{
391767468Snon		/* XXX:
391867468Snon		 * Current period and offset are not acceptable
391967468Snon		 * for our adapter.
392067468Snon		 * The adapter changes max synch and max offset.
392167468Snon		 */
392267468Snon		printf("%s: synch neg failed. retry synch msg neg ...\n",
392367468Snon			slp->sl_xname);
392467468Snon		return error;
392567468Snon	}
392667468Snon
392779697Snon	ti->ti_osynch = ti->ti_maxsynch;
392879697Snon	if (offset > 0)
392979697Snon	{
393079697Snon		ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
393179697Snon	}
393279697Snon
393367468Snon	/* inform data */
393479697Snon	if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
393567468Snon	{
393679697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
393779697Snon		struct slccb *cb = slp->sl_Qnexus;
393879697Snon
393979697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
394079697Snon			return 0;
394179697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
394279697Snon
394379697Snon		printf("%s(%d:*): <%s> offset %d period %dns ",
394479697Snon			slp->sl_xname, ti->ti_id, s, offset, period * 4);
394579697Snon
394679697Snon		if (period != 0)
394779697Snon		{
394879697Snon			speed = 1000 * 10 / (period * 4);
394979697Snon			printf("%d.%d M/s", speed / 10, speed % 10);
395079697Snon		}
395179697Snon		printf("\n");
395267468Snon	}
395379697Snon	return 0;
395479697Snon}
395567468Snon
395679697Snonstatic int
395779697Snonscsi_low_wide(slp)
395879697Snon	struct scsi_low_softc *slp;
395979697Snon{
396079697Snon	struct targ_info *ti = slp->sl_Tnexus;
396179697Snon	int error;
396279697Snon
396379697Snon	ti->ti_width = MSGIN_WIDTHP(ti);
396479697Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
396579697Snon	if (error != 0)
396679697Snon	{
396779697Snon		/* XXX:
396879697Snon		 * Current width is not acceptable for our adapter.
396979697Snon		 * The adapter changes max width.
397079697Snon		 */
397179697Snon		printf("%s: wide neg failed. retry wide msg neg ...\n",
397279697Snon			slp->sl_xname);
397379697Snon		return error;
397479697Snon	}
397579697Snon
397679697Snon	ti->ti_owidth = ti->ti_width;
397779697Snon	if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
397879697Snon	{
397979697Snon		ti->ti_setup_msg_done |=
398079697Snon			(SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
398179697Snon	}
398279697Snon
398379697Snon	/* inform data */
398479697Snon	if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
398579697Snon	{
398679697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
398779697Snon		struct slccb *cb = slp->sl_Qnexus;
398879697Snon
398979697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
399079697Snon			return 0;
399179697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
399279697Snon
399379697Snon		printf("%s(%d:*): transfer width %d bits\n",
399479697Snon			slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width));
399579697Snon	}
399667468Snon	return 0;
399767468Snon}
399867468Snon
399967468Snonstatic int
400079697Snonscsi_low_msginfunc_simple_qtag(slp)
400179697Snon	struct scsi_low_softc *slp;
400267468Snon{
400379697Snon	struct targ_info *ti = slp->sl_Tnexus;
400479697Snon	scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
400579697Snon
400679697Snon	if (slp->sl_Qnexus != NULL)
400779697Snon	{
400879697Snon		if (slp->sl_Qnexus->ccb_tag != etag)
400979697Snon		{
401079697Snon			slp->sl_error |= FATALIO;
401179697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
401279697Snon			SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
401379697Snon		}
401479697Snon	}
401579697Snon	else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
401679697Snon	{
401779697Snon#ifdef	SCSI_LOW_DEBUG
401879697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
401979697Snon			return 0;
402079697Snon#endif	/* SCSI_LOW_DEBUG */
402179697Snon
402279697Snon		slp->sl_error |= FATALIO;
402379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
402479697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
402579697Snon	}
402679697Snon	return 0;
402779697Snon}
402879697Snon
402979697Snonstatic int
403079697Snonscsi_low_msginfunc_i_wide_residue(slp)
403179697Snon	struct scsi_low_softc *slp;
403279697Snon{
403379697Snon	struct targ_info *ti = slp->sl_Tnexus;
403479697Snon	struct slccb *cb = slp->sl_Qnexus;
403579697Snon	int res = (int) ti->ti_msgin[1];
403679697Snon
403779697Snon	if (cb == NULL || res <= 0 ||
403879697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
403979697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
404079697Snon		return EINVAL;
404179697Snon
404279697Snon	if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
404379697Snon		return EINVAL;
404479697Snon
404579697Snon	slp->sl_scp.scp_datalen += res;
404679697Snon	slp->sl_scp.scp_data -= res;
404779697Snon	scsi_low_data_finish(slp);
404879697Snon	return 0;
404979697Snon}
405079697Snon
405179697Snonstatic int
405279697Snonscsi_low_msginfunc_ext(slp)
405379697Snon	struct scsi_low_softc *slp;
405479697Snon{
405579697Snon	struct slccb *cb = slp->sl_Qnexus;
405679697Snon	struct lun_info *li = slp->sl_Lnexus;
405779697Snon	struct targ_info *ti = slp->sl_Tnexus;
405867468Snon	int count, retry;
405967468Snon	u_int32_t *ptr;
406067468Snon
406167468Snon	if (ti->ti_msginptr == 2)
406267468Snon	{
406367468Snon		ti->ti_msginlen = ti->ti_msgin[1] + 2;
406467468Snon		return 0;
406567468Snon	}
406667468Snon
406767468Snon	switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
406867468Snon	{
406967468Snon	case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
407067468Snon		if (cb == NULL)
407167468Snon			break;
407267468Snon
407367468Snon		ptr = (u_int32_t *)(&ti->ti_msgin[3]);
407467468Snon		count = (int) htonl((long) (*ptr));
407567468Snon		if(slp->sl_scp.scp_datalen - count < 0 ||
407667468Snon		   slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen)
407767468Snon			break;
407867468Snon
407967468Snon		slp->sl_scp.scp_datalen -= count;
408067468Snon		slp->sl_scp.scp_data += count;
408167468Snon		return 0;
408267468Snon
408367468Snon	case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
408467468Snon		if (li == NULL)
408567468Snon			break;
408667468Snon
408779697Snon		retry = scsi_low_synch(slp);
408867468Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
408967468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
409079697Snon
409179697Snon#ifdef	SCSI_LOW_DEBUG
409279697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
409379697Snon		{
409479697Snon			scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
409579697Snon		}
409679697Snon#endif	/* SCSI_LOW_DEBUG */
409767468Snon		return 0;
409867468Snon
409967468Snon	case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
410067468Snon		if (li == NULL)
410167468Snon			break;
410267468Snon
410379697Snon		retry = scsi_low_wide(slp);
410479697Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
410579697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
410679697Snon
410767468Snon		return 0;
410867468Snon
410967468Snon	default:
411067468Snon		break;
411167468Snon	}
411267468Snon
411367468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
411467468Snon	return EINVAL;
411567468Snon}
411667468Snon
411767468Snonstatic int
411879697Snonscsi_low_msginfunc_parity(slp)
411979697Snon	struct scsi_low_softc *slp;
412067468Snon{
412179697Snon	struct targ_info *ti = slp->sl_Tnexus;
412267468Snon
412379697Snon	/* only I -> T, invalid! */
412479697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
412567468Snon	return 0;
412667468Snon}
412767468Snon
412867468Snonstatic int
412979697Snonscsi_low_msginfunc_msg_reject(slp)
413079697Snon	struct scsi_low_softc *slp;
413167468Snon{
413279697Snon	struct targ_info *ti = slp->sl_Tnexus;
413367468Snon	struct scsi_low_msgout_data *mdp;
413467468Snon	u_int msgflags;
413567468Snon
413679697Snon	if (ti->ti_emsgflags != 0)
413767468Snon	{
413879697Snon		printf("%s: msg flags [0x%x] rejected\n",
413979697Snon		       slp->sl_xname, ti->ti_emsgflags);
414067468Snon		msgflags = SCSI_LOW_MSG_REJECT;
414167468Snon		mdp = &scsi_low_msgout_data[0];
414267468Snon		for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
414367468Snon		{
414467468Snon			if ((ti->ti_emsgflags & mdp->md_flags) != 0)
414567468Snon			{
414667468Snon				ti->ti_emsgflags &= ~mdp->md_flags;
414767468Snon				if (mdp->md_errfunc != NULL)
414879697Snon					(*mdp->md_errfunc) (slp, msgflags);
414967468Snon				break;
415067468Snon			}
415167468Snon		}
415279697Snon		return 0;
415367468Snon	}
415479697Snon	else
415579697Snon	{
415679697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
415779697Snon		slp->sl_error |= MSGERR;
415879697Snon	}
415979697Snon	return EINVAL;
416067468Snon}
416167468Snon
416279697Snonint
416367468Snonscsi_low_msgin(slp, ti, c)
416467468Snon	struct scsi_low_softc *slp;
416567468Snon	struct targ_info *ti;
416679697Snon	u_int c;
416767468Snon{
416867468Snon	struct scsi_low_msgin_data *sdp;
416967468Snon	struct lun_info *li;
417067468Snon	u_int8_t msg;
417167468Snon
417279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
417379697Snon	if (ti != slp->sl_Tnexus)
417479697Snon	{
417579697Snon		scsi_low_print(slp, NULL);
417679697Snon		panic("scsi_low_msgin: Target nexus inconsistent");
417779697Snon	}
417879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
417979697Snon
418067468Snon	/*
418167468Snon	 * Phase changes, clear the pointer.
418267468Snon	 */
418367468Snon	if (ti->ti_ophase != ti->ti_phase)
418467468Snon	{
418567468Snon		MSGINPTR_CLR(ti);
418679697Snon		ti->ti_msgin_parity_error = 0;
418779697Snon
418879697Snon		slp->sl_ph_count ++;
418979697Snon		if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
419079697Snon		{
419179697Snon			printf("%s: too many phase changes\n", slp->sl_xname);
419279697Snon			slp->sl_error |= FATALIO;
419379697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
419479697Snon		}
419567468Snon	}
419667468Snon
419767468Snon	/*
419867468Snon	 * Store a current messages byte into buffer and
419967468Snon	 * wait for the completion of the current msg.
420067468Snon	 */
420179697Snon	ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
420267468Snon	if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
420367468Snon	{
420467468Snon		ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
420567468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
420667468Snon	}
420767468Snon
420867468Snon	/*
420979697Snon	 * Check parity errors.
421079697Snon	 */
421179697Snon	if ((c & SCSI_LOW_DATA_PE) != 0)
421279697Snon	{
421379697Snon		ti->ti_msgin_parity_error ++;
421479697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
421579697Snon		goto out;
421679697Snon	}
421779697Snon
421879697Snon	if (ti->ti_msgin_parity_error != 0)
421979697Snon		goto out;
422079697Snon
422179697Snon	/*
422267468Snon	 * Calculate messages length.
422367468Snon	 */
422467468Snon	msg = ti->ti_msgin[0];
422567468Snon	if (msg < MSGIN_DATA_LAST)
422667468Snon		sdp = &scsi_low_msgin_data[msg];
422767468Snon	else
422867468Snon		sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST];
422967468Snon
423067468Snon	if (ti->ti_msginlen == 0)
423167468Snon	{
423267468Snon		ti->ti_msginlen = sdp->md_len;
423367468Snon	}
423467468Snon
423567468Snon	/*
423667468Snon	 * Check comletion.
423767468Snon	 */
423867468Snon	if (ti->ti_msginptr < ti->ti_msginlen)
423979697Snon		return EJUSTRETURN;
424067468Snon
424167468Snon	/*
424267468Snon	 * Do process.
424367468Snon	 */
424467468Snon	if ((msg & MSG_IDENTIFY) == 0)
424567468Snon	{
424679697Snon		if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
424779697Snon			return EJUSTRETURN;
424867468Snon	}
424967468Snon	else
425067468Snon	{
425179697Snon		li = slp->sl_Lnexus;
425267468Snon		if (li == NULL)
425367468Snon		{
425479697Snon			li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
425567468Snon			if (li == NULL)
425667468Snon				goto badlun;
425779697Snon			slp->sl_Lnexus = li;
425879697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
425967468Snon		}
426079697Snon		else
426179697Snon		{
426279697Snon			if (MSGCMD_LUN(msg) != li->li_lun)
426379697Snon				goto badlun;
426479697Snon		}
426567468Snon
426679697Snon		if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
426767468Snon		{
426867468Snon			if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
426979697Snon			{
427079697Snon#ifdef	SCSI_LOW_DEBUG
427179697Snon				if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
427279697Snon				{
427379697Snon					goto out;
427479697Snon				}
427579697Snon#endif	/* SCSI_LOW_DEBUG */
427667468Snon				goto badlun;
427779697Snon			}
427867468Snon		}
427967468Snon	}
428079697Snon	goto out;
428167468Snon
428267468Snon	/*
428379697Snon	 * Msg process completed, reset msgin pointer and assert ATN if desired.
428467468Snon	 */
428579697Snonbadlun:
428679697Snon	slp->sl_error |= FATALIO;
428779697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
428879697Snon	SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
428979697Snon
429079697Snonout:
429179697Snon	if (ti->ti_msginptr < ti->ti_msginlen)
429279697Snon		return EJUSTRETURN;
429379697Snon
429479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
429579697Snon	scsi_low_msg_log_write(&ti->ti_log_msgin,
429679697Snon			       &ti->ti_msgin[0], ti->ti_msginlen);
429779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
429879697Snon
429979697Snon	MSGINPTR_CLR(ti);
430079697Snon	return 0;
430179697Snon}
430279697Snon
430379697Snon/**********************************************************
430479697Snon * disconnect
430579697Snon **********************************************************/
430679697Snonint
430779697Snonscsi_low_disconnected(slp, ti)
430879697Snon	struct scsi_low_softc *slp;
430979697Snon	struct targ_info *ti;
431079697Snon{
431179697Snon	struct slccb *cb = slp->sl_Qnexus;
431279697Snon
431379697Snon	/* check phase completion */
431479697Snon	switch (slp->sl_msgphase)
431567468Snon	{
431679697Snon	case MSGPH_RESET:
431779697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
431879697Snon		scsi_low_msginfunc_cc(slp);
431979697Snon		scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
432079697Snon		goto io_resume;
432167468Snon
432279697Snon	case MSGPH_ABORT:
432379697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
432479697Snon		scsi_low_msginfunc_cc(slp);
432579697Snon		scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
432679697Snon		goto io_resume;
432779697Snon
432879697Snon	case MSGPH_TERM:
432979697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
433079697Snon		scsi_low_msginfunc_cc(slp);
433179697Snon		goto io_resume;
433279697Snon
433379697Snon	case MSGPH_DISC:
433479697Snon		if (cb != NULL)
433567468Snon		{
433679697Snon			struct lun_info *li;
433779697Snon
433879697Snon			li = cb->li;
433979697Snon			TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
434079697Snon			cb->ccb_flags |= CCB_DISCQ;
434179697Snon			cb->ccb_error |= slp->sl_error;
434279697Snon			li->li_disc ++;
434379697Snon			ti->ti_disc ++;
434479697Snon			slp->sl_disc ++;
434579697Snon		}
434679697Snon
434779697Snon#ifdef	SCSI_LOW_STATICS
434879697Snon		scsi_low_statics.nexus_disconnected ++;
434979697Snon#endif	/* SCSI_LOW_STATICS */
435079697Snon
435179697Snon#ifdef	SCSI_LOW_DEBUG
435279697Snon		if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
435379697Snon		{
435479697Snon			printf("## SCSI_LOW_DISCONNECTED ===============\n");
435579697Snon			scsi_low_print(slp, NULL);
435679697Snon		}
435779697Snon#endif	/* SCSI_LOW_DEBUG */
435879697Snon		break;
435979697Snon
436079697Snon	case MSGPH_NULL:
436179697Snon		slp->sl_error |= FATALIO;
436279697Snon		if (ti->ti_phase == PH_SELSTART)
436379697Snon			slp->sl_error |= SELTIMEOUTIO;
436479697Snon		else
436579697Snon			slp->sl_error |= UBFERR;
436679697Snon		/* fall through */
436779697Snon
436879697Snon	case MSGPH_LCTERM:
436979697Snon	case MSGPH_CMDC:
437079697Snonio_resume:
437179697Snon		if (cb == NULL)
437279697Snon			break;
437379697Snon
437479697Snon#ifdef	SCSI_LOW_DEBUG
437579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
437679697Snon		{
437779697Snon			if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
437879697Snon			    (cb->ccb_msgoutflag != 0 ||
437979697Snon			     (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
438079697Snon			{
438179697Snon				scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
438279697Snon			}
438379697Snon		}
438479697Snon#endif	/* SCSI_LOW_DEBUG */
438579697Snon
438679697Snon		cb->ccb_error |= slp->sl_error;
438779697Snon		if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
438879697Snon		{
438979697Snon			cb->ccb_flags |= CCB_STARTQ;
439079697Snon			TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
439179697Snon		}
439279697Snon		break;
439379697Snon	}
439479697Snon
439579697Snon	scsi_low_bus_release(slp, ti);
439679697Snon	scsi_low_start(slp);
439779697Snon	return 1;
439879697Snon}
439979697Snon
440079697Snon/**********************************************************
440179697Snon * TAG operations
440279697Snon **********************************************************/
4403104094Sphkstatic int
440479697Snonscsi_low_alloc_qtag(cb)
440579697Snon	struct slccb *cb;
440679697Snon{
440779697Snon	struct lun_info *li = cb->li;
440879697Snon	scsi_low_tag_t etag;
440979697Snon
441079697Snon	if (cb->ccb_otag != SCSI_LOW_UNKTAG)
441179697Snon		return 0;
441279697Snon
441379697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
441479697Snon	etag = ffs(li->li_qtagbits);
441579697Snon	if (etag == 0)
441679697Snon		return ENOSPC;
441779697Snon
441879697Snon	li->li_qtagbits &= ~(1 << (etag - 1));
441979697Snon	cb->ccb_otag = etag;
442079697Snon	return 0;
442179697Snon
442279697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
442379697Snon	for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
442479697Snon		if (li->li_qtagarray[li->li_qd] == 0)
442579697Snon			goto found;
442679697Snon
442779697Snon	for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
442879697Snon		if (li->li_qtagarray[li->li_qd] == 0)
442979697Snon			goto found;
443079697Snon
443179697Snon	return ENOSPC;
443279697Snon
443379697Snonfound:
443479697Snon	li->li_qtagarray[li->li_qd] ++;
443579697Snon	cb->ccb_otag = (li->li_qd ++);
443679697Snon	return 0;
443779697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
443879697Snon}
443979697Snon
4440104094Sphkstatic int
444179697Snonscsi_low_dealloc_qtag(cb)
444279697Snon	struct slccb *cb;
444379697Snon{
444479697Snon	struct lun_info *li = cb->li;
444579697Snon	scsi_low_tag_t etag;
444679697Snon
444779697Snon	if (cb->ccb_otag == SCSI_LOW_UNKTAG)
444879697Snon		return 0;
444979697Snon
445079697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
445179697Snon	etag = cb->ccb_otag - 1;
445267468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
445379697Snon	if (etag >= sizeof(li->li_qtagbits) * NBBY)
445479697Snon		panic("scsi_low_dealloc_tag: illegal tag");
445567468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
445679697Snon	li->li_qtagbits |= (1 << etag);
445779697Snon
445879697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
445979697Snon	etag = cb->ccb_otag;
446079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
446179697Snon	if (etag >= SCSI_LOW_MAXNEXUS)
446279697Snon		panic("scsi_low_dealloc_tag: illegal tag");
446379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
446479697Snon	li->li_qtagarray[etag] --;
446579697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
446679697Snon
446779697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
446879697Snon	return 0;
446979697Snon}
447079697Snon
4471104094Sphkstatic struct slccb *
447279697Snonscsi_low_revoke_ccb(slp, cb, fdone)
447379697Snon	struct scsi_low_softc *slp;
447479697Snon	struct slccb *cb;
447579697Snon	int fdone;
447679697Snon{
447779697Snon	struct targ_info *ti = cb->ti;
447879697Snon	struct lun_info *li = cb->li;
447979697Snon
448079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
448179697Snon	if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
448279697Snon	    (CCB_STARTQ | CCB_DISCQ))
448379697Snon	{
4484106890Simp		panic("%s: ccb in both queue", slp->sl_xname);
448567468Snon	}
448679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
448767468Snon
448879697Snon	if ((cb->ccb_flags & CCB_STARTQ) != 0)
448979697Snon	{
449079697Snon		TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
449179697Snon	}
449279697Snon
449379697Snon	if ((cb->ccb_flags & CCB_DISCQ) != 0)
449479697Snon	{
449579697Snon		TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
449679697Snon		li->li_disc --;
449779697Snon		ti->ti_disc --;
449879697Snon		slp->sl_disc --;
449979697Snon	}
450079697Snon
450179697Snon	cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
450279697Snon			   CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
450379697Snon
450479697Snon	if (fdone != 0 &&
450579697Snon	    (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
450679697Snon	     (cb->ccb_flags & CCB_NORETRY) != 0))
450779697Snon	{
450879697Snon		cb->ccb_error |= FATALIO;
450979697Snon		cb->ccb_flags &= ~CCB_AUTOSENSE;
451079697Snon		if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
4511106890Simp			panic("%s: done ccb retried", slp->sl_xname);
451279697Snon		return NULL;
451379697Snon	}
451479697Snon	else
451579697Snon	{
451679697Snon		cb->ccb_error |= PENDINGIO;
451779697Snon		scsi_low_deactivate_qtag(cb);
451879697Snon		scsi_low_ccb_message_retry(cb);
451979697Snon		cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
452079697Snon		return cb;
452179697Snon	}
452267468Snon}
452367468Snon
4524104094Sphkstatic void
452579697Snonscsi_low_reset_nexus_lun(slp, li, fdone)
452679697Snon	struct scsi_low_softc *slp;
452779697Snon	struct lun_info *li;
452879697Snon	int fdone;
452979697Snon{
453079697Snon	struct slccb *cb, *ncb, *ecb;
453179697Snon
453279697Snon	if (li == NULL)
453379697Snon		return;
453479697Snon
453579697Snon	ecb = NULL;
453679697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
453779697Snon	{
453879697Snon		ncb = TAILQ_NEXT(cb, ccb_chain);
453979697Snon		cb = scsi_low_revoke_ccb(slp, cb, fdone);
454079697Snon		if (cb != NULL)
454179697Snon		{
454279697Snon			/*
454379697Snon			 * presumely keep ordering of io
454479697Snon			 */
454579697Snon			cb->ccb_flags |= CCB_STARTQ;
454679697Snon			if (ecb == NULL)
454779697Snon			{
454879697Snon				TAILQ_INSERT_HEAD(&slp->sl_start,\
454979697Snon						  cb, ccb_chain);
455079697Snon			}
455179697Snon			else
455279697Snon			{
455379697Snon				TAILQ_INSERT_AFTER(&slp->sl_start,\
455479697Snon						   ecb, cb, ccb_chain);
455579697Snon			}
455679697Snon			ecb = cb;
455779697Snon		}
455879697Snon	}
455979697Snon}
456079697Snon
456167468Snon/**************************************************************
456267468Snon * Qurik setup
456367468Snon **************************************************************/
456467468Snonstatic void
456579697Snonscsi_low_calcf_lun(li)
456667468Snon	struct lun_info *li;
456767468Snon{
456879697Snon	struct targ_info *ti = li->li_ti;
456967468Snon	struct scsi_low_softc *slp = ti->ti_sc;
457079697Snon	u_int cfgflags, diskflags;
457167468Snon
457279697Snon	if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
457379697Snon		cfgflags = li->li_cfgflags;
457479697Snon	else
457579697Snon		cfgflags = 0;
457679697Snon
457779697Snon	diskflags = li->li_diskflags & li->li_quirks;
457879697Snon
457979697Snon	/* disconnect */
458067468Snon	li->li_flags &= ~SCSI_LOW_DISC;
458167468Snon	if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
458279697Snon	    (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
458379697Snon	    (cfgflags & SCSI_LOW_DISC) != 0)
458467468Snon		li->li_flags |= SCSI_LOW_DISC;
458567468Snon
458679697Snon	/* parity */
458767468Snon	li->li_flags |= SCSI_LOW_NOPARITY;
458867468Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
458979697Snon	    (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
459079697Snon	    (cfgflags & SCSI_LOW_NOPARITY) == 0)
459167468Snon		li->li_flags &= ~SCSI_LOW_NOPARITY;
459267468Snon
459379697Snon	/* qtag */
459479697Snon	if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
459579697Snon	    (cfgflags & SCSI_LOW_QTAG) != 0 &&
459679697Snon	    (diskflags & SCSI_LOW_DISK_QTAG) != 0)
459779697Snon	{
459879697Snon		li->li_flags |= SCSI_LOW_QTAG;
459979697Snon		li->li_maxnexus = SCSI_LOW_MAXNEXUS;
460079697Snon		li->li_maxnqio = li->li_maxnexus;
460179697Snon	}
460279697Snon	else
460379697Snon	{
460479697Snon		li->li_flags &= ~SCSI_LOW_QTAG;
460579697Snon		li->li_maxnexus = 0;
460679697Snon		li->li_maxnqio = li->li_maxnexus;
460779697Snon	}
460879697Snon
460979697Snon	/* cmd link */
461079697Snon	li->li_flags &= ~SCSI_LOW_LINK;
461179697Snon	if ((cfgflags & SCSI_LOW_LINK) != 0 &&
461279697Snon	    (diskflags & SCSI_LOW_DISK_LINK) != 0)
461379697Snon		li->li_flags |= SCSI_LOW_LINK;
461479697Snon
461579697Snon	/* compatible flags */
461667468Snon	li->li_flags &= ~SCSI_LOW_SYNC;
461779697Snon	if (ti->ti_maxsynch.offset > 0)
461879697Snon		li->li_flags |= SCSI_LOW_SYNC;
461979697Snon
462079697Snon#ifdef	SCSI_LOW_DEBUG
462179697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
462267468Snon	{
462379697Snon		scsi_low_calcf_show(li);
462467468Snon	}
462579697Snon#endif	/* SCSI_LOW_DEBUG */
462679697Snon}
462779697Snon
462879697Snonstatic void
462979697Snonscsi_low_calcf_target(ti)
463079697Snon	struct targ_info *ti;
463179697Snon{
463279697Snon	struct scsi_low_softc *slp = ti->ti_sc;
463379697Snon	u_int offset, period, diskflags;
463479697Snon
463579697Snon	diskflags = ti->ti_diskflags & ti->ti_quirks;
463679697Snon
463779697Snon	/* synch */
463879697Snon	if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
463979697Snon	    (diskflags & SCSI_LOW_DISK_SYNC) != 0)
464079697Snon	{
464179697Snon		offset = ti->ti_maxsynch.offset;
464279697Snon		period = ti->ti_maxsynch.period;
464379697Snon		if (offset == 0 || period == 0)
464479697Snon			offset = period = 0;
464579697Snon	}
464667468Snon	else
464779697Snon	{
464879697Snon		offset = period = 0;
464979697Snon	}
465067468Snon
465179697Snon	ti->ti_maxsynch.offset = offset;
465279697Snon	ti->ti_maxsynch.period = period;
465379697Snon
465479697Snon	/* wide */
465579697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
465679697Snon	     ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
465779697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
465879697Snon
465979697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
466079697Snon	    ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
466179697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
466279697Snon
466379697Snon	if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
466467468Snon	{
466579697Snon		if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
466679697Snon		    ti->ti_maxsynch.period != ti->ti_osynch.period)
466779697Snon			ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
466879697Snon		if (ti->ti_width != ti->ti_owidth)
466979697Snon			ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
467079697Snon
467179697Snon		ti->ti_osynch = ti->ti_maxsynch;
467279697Snon		ti->ti_owidth = ti->ti_width;
467367468Snon	}
467467468Snon
467579697Snon#ifdef	SCSI_LOW_DEBUG
467679697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
467779697Snon	{
467879697Snon		printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n",
467979697Snon			slp->sl_xname, ti->ti_id,
468079697Snon			ti->ti_maxsynch.period * 4,
468179697Snon			ti->ti_maxsynch.offset,
468279697Snon			ti->ti_width);
468379697Snon	}
468479697Snon#endif	/* SCSI_LOW_DEBUG */
468567468Snon}
468667468Snon
468779697Snonstatic void
468879697Snonscsi_low_calcf_show(li)
468979697Snon	struct lun_info *li;
469079697Snon{
469179697Snon	struct targ_info *ti = li->li_ti;
469279697Snon	struct scsi_low_softc *slp = ti->ti_sc;
469379697Snon
469479697Snon	printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
469579697Snon		slp->sl_xname, ti->ti_id, li->li_lun,
469679697Snon		ti->ti_maxsynch.period * 4,
469779697Snon		ti->ti_maxsynch.offset,
469879697Snon		ti->ti_width,
469979697Snon		li->li_flags, SCSI_LOW_BITS);
470079697Snon}
470179697Snon
470279697Snon#ifdef	SCSI_LOW_START_UP_CHECK
470379697Snon/**************************************************************
470479697Snon * scsi world start up
470579697Snon **************************************************************/
470692770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *);
470779697Snon
470867468Snonstatic int
470979697Snonscsi_low_start_up(slp)
471079697Snon	struct scsi_low_softc *slp;
471167468Snon{
471267468Snon	struct targ_info *ti;
471367468Snon	struct lun_info *li;
471479697Snon	struct slccb *cb;
471579697Snon	int target, lun;
471667468Snon
471779697Snon	printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname);
471867468Snon
471979697Snon	for (target = 0; target < slp->sl_ntargs; target ++)
472079697Snon	{
472179697Snon		if (target == slp->sl_hostid)
472279697Snon		{
472379697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
472479697Snon			{
472579697Snon				printf("%s: scsi_low: target %d (host card)\n",
472679697Snon					slp->sl_xname, target);
472779697Snon			}
472879697Snon			continue;
472979697Snon		}
473067468Snon
473179697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
473279697Snon		{
473379697Snon			printf("%s: scsi_low: target %d lun ",
473479697Snon				slp->sl_xname, target);
473579697Snon		}
473667468Snon
473779697Snon		ti = slp->sl_ti[target];
473879697Snon		for (lun = 0; lun < slp->sl_nluns; lun ++)
473979697Snon		{
474079697Snon			if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
474179697Snon				break;
474279697Snon
474379697Snon			cb->osdep = NULL;
474479697Snon			cb->bp = NULL;
474579697Snon
474679697Snon			li = scsi_low_alloc_li(ti, lun, 1);
474779697Snon
474879697Snon			scsi_low_enqueue(slp, ti, li, cb,
474979697Snon					 CCB_AUTOSENSE | CCB_POLLED, 0);
475079697Snon
475179697Snon			scsi_low_poll(slp, cb);
475279697Snon
475379697Snon			if (li->li_state != SCSI_LOW_LUN_OK)
475479697Snon				break;
475579697Snon
475679697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
475779697Snon			{
475879697Snon				printf("%d ", lun);
475979697Snon			}
476079697Snon		}
476179697Snon
476279697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
476379697Snon		{
476479697Snon			printf("\n");
476579697Snon		}
476679697Snon	}
476767468Snon	return 0;
476867468Snon}
476967468Snon
477079697Snonstatic int
477179697Snonscsi_low_poll(slp, cb)
477279697Snon	struct scsi_low_softc *slp;
477379697Snon	struct slccb *cb;
477479697Snon{
477579697Snon	int tcount;
477679697Snon
477779697Snon	tcount = 0;
477879697Snon	while (slp->sl_nio > 0)
477979697Snon	{
478079697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
478179697Snon
478279697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
478379697Snon		if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
478479697Snon			continue;
478579697Snon
478679697Snon		tcount = 0;
478779697Snon		scsi_low_timeout_check(slp);
478879697Snon	}
478979697Snon
479079697Snon	return 0;
479179697Snon}
479279697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
479379697Snon
479467468Snon/**********************************************************
479567468Snon * DEBUG SECTION
479667468Snon **********************************************************/
479779697Snon#ifdef	SCSI_LOW_DEBUG
479867468Snonstatic void
479979697Snonscsi_low_test_abort(slp, ti, li)
480079697Snon	struct scsi_low_softc *slp;
480179697Snon	struct targ_info *ti;
480279697Snon	struct lun_info *li;
480379697Snon{
480479697Snon	struct slccb *acb;
480579697Snon
480679697Snon	if (li->li_disc > 1)
480779697Snon	{
480879697Snon		acb = TAILQ_FIRST(&li->li_discq);
480979697Snon		if (scsi_low_abort_ccb(slp, acb) == 0)
481079697Snon		{
481179697Snon			printf("%s: aborting ccb(0x%lx) start\n",
481279697Snon				slp->sl_xname, (u_long) acb);
481379697Snon		}
481479697Snon	}
481579697Snon}
481679697Snon
481779697Snonstatic void
481879697Snonscsi_low_test_atten(slp, ti, msg)
481979697Snon	struct scsi_low_softc *slp;
482079697Snon	struct targ_info *ti;
482179697Snon	u_int msg;
482279697Snon{
482379697Snon
482479697Snon	if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
482579697Snon		scsi_low_assert_msg(slp, ti, msg, 0);
482679697Snon	else
482779697Snon		printf("%s: atten check OK\n", slp->sl_xname);
482879697Snon}
482979697Snon
483079697Snonstatic void
483179697Snonscsi_low_test_cmdlnk(slp, cb)
483279697Snon	struct scsi_low_softc *slp;
483379697Snon	struct slccb *cb;
483479697Snon{
483579697Snon#define	SCSI_LOW_CMDLNK_NOK	(CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
483679697Snon
483779697Snon	if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
483879697Snon		return;
483979697Snon
484079697Snon	memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
484179697Snon	       slp->sl_scp.scp_cmdlen);
484279697Snon	cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
484379697Snon	slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
484479697Snon}
484579697Snon#endif	/* SCSI_LOW_DEBUG */
484679697Snon
484779697Snon/* static */ void
484867468Snonscsi_low_info(slp, ti, s)
484967468Snon	struct scsi_low_softc *slp;
485067468Snon	struct targ_info *ti;
485167468Snon	u_char *s;
485267468Snon{
485367468Snon
485479697Snon	if (slp == NULL)
485579697Snon		slp = LIST_FIRST(&sl_tab);
485679697Snon	if (s == NULL)
485779697Snon		s = "no message";
485879697Snon
485979697Snon	printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
486067468Snon	if (ti == NULL)
486167468Snon	{
486279697Snon		for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
486379697Snon		     ti = TAILQ_NEXT(ti, ti_chain))
486479697Snon		{
486567468Snon			scsi_low_print(slp, ti);
486679697Snon		}
486767468Snon	}
486867468Snon	else
486979697Snon	{
487067468Snon		scsi_low_print(slp, ti);
487179697Snon	}
487267468Snon}
487367468Snon
487467468Snonstatic u_char *phase[] =
487567468Snon{
487667468Snon	"FREE", "ARBSTART", "SELSTART", "SELECTED",
487767468Snon	"CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL"
487867468Snon};
487967468Snon
488067468Snonvoid
488167468Snonscsi_low_print(slp, ti)
488267468Snon	struct scsi_low_softc *slp;
488367468Snon	struct targ_info *ti;
488467468Snon{
488579697Snon	struct lun_info *li;
488679697Snon	struct slccb *cb;
488779697Snon	struct sc_p *sp;
488867468Snon
488979697Snon	if (ti == NULL || ti == slp->sl_Tnexus)
489079697Snon	{
489179697Snon		ti = slp->sl_Tnexus;
489279697Snon		li = slp->sl_Lnexus;
489379697Snon		cb = slp->sl_Qnexus;
489479697Snon	}
489579697Snon	else
489679697Snon	{
489779697Snon		li = LIST_FIRST(&ti->ti_litab);
489879697Snon		cb = TAILQ_FIRST(&li->li_discq);
489979697Snon	}
490079697Snon 	sp = &slp->sl_scp;
490167468Snon
490279697Snon	printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
490379697Snon		slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb,
490479697Snon		slp->sl_nio);
490567468Snon
490667468Snon	/* target stat */
490767468Snon	if (ti != NULL)
490867468Snon	{
490979697Snon		u_int flags = 0, maxnqio = 0, nqio = 0;
491067468Snon		int lun = -1;
491167468Snon
491267468Snon		if (li != NULL)
491367468Snon		{
491467468Snon			lun = li->li_lun;
491567468Snon			flags = li->li_flags;
491679697Snon			maxnqio = li->li_maxnqio;
491779697Snon			nqio = li->li_nqio;
491867468Snon		}
491967468Snon
492079697Snon		printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
492179697Snon			slp->sl_xname,
492267468Snon		       ti->ti_id, lun, phase[(int) ti->ti_ophase],
492379697Snon		       phase[(int) ti->ti_phase], ti->ti_disc,
492479697Snon		       nqio, maxnqio);
492567468Snon
492679697Snon		if (cb != NULL)
492779697Snon		{
492879697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
492979697Snon		       (u_int) cb->ccb_scp.scp_cmd[0],
493079697Snon		       cb->ccb_scp.scp_cmdlen,
493179697Snon		       cb->ccb_datalen,
493279697Snon		       cb->ccb_scp.scp_datalen,
493379697Snon		       (u_int) cb->ccb_sscp.scp_status,
493479697Snon		       cb->ccb_error, SCSI_LOW_ERRORBITS);
493579697Snon		}
493667468Snon
493779697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
493879697Snon	       (u_int) (ti->ti_msginptr),
493979697Snon	       (u_int) (ti->ti_msgin[0]),
494079697Snon	       (u_int) (ti->ti_msgin[1]),
494179697Snon	       (u_int) (ti->ti_msgin[2]),
494279697Snon	       (u_int) (ti->ti_msgin[3]),
494379697Snon	       (u_int) (ti->ti_msgin[4]),
494479697Snon	       slp->sl_atten);
494579697Snon
494667468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
494779697Snon		(u_int) ti->ti_msgflags,
494879697Snon		(u_int) (ti->ti_msgoutstr[0]),
494979697Snon		(u_int) (ti->ti_msgoutstr[1]),
495079697Snon		(u_int) (ti->ti_msgoutstr[2]),
495179697Snon		(u_int) (ti->ti_msgoutstr[3]),
495279697Snon		(u_int) (ti->ti_msgoutstr[4]),
495379697Snon		ti->ti_msgoutlen,
495479697Snon		flags, SCSI_LOW_BITS);
495567468Snon
495679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
495779697Snon		scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
495879697Snon		scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
495979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
496067468Snon
496167468Snon	}
496279697Snon
496379697Snon	printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
496479697Snon	       (u_long) sp->scp_data,
496579697Snon	       sp->scp_datalen,
496679697Snon	       (u_int) sp->scp_status,
496779697Snon	       slp->sl_error, SCSI_LOW_ERRORBITS);
496867468Snon}
4969