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: releng/10.2/sys/cam/scsi/scsi_low.c 265632 2014-05-08 06:55:48Z mav $");
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
1779697Snon#define	SCSI_LOW_FLAGS_QUIRKS_OK
1879697Snon
19139743Simp/*-
2067468Snon * [NetBSD for NEC PC-98 series]
2179697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2267468Snon *	NetBSD/pc98 porting staff. All rights reserved.
2379697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2467468Snon *	Naofumi HONDA. All rights reserved.
2579697Snon *
2679697Snon * [Ported for FreeBSD CAM]
2779697Snon *  Copyright (c) 2000, 2001
2879697Snon *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
2979697Snon *      All rights reserved.
3067468Snon *
3167468Snon *  Redistribution and use in source and binary forms, with or without
3267468Snon *  modification, are permitted provided that the following conditions
3367468Snon *  are met:
3467468Snon *  1. Redistributions of source code must retain the above copyright
3567468Snon *     notice, this list of conditions and the following disclaimer.
3667468Snon *  2. Redistributions in binary form must reproduce the above copyright
3767468Snon *     notice, this list of conditions and the following disclaimer in the
3867468Snon *     documentation and/or other materials provided with the distribution.
3967468Snon *  3. The name of the author may not be used to endorse or promote products
4067468Snon *     derived from this software without specific prior written permission.
4167468Snon *
4267468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4367468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4467468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4567468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
4667468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4767468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4867468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4967468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
5067468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
5167468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5267468Snon * POSSIBILITY OF SUCH DAMAGE.
5367468Snon */
5467468Snon
5567468Snon/* <On the nexus establishment>
5667468Snon * When our host is reselected,
5767468Snon * nexus establish processes are little complicated.
5867468Snon * Normal steps are followings:
5979697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
6079697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
6179697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
6267468Snon */
6367468Snon#include "opt_ddb.h"
6467468Snon
6567468Snon#include <sys/param.h>
6667468Snon#include <sys/systm.h>
6767468Snon#include <sys/kernel.h>
6867468Snon#include <sys/bio.h>
6967468Snon#include <sys/buf.h>
7067468Snon#include <sys/queue.h>
7167468Snon#include <sys/malloc.h>
7267468Snon#include <sys/errno.h>
7367468Snon
7467468Snon#include <cam/cam.h>
7567468Snon#include <cam/cam_ccb.h>
7667468Snon#include <cam/cam_sim.h>
7767468Snon#include <cam/cam_debug.h>
7867468Snon#include <cam/cam_periph.h>
79147723Savatar#include <cam/cam_xpt_periph.h>
8067468Snon
8167468Snon#include <cam/scsi/scsi_all.h>
8273025Snon#include <cam/scsi/scsi_message.h>
8367468Snon
8467468Snon#include <cam/scsi/scsi_low.h>
8567468Snon
8667468Snon#include <sys/cons.h>
8767468Snon
8879697Snon/**************************************************************
8979697Snon * Constants
9079697Snon **************************************************************/
9179697Snon#define	SCSI_LOW_POLL_HZ	1000
9267468Snon
9379697Snon/* functions return values */
9479697Snon#define	SCSI_LOW_START_NO_QTAG	0
9579697Snon#define	SCSI_LOW_START_QTAG	1
9679697Snon
9767468Snon#define	SCSI_LOW_DONE_COMPLETE	0
9867468Snon#define	SCSI_LOW_DONE_RETRY	1
9967468Snon
10079697Snon/* internal disk flags */
10179697Snon#define	SCSI_LOW_DISK_DISC	0x00000001
10279697Snon#define	SCSI_LOW_DISK_QTAG	0x00000002
10379697Snon#define	SCSI_LOW_DISK_LINK	0x00000004
10479697Snon#define	SCSI_LOW_DISK_PARITY	0x00000008
10579697Snon#define	SCSI_LOW_DISK_SYNC	0x00010000
10679697Snon#define	SCSI_LOW_DISK_WIDE_16	0x00020000
10779697Snon#define	SCSI_LOW_DISK_WIDE_32	0x00040000
10879697Snon#define	SCSI_LOW_DISK_WIDE	(SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
10979697Snon#define	SCSI_LOW_DISK_LFLAGS	0x0000ffff
11079697Snon#define	SCSI_LOW_DISK_TFLAGS	0xffff0000
11179697Snon
112227293Sedstatic MALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers");
113147723Savatar
11479697Snon/**************************************************************
11579697Snon * Declarations
11679697Snon **************************************************************/
11792770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *);
11892770Salfredstatic void scsi_low_engage(void *);
11992770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t);
12092770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *);
12192770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *);
12292770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *);
12392770Salfredstatic void scsi_low_twiddle_wait(void);
12492770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int);
12592770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int);
12692770Salfredstatic void scsi_low_calcf_lun(struct lun_info *);
12792770Salfredstatic void scsi_low_calcf_target(struct targ_info *);
12892770Salfredstatic void scsi_low_calcf_show(struct lun_info *);
12992770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int);
13092770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int);
13192770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int);
13292770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int);
13392770Salfredstatic void scsi_low_start(struct scsi_low_softc *);
13492770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *);
13567468Snon
13692770Salfredstatic int scsi_low_alloc_qtag(struct slccb *);
13792770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *);
13892770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int);
13992770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int);
14092770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *);
14192770Salfredstatic void scsi_low_timeout(void *);
14292770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *);
14379697Snon#ifdef	SCSI_LOW_START_UP_CHECK
14492770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *);
14579697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
14692770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *);
14792770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int);
14879697Snon
14979697Snonint scsi_low_version_major = 2;
15079697Snonint scsi_low_version_minor = 17;
15179697Snon
15279697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
15379697Snon
15479697Snon/**************************************************************
15579697Snon * Debug, Run test and Statics
15679697Snon **************************************************************/
15779697Snon#ifdef	SCSI_LOW_INFO_DETAIL
15879697Snon#define	SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
15979697Snon#else	/* !SCSI_LOW_INFO_DETAIL */
160240325Sjhb#define	SCSI_LOW_INFO(slp, ti, s) device_printf((slp)->sl_dev, "%s\n", (s))
16179697Snon#endif	/* !SCSI_LOW_INFO_DETAIL */
16279697Snon
16367468Snon#ifdef	SCSI_LOW_STATICS
16489113Smsmithstatic struct scsi_low_statics {
16567468Snon	int nexus_win;
16667468Snon	int nexus_fail;
16767468Snon	int nexus_disconnected;
16867468Snon	int nexus_reselected;
16967468Snon	int nexus_conflict;
17067468Snon} scsi_low_statics;
17167468Snon#endif	/* SCSI_LOW_STATICS */
17279697Snon
17379697Snon#ifdef	SCSI_LOW_DEBUG
17479697Snon#define	SCSI_LOW_DEBUG_DONE	0x00001
17579697Snon#define	SCSI_LOW_DEBUG_DISC	0x00002
17679697Snon#define	SCSI_LOW_DEBUG_SENSE	0x00004
17779697Snon#define	SCSI_LOW_DEBUG_CALCF	0x00008
17879697Snon#define	SCSI_LOW_DEBUG_ACTION	0x10000
17979697Snonint scsi_low_debug = 0;
18079697Snon
18179697Snon#define	SCSI_LOW_MAX_ATTEN_CHECK	32
18279697Snon#define	SCSI_LOW_ATTEN_CHECK	0x0001
18379697Snon#define	SCSI_LOW_CMDLNK_CHECK	0x0002
18479697Snon#define	SCSI_LOW_ABORT_CHECK	0x0004
18579697Snon#define	SCSI_LOW_NEXUS_CHECK	0x0008
18679697Snonint scsi_low_test = 0;
18779697Snonint scsi_low_test_id = 0;
18879697Snon
18992770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *);
19092770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *);
19192770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int);
19279697Snon#define	SCSI_LOW_DEBUG_TEST_GO(fl, id) \
19379697Snon	((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
19479697Snon#define	SCSI_LOW_DEBUG_GO(fl, id) \
19579697Snon	((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
19679697Snon#endif	/* SCSI_LOW_DEBUG */
19779697Snon
19867468Snon/**************************************************************
19979697Snon * CCB
20079697Snon **************************************************************/
20179697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
20279697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain)
20379697Snon
20479697Snon/**************************************************************
20579697Snon * Inline functions
20679697Snon **************************************************************/
20779697Snon#define	SCSI_LOW_INLINE	static __inline
20892770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *);
20992770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *);
21092770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int);
21192770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *);
21292770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *);
21392770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *);
21492770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *);
21579697Snon
21679697SnonSCSI_LOW_INLINE void
21779697Snonscsi_low_activate_qtag(cb)
21879697Snon	struct slccb *cb;
21979697Snon{
22079697Snon	struct lun_info *li = cb->li;
22179697Snon
22279697Snon	if (cb->ccb_tag != SCSI_LOW_UNKTAG)
22379697Snon		return;
22479697Snon
22579697Snon	li->li_nqio ++;
22679697Snon	cb->ccb_tag = cb->ccb_otag;
22779697Snon}
22879697Snon
22979697SnonSCSI_LOW_INLINE void
23079697Snonscsi_low_deactivate_qtag(cb)
23179697Snon	struct slccb *cb;
23279697Snon{
23379697Snon	struct lun_info *li = cb->li;
23479697Snon
23579697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
23679697Snon		return;
23779697Snon
23879697Snon	li->li_nqio --;
23979697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
24079697Snon}
24179697Snon
24279697SnonSCSI_LOW_INLINE void
24379697Snonscsi_low_ccb_message_exec(slp, cb)
24479697Snon	struct scsi_low_softc *slp;
24579697Snon	struct slccb *cb;
24679697Snon{
24779697Snon
24879697Snon	scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
24979697Snon	cb->ccb_msgoutflag = 0;
25079697Snon}
25179697Snon
25279697SnonSCSI_LOW_INLINE void
25379697Snonscsi_low_ccb_message_assert(cb, msg)
25479697Snon	struct slccb *cb;
25579697Snon	u_int msg;
25679697Snon{
25779697Snon
25879697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
25979697Snon}
26079697Snon
26179697SnonSCSI_LOW_INLINE void
26279697Snonscsi_low_ccb_message_retry(cb)
26379697Snon	struct slccb *cb;
26479697Snon{
26579697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
26679697Snon}
26779697Snon
26879697SnonSCSI_LOW_INLINE void
26979697Snonscsi_low_ccb_message_clear(cb)
27079697Snon	struct slccb *cb;
27179697Snon{
27279697Snon	cb->ccb_msgoutflag = 0;
27379697Snon}
27479697Snon
27579697SnonSCSI_LOW_INLINE void
27679697Snonscsi_low_init_msgsys(slp, ti)
27779697Snon	struct scsi_low_softc *slp;
27879697Snon	struct targ_info *ti;
27979697Snon{
28079697Snon
28179697Snon	ti->ti_msginptr = 0;
28279697Snon	ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
28379697Snon	SCSI_LOW_DEASSERT_ATN(slp);
28479697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
28579697Snon}
28679697Snon
28779697Snon/*=============================================================
28879697Snon * START OF OS switch  (All OS depend fucntions should be here)
28979697Snon =============================================================*/
29079697Snon/* common os depend utitlities */
29179697Snon#define	SCSI_LOW_CMD_RESIDUAL_CHK	0x0001
29279697Snon#define	SCSI_LOW_CMD_ORDERED_QTAG	0x0002
29379697Snon#define	SCSI_LOW_CMD_ABORT_WARNING	0x0004
29479697Snon
29579697Snonstatic u_int8_t scsi_low_cmd_flags[256] = {
29679697Snon/*	0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
29779697Snon/*0*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
29879697Snon/*1*/	0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
29979697Snon/*2*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
30079697Snon/*3*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
30179697Snon};
30279697Snon
30379697Snonstruct scsi_low_error_code {
30479697Snon	int error_bits;
30579697Snon	int error_code;
30679697Snon};
30779697Snon
30892770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *);
30992770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *);
31079697Snon
31179697Snonstatic struct slccb *
31279697Snonscsi_low_find_ccb(slp, target, lun, osdep)
31379697Snon	struct scsi_low_softc *slp;
31479697Snon	u_int target, lun;
31579697Snon	void *osdep;
31679697Snon{
31779697Snon	struct targ_info *ti;
31879697Snon	struct lun_info *li;
31979697Snon	struct slccb *cb;
32079697Snon
32179697Snon	ti = slp->sl_ti[target];
32279697Snon	li = scsi_low_alloc_li(ti, lun, 0);
32379697Snon	if (li == NULL)
32479697Snon		return NULL;
32579697Snon
32679697Snon	if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
32779697Snon		return cb;
32879697Snon
32979697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
33079697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
33179697Snon	{
33279697Snon		if (cb->osdep == osdep)
33379697Snon			return cb;
33479697Snon	}
33579697Snon
33679697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL;
33779697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
33879697Snon	{
33979697Snon		if (cb->osdep == osdep)
34079697Snon			return cb;
34179697Snon	}
34279697Snon	return NULL;
34379697Snon}
34479697Snon
34579697Snonstatic int
34679697Snonscsi_low_translate_error_code(cb, tp)
34779697Snon	struct slccb *cb;
34879697Snon	struct scsi_low_error_code *tp;
34979697Snon{
35079697Snon
35179697Snon	if (cb->ccb_error == 0)
35279697Snon		return tp->error_code;
35379697Snon
35479697Snon	for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
35579697Snon		;
35679697Snon	return tp->error_code;
35779697Snon}
35879697Snon
35979697Snon/**************************************************************
36079697Snon * SCSI INTERFACE (CAM)
36179697Snon **************************************************************/
362147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
363147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
36479697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb()
36579697Snon
36692770Salfredstatic void scsi_low_poll_cam(struct cam_sim *);
36792770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
36879697Snon
36992770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *);
37092770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *);
37192770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *);
37292770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *);
37392770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *);
37492770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int);
37579697Snon
37679697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = {
37779697Snon	scsi_low_attach_cam,
37879697Snon	scsi_low_world_start_cam,
37979697Snon	scsi_low_dettach_cam,
38079697Snon	scsi_low_ccb_setup_cam,
38179697Snon	scsi_low_done_cam,
38279697Snon	scsi_low_timeout_cam
38379697Snon};
38479697Snon
38579697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = {
38679697Snon	{0,			CAM_REQ_CMP},
38779697Snon	{SENSEIO, 		CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
38879697Snon	{SENSEERR,		CAM_AUTOSENSE_FAIL},
38979697Snon	{UACAERR,		CAM_SCSI_STATUS_ERROR},
39079697Snon	{BUSYERR | STATERR,	CAM_SCSI_STATUS_ERROR},
39179697Snon	{SELTIMEOUTIO,		CAM_SEL_TIMEOUT},
39279697Snon	{TIMEOUTIO,		CAM_CMD_TIMEOUT},
39379697Snon	{PDMAERR,		CAM_DATA_RUN_ERR},
39479697Snon	{PARITYERR,		CAM_UNCOR_PARITY},
39579697Snon	{UBFERR,		CAM_UNEXP_BUSFREE},
39679697Snon	{ABORTIO,		CAM_REQ_ABORTED},
39779697Snon	{-1,			CAM_UNREC_HBA_ERROR}
39879697Snon};
39979697Snon
40079697Snon#define	SIM2SLP(sim)	((struct scsi_low_softc *) cam_sim_softc((sim)))
40179697Snon
40279697Snon/* XXX:
40379697Snon * Please check a polling hz, currently we assume scsi_low_poll() is
40479697Snon * called each 1 ms.
40579697Snon */
40679697Snon#define	SCSI_LOW_CAM_POLL_HZ	1000	/* OK ? */
40779697Snon
40879697Snonstatic void
40979697Snonscsi_low_poll_cam(sim)
41079697Snon	struct cam_sim *sim;
41179697Snon{
41279697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
41379697Snon
41479697Snon	(*slp->sl_funcs->scsi_low_poll) (slp);
41579697Snon
41679697Snon	if (slp->sl_si.si_poll_count ++ >=
41779697Snon	    SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
41879697Snon	{
41979697Snon		slp->sl_si.si_poll_count = 0;
42079697Snon		scsi_low_timeout_check(slp);
42179697Snon	}
42279697Snon}
42379697Snon
42479697Snonvoid
42579697Snonscsi_low_scsi_action_cam(sim, ccb)
42679697Snon	struct cam_sim *sim;
42779697Snon	union ccb *ccb;
42879697Snon{
42979697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
43079697Snon	struct targ_info *ti;
43179697Snon	struct lun_info *li;
43279697Snon	struct slccb *cb;
43379697Snon	u_int lun, flags, msg, target;
43479697Snon	int s, rv;
43579697Snon
43679697Snon	target = (u_int) (ccb->ccb_h.target_id);
43779697Snon	lun = (u_int) ccb->ccb_h.target_lun;
43879697Snon
43979697Snon#ifdef	SCSI_LOW_DEBUG
44079697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
44179697Snon	{
442240325Sjhb		device_printf(slp->sl_dev,
443240325Sjhb		    "cam_action: func code 0x%x target: %d, lun: %d\n",
444240325Sjhb		    ccb->ccb_h.func_code, target, lun);
44579697Snon	}
44679697Snon#endif	/* SCSI_LOW_DEBUG */
44779697Snon
44879697Snon	switch (ccb->ccb_h.func_code) {
44979697Snon	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
45079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
45179697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
45279697Snon		{
453240325Sjhb			device_printf(slp->sl_dev, "invalid target/lun\n");
45479697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
45579697Snon			xpt_done(ccb);
45679697Snon			return;
45779697Snon		}
45879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
45979697Snon
46079697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
46179697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
46279697Snon			xpt_done(ccb);
46379697Snon			return;
46479697Snon		}
46579697Snon
46679697Snon		ti = slp->sl_ti[target];
46779697Snon		cb->osdep = ccb;
46879697Snon		cb->bp = NULL;
46979697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
47079697Snon			flags = CCB_AUTOSENSE | CCB_SCSIIO;
47179697Snon		else
47279697Snon			flags = CCB_SCSIIO;
47379697Snon
474240172Sjhb		s = splcam();
47579697Snon		li = scsi_low_alloc_li(ti, lun, 1);
47679697Snon
47779697Snon		if (ti->ti_setup_msg != 0)
47879697Snon		{
47979697Snon			scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
48079697Snon		}
48179697Snon
48279697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
48379697Snon
48479697Snon#ifdef	SCSI_LOW_DEBUG
48579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
48679697Snon		{
48779697Snon			scsi_low_test_abort(slp, ti, li);
48879697Snon		}
48979697Snon#endif	/* SCSI_LOW_DEBUG */
49079697Snon		splx(s);
49179697Snon		break;
49279697Snon
49379697Snon	case XPT_EN_LUN:		/* Enable LUN as a target */
49479697Snon	case XPT_TARGET_IO:		/* Execute target I/O request */
49579697Snon	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
49679697Snon	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
49779697Snon		/* XXX Implement */
49879697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
49979697Snon		xpt_done(ccb);
50079697Snon		break;
50179697Snon
50279697Snon	case XPT_ABORT:			/* Abort the specified CCB */
50379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
50479697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
50579697Snon		{
506240325Sjhb			device_printf(slp->sl_dev, "invalid target/lun\n");
50779697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
50879697Snon			xpt_done(ccb);
50979697Snon			return;
51079697Snon		}
51179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
51279697Snon
513240172Sjhb		s = splcam();
51479697Snon		cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
51579697Snon		rv = scsi_low_abort_ccb(slp, cb);
51679697Snon		splx(s);
51779697Snon
51879697Snon		if (rv == 0)
51979697Snon			ccb->ccb_h.status = CAM_REQ_CMP;
52079697Snon		else
52179697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
52279697Snon		xpt_done(ccb);
52379697Snon		break;
52479697Snon
52579697Snon	case XPT_SET_TRAN_SETTINGS: {
526163816Smjacob		struct ccb_trans_settings_scsi *scsi;
527163816Smjacob        	struct ccb_trans_settings_spi *spi;
52879697Snon		struct ccb_trans_settings *cts;
52979697Snon		u_int val;
53079697Snon
53179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
53279697Snon		if (target == CAM_TARGET_WILDCARD)
53379697Snon		{
534240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
53579697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
53679697Snon			xpt_done(ccb);
53779697Snon			return;
53879697Snon		}
53979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
54079697Snon		cts = &ccb->cts;
54179697Snon		ti = slp->sl_ti[target];
54279697Snon		if (lun == CAM_LUN_WILDCARD)
54379697Snon			lun = 0;
54479697Snon
545240172Sjhb		s = splcam();
546163816Smjacob		scsi = &cts->proto_specific.scsi;
547163816Smjacob		spi = &cts->xport_specific.spi;
548163816Smjacob		if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH |
549163816Smjacob				   CTS_SPI_VALID_SYNC_RATE |
550163816Smjacob				   CTS_SPI_VALID_SYNC_OFFSET)) != 0)
551163816Smjacob		{
552163816Smjacob			if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
553163816Smjacob				val = spi->bus_width;
554163816Smjacob				if (val < ti->ti_width)
555163816Smjacob					ti->ti_width = val;
556163816Smjacob			}
557163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_RATE) {
558163816Smjacob				val = spi->sync_period;
559163816Smjacob				if (val == 0 || val > ti->ti_maxsynch.period)
560163816Smjacob					ti->ti_maxsynch.period = val;
561163816Smjacob			}
562163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
563163816Smjacob				val = spi->sync_offset;
564163816Smjacob				if (val < ti->ti_maxsynch.offset)
565163816Smjacob					ti->ti_maxsynch.offset = val;
566163816Smjacob			}
567163816Smjacob			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
568163816Smjacob			scsi_low_calcf_target(ti);
569163816Smjacob		}
570163816Smjacob
571163816Smjacob		if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 ||
572163816Smjacob                    (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
573163816Smjacob
574163816Smjacob			li = scsi_low_alloc_li(ti, lun, 1);
575163816Smjacob			if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) {
576163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_DISC;
577163816Smjacob			} else {
578163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_DISC;
579163816Smjacob			}
580163816Smjacob
581163816Smjacob			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
582163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_QTAG;
583163816Smjacob			} else {
584163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
585163816Smjacob			}
586163816Smjacob			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
587163816Smjacob			scsi_low_calcf_target(ti);
588163816Smjacob			scsi_low_calcf_lun(li);
589163816Smjacob			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
590163816Smjacob				scsi_low_calcf_show(li);
591163816Smjacob		}
59279697Snon		splx(s);
59379697Snon
59479697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
59579697Snon		xpt_done(ccb);
59679697Snon		break;
59779697Snon	}
59879697Snon
59979697Snon	case XPT_GET_TRAN_SETTINGS: {
60079697Snon		struct ccb_trans_settings *cts;
60179697Snon		u_int diskflags;
60279697Snon
60379697Snon		cts = &ccb->cts;
60479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
60579697Snon		if (target == CAM_TARGET_WILDCARD)
60679697Snon		{
607240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
60879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
60979697Snon			xpt_done(ccb);
61079697Snon			return;
61179697Snon		}
61279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
61379697Snon		ti = slp->sl_ti[target];
61479697Snon		if (lun == CAM_LUN_WILDCARD)
61579697Snon			lun = 0;
61679697Snon
617240172Sjhb		s = splcam();
61879697Snon		li = scsi_low_alloc_li(ti, lun, 1);
61979697Snon		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
62079697Snon			struct ccb_trans_settings_scsi *scsi =
62179697Snon				&cts->proto_specific.scsi;
62279697Snon			struct ccb_trans_settings_spi *spi =
62379697Snon				&cts->xport_specific.spi;
62479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
62579697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
62679697Snon			{
62779697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
628240325Sjhb				device_printf(slp->sl_dev,
629240325Sjhb				    "invalid GET_TRANS_CURRENT_SETTINGS call\n");
63079697Snon				goto settings_out;
63179697Snon			}
63279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
63379697Snon			cts->protocol = PROTO_SCSI;
63479697Snon			cts->protocol_version = SCSI_REV_2;
63579697Snon			cts->transport = XPORT_SPI;
63679697Snon			cts->transport_version = 2;
63779697Snon
63879697Snon			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
63979697Snon			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
64079697Snon
64179697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
64279697Snon			if (diskflags & SCSI_LOW_DISK_DISC)
64379697Snon				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
64479697Snon			if (diskflags & SCSI_LOW_DISK_QTAG)
64579697Snon				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
64679697Snon
64779697Snon			spi->sync_period = ti->ti_maxsynch.period;
64879697Snon			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
64979697Snon			spi->sync_offset = ti->ti_maxsynch.offset;
65079697Snon			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
65179697Snon
65279697Snon			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
65379697Snon			spi->bus_width = ti->ti_width;
65479697Snon
65579697Snon			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
65679697Snon				scsi->valid = CTS_SCSI_VALID_TQ;
65779697Snon				spi->valid |= CTS_SPI_VALID_DISC;
65879697Snon			} else
65979697Snon				scsi->valid = 0;
66079697Snon		} else
66179697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
66279697Snonsettings_out:
66379697Snon		splx(s);
66479697Snon		xpt_done(ccb);
66579697Snon		break;
66679697Snon	}
66779697Snon
66879697Snon	case XPT_CALC_GEOMETRY: { /* not yet HN2 */
669116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
67079697Snon		xpt_done(ccb);
67179697Snon		break;
67279697Snon	}
67379697Snon
67479697Snon	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
675240172Sjhb		s = splcam();
67679697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
67779697Snon		splx(s);
67879697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
67979697Snon		xpt_done(ccb);
68079697Snon		break;
68179697Snon
68279697Snon	case XPT_TERM_IO:	/* Terminate the I/O process */
68379697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
68479697Snon		xpt_done(ccb);
68579697Snon		break;
68679697Snon
68779697Snon	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
68879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
68979697Snon		if (target == CAM_TARGET_WILDCARD)
69079697Snon		{
691240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
69279697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
69379697Snon			xpt_done(ccb);
69479697Snon			return;
69579697Snon		}
69679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
69779697Snon
69879697Snon		msg = SCSI_LOW_MSG_RESET;
69979697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
70079697Snon		{
70179697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
70279697Snon			xpt_done(ccb);
70379697Snon			return;
70479697Snon		}
70579697Snon
70679697Snon		ti = slp->sl_ti[target];
70779697Snon		if (lun == CAM_LUN_WILDCARD)
70879697Snon			lun = 0;
70979697Snon		cb->osdep = ccb;
71079697Snon		cb->bp = NULL;
71179697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
71279697Snon			flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
71379697Snon		else
71479697Snon			flags = CCB_NORETRY | CCB_URGENT;
71579697Snon
716240172Sjhb		s = splcam();
71779697Snon		li = scsi_low_alloc_li(ti, lun, 1);
71879697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, msg);
71979697Snon		splx(s);
72079697Snon		break;
72179697Snon
72279697Snon	case XPT_PATH_INQ: {		/* Path routing inquiry */
72379697Snon		struct ccb_pathinq *cpi = &ccb->cpi;
72479697Snon
72579697Snon		cpi->version_num = scsi_low_version_major;
72679697Snon		cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
72779697Snon		ti = slp->sl_ti[slp->sl_hostid];	/* host id */
72879697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
72979697Snon			cpi->hba_inquiry |= PI_WIDE_16;
73079697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
73179697Snon			cpi->hba_inquiry |= PI_WIDE_32;
73279697Snon		if (ti->ti_maxsynch.offset > 0)
73379697Snon			cpi->hba_inquiry |= PI_SDTR_ABLE;
73479697Snon		cpi->target_sprt = 0;
73579697Snon		cpi->hba_misc = 0;
73679697Snon		cpi->hba_eng_cnt = 0;
73779697Snon		cpi->max_target = slp->sl_ntargs - 1;
73879697Snon		cpi->max_lun = slp->sl_nluns - 1;
73979697Snon		cpi->initiator_id = slp->sl_hostid;
74079697Snon		cpi->bus_id = cam_sim_bus(sim);
74179697Snon		cpi->base_transfer_speed = 3300;
74279697Snon		cpi->transport = XPORT_SPI;
74379697Snon		cpi->transport_version = 2;
74479697Snon		cpi->protocol = PROTO_SCSI;
74579697Snon		cpi->protocol_version = SCSI_REV_2;
74679697Snon		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
74779697Snon		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
74879697Snon		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
74979697Snon		cpi->unit_number = cam_sim_unit(sim);
75079697Snon		cpi->ccb_h.status = CAM_REQ_CMP;
75179697Snon		xpt_done(ccb);
75279697Snon		break;
75379697Snon	}
75479697Snon
75579697Snon	default:
75679697Snon	        printf("scsi_low: non support func_code = %d ",
75779697Snon			ccb->ccb_h.func_code);
75879697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
75979697Snon		xpt_done(ccb);
76079697Snon		break;
76179697Snon	}
76279697Snon}
76379697Snon
76479697Snonstatic int
76579697Snonscsi_low_attach_cam(slp)
76679697Snon	struct scsi_low_softc *slp;
76779697Snon{
76879697Snon	struct cam_devq *devq;
76979697Snon	int tagged_openings;
77079697Snon
77179697Snon	devq = cam_simq_alloc(SCSI_LOW_NCCB);
77279697Snon	if (devq == NULL)
77379697Snon		return (ENOMEM);
77479697Snon
77579697Snon	/*
77679697Snon	 * ask the adapter what subunits are present
77779697Snon	 */
77879697Snon	tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
77979697Snon	slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
78079697Snon				scsi_low_poll_cam,
781240172Sjhb				device_get_name(slp->sl_dev), slp,
782240172Sjhb				device_get_unit(slp->sl_dev), &Giant,
78379697Snon				slp->sl_openings, tagged_openings, devq);
78479697Snon
78579697Snon	if (slp->sl_si.sim == NULL) {
78679697Snon		cam_simq_free(devq);
78779697Snon	 	return ENODEV;
78879697Snon	}
78979697Snon
790170872Sscottl	if (xpt_bus_register(slp->sl_si.sim, NULL, 0) != CAM_SUCCESS) {
791147723Savatar		free(slp->sl_si.sim, M_SCSILOW);
79279697Snon	 	return ENODEV;
79379697Snon	}
79479697Snon
79579697Snon	if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL,
79679697Snon			cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD,
79779697Snon			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
79879697Snon		xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
79979697Snon		cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE);
80079697Snon		return ENODEV;
80179697Snon	}
80279697Snon
80379697Snon	slp->sl_show_result = SHOW_CALCF_RES;		/* OK ? */
80479697Snon	return 0;
80579697Snon}
80679697Snon
80779697Snonstatic int
80879697Snonscsi_low_world_start_cam(slp)
80979697Snon	struct scsi_low_softc *slp;
81079697Snon{
81179697Snon
81279697Snon	return 0;
81379697Snon}
81479697Snon
81579697Snonstatic int
81679697Snonscsi_low_dettach_cam(slp)
81779697Snon	struct scsi_low_softc *slp;
81879697Snon{
81979697Snon
82079697Snon	xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL);
82179697Snon	xpt_free_path(slp->sl_si.path);
82279697Snon	xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
82379697Snon	cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE);
82479697Snon	return 0;
82579697Snon}
82679697Snon
82779697Snonstatic int
82879697Snonscsi_low_ccb_setup_cam(slp, cb)
82979697Snon	struct scsi_low_softc *slp;
83079697Snon	struct slccb *cb;
83179697Snon{
83279697Snon        union ccb *ccb = (union ccb *) cb->osdep;
83379697Snon
83479697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
83579697Snon	{
83679697Snon		cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
83779697Snon		cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
83879697Snon		cb->ccb_scp.scp_data = ccb->csio.data_ptr;
83979697Snon		cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
84079697Snon		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
84179697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
84279697Snon		else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
84379697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_READ;
84479697Snon		cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
84579697Snon	}
84679697Snon	else
84779697Snon	{
84879697Snon		scsi_low_unit_ready_cmd(cb);
84979697Snon	}
85079697Snon	return SCSI_LOW_START_QTAG;
85179697Snon}
85279697Snon
85379697Snonstatic int
85479697Snonscsi_low_done_cam(slp, cb)
85579697Snon	struct scsi_low_softc *slp;
85679697Snon	struct slccb *cb;
85779697Snon{
85879697Snon	union ccb *ccb;
85979697Snon
86079697Snon	ccb = (union ccb *) cb->osdep;
86179697Snon	if (cb->ccb_error == 0)
86279697Snon	{
86379697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
86479697Snon		ccb->csio.resid = 0;
86579697Snon	}
86679697Snon	else
86779697Snon	{
86879697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
86979697Snon			cb->ccb_error |= ABORTIO;
87079697Snon
87179697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
87279697Snon		    (cb->ccb_error & ABORTIO) == 0)
87379697Snon			return EJUSTRETURN;
87479697Snon
87579697Snon		if ((cb->ccb_error & SENSEIO) != 0)
87679697Snon		{
87779697Snon			memcpy(&ccb->csio.sense_data,
87879697Snon			       &cb->ccb_sense,
87979697Snon			       sizeof(ccb->csio.sense_data));
88079697Snon		}
88179697Snon
88279697Snon		ccb->ccb_h.status = scsi_low_translate_error_code(cb,
88379697Snon					&scsi_low_error_code_cam[0]);
88479697Snon
88579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
88679697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
88779697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
88879697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
88979697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
89079697Snon		{
891240325Sjhb			device_printf(slp->sl_dev,
892240325Sjhb			    "WARNING: scsi_low IO abort\n");
89379697Snon			scsi_low_print(slp, NULL);
89479697Snon		}
89579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
89679697Snon	}
89779697Snon
89879697Snon	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
89979697Snon		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
90079697Snon
90179697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
90279697Snon		ccb->csio.scsi_status = 0;	/* XXX */
90379697Snon	else
90479697Snon		ccb->csio.scsi_status = cb->ccb_scp.scp_status;
90579697Snon
90679697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
90779697Snon		xpt_done(ccb);
90879697Snon	return 0;
90979697Snon}
91079697Snon
91179697Snonstatic void
91279697Snonscsi_low_timeout_cam(slp, ch, action)
91379697Snon	struct scsi_low_softc *slp;
91479697Snon	int ch;
91579697Snon	int action;
91679697Snon{
91779697Snon
91879697Snon	switch (ch)
91979697Snon	{
92079697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
92179697Snon		switch (action)
92279697Snon		{
92379697Snon		case SCSI_LOW_TIMEOUT_START:
92479697Snon			slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp,
92579697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
92679697Snon			break;
92779697Snon		case SCSI_LOW_TIMEOUT_STOP:
92879697Snon			untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch);
92979697Snon			break;
93079697Snon		}
93179697Snon		break;
93279697Snon
93379697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
93479697Snon		switch (action)
93579697Snon		{
93679697Snon		case SCSI_LOW_TIMEOUT_START:
93779697Snon			slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1);
93879697Snon			break;
93979697Snon		case SCSI_LOW_TIMEOUT_STOP:
94079697Snon			untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch);
94179697Snon			break;
94279697Snon		}
94379697Snon		break;
94479697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
94579697Snon		break;
94679697Snon	}
94779697Snon}
94879697Snon
94979697Snon/*=============================================================
95079697Snon * END OF OS switch  (All OS depend fucntions should be above)
95179697Snon =============================================================*/
95279697Snon
95379697Snon/**************************************************************
95479697Snon * scsi low deactivate and activate
95579697Snon **************************************************************/
95679697Snonint
95779697Snonscsi_low_is_busy(slp)
95879697Snon	struct scsi_low_softc *slp;
95979697Snon{
96079697Snon
96179697Snon	if (slp->sl_nio > 0)
96279697Snon		return EBUSY;
96379697Snon	return 0;
96479697Snon}
96579697Snon
96679697Snonint
96779697Snonscsi_low_deactivate(slp)
96879697Snon	struct scsi_low_softc *slp;
96979697Snon{
97079697Snon	int s;
97179697Snon
972240172Sjhb	s = splcam();
97379697Snon	slp->sl_flags |= HW_INACTIVE;
97479697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
97579697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP);
97679697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
97779697Snon		(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
97879697Snon	splx(s);
97979697Snon	return 0;
98079697Snon}
98179697Snon
98279697Snonint
98379697Snonscsi_low_activate(slp)
98479697Snon	struct scsi_low_softc *slp;
98579697Snon{
98679697Snon	int error, s;
98779697Snon
988240172Sjhb	s = splcam();
98979697Snon	slp->sl_flags &= ~HW_INACTIVE;
99079697Snon	if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
99179697Snon	{
99279697Snon		slp->sl_flags |= HW_INACTIVE;
99379697Snon		splx(s);
99479697Snon		return error;
99579697Snon	}
99679697Snon
99779697Snon	slp->sl_timeout_count = 0;
99879697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
99979697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
100079697Snon	splx(s);
100179697Snon	return 0;
100279697Snon}
100379697Snon
100479697Snon/**************************************************************
100579697Snon * scsi low log
100679697Snon **************************************************************/
100779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
100892770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *);
100992770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int);
101092770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int);
101179697Snon
101279697Snonstatic void
101379697Snonscsi_low_msg_log_init(slmlp)
101479697Snon	struct scsi_low_msg_log *slmlp;
101579697Snon{
101679697Snon
101779697Snon	slmlp->slml_ptr = 0;
101879697Snon}
101979697Snon
102079697Snonstatic void
102179697Snonscsi_low_msg_log_write(slmlp, datap, len)
102279697Snon	struct scsi_low_msg_log *slmlp;
102379697Snon	u_int8_t *datap;
102479697Snon	int len;
102579697Snon{
102679697Snon	int ptr, ind;
102779697Snon
102879697Snon	if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
102979697Snon		return;
103079697Snon
103179697Snon	ptr = slmlp->slml_ptr ++;
103279697Snon	for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
103379697Snon		slmlp->slml_msg[ptr].msg[ind] = datap[ind];
103479697Snon	for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
103579697Snon		slmlp->slml_msg[ptr].msg[ind] = 0;
103679697Snon}
103779697Snon
103879697Snonstatic void
103979697Snonscsi_low_msg_log_show(slmlp, s, len)
104079697Snon	struct scsi_low_msg_log *slmlp;
104179697Snon	char *s;
104279697Snon	int len;
104379697Snon{
104479697Snon	int ptr, ind;
104579697Snon
104679697Snon	printf("%s: (%d) ", s, slmlp->slml_ptr);
104779697Snon	for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
104879697Snon	{
104979697Snon		for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
105079697Snon		     ind ++)
105179697Snon		{
105279697Snon			printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
105379697Snon		}
105479697Snon		printf(">");
105579697Snon	}
105679697Snon	printf("\n");
105779697Snon}
105879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
105979697Snon
106079697Snon/**************************************************************
106167468Snon * power control
106267468Snon **************************************************************/
106367468Snonstatic void
106467468Snonscsi_low_engage(arg)
106567468Snon	void *arg;
106667468Snon{
106767468Snon	struct scsi_low_softc *slp = arg;
1068240172Sjhb	int s = splcam();
106967468Snon
107067468Snon	switch (slp->sl_rstep)
107167468Snon	{
107267468Snon	case 0:
107367468Snon		slp->sl_rstep ++;
107467468Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
107579697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
107679697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START);
107767468Snon		break;
107867468Snon
107967468Snon	case 1:
108067468Snon		slp->sl_rstep ++;
108167468Snon		slp->sl_flags &= ~HW_RESUME;
108267468Snon		scsi_low_start(slp);
108367468Snon		break;
108467468Snon
108567468Snon	case 2:
108667468Snon		break;
108767468Snon	}
108867468Snon	splx(s);
108967468Snon}
109067468Snon
109167468Snonstatic int
109267468Snonscsi_low_init(slp, flags)
109367468Snon	struct scsi_low_softc *slp;
109467468Snon	u_int flags;
109567468Snon{
109679697Snon	int rv = 0;
109767468Snon
109879697Snon	slp->sl_flags |= HW_INITIALIZING;
109979697Snon
110079697Snon	/* clear power control timeout */
110167468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
110267468Snon	{
110379697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
110479697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
110567468Snon		slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
110667468Snon		slp->sl_active = 1;
110767468Snon		slp->sl_powc = SCSI_LOW_POWDOWN_TC;
110867468Snon	}
110967468Snon
111067468Snon	/* reset current nexus */
111167468Snon	scsi_low_reset_nexus(slp, flags);
111267468Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
111379697Snon	{
111479697Snon		rv = EBUSY;
111579697Snon		goto out;
111679697Snon	}
111767468Snon
111879697Snon	if (flags != SCSI_LOW_RESTART_SOFT)
111979697Snon	{
112079697Snon		rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
112179697Snon	}
112267468Snon
112379697Snonout:
112479697Snon	slp->sl_flags &= ~HW_INITIALIZING;
112579697Snon	return rv;
112667468Snon}
112767468Snon
112867468Snon/**************************************************************
112967468Snon * allocate lun_info
113067468Snon **************************************************************/
113167468Snonstatic struct lun_info *
113267468Snonscsi_low_alloc_li(ti, lun, alloc)
113367468Snon	struct targ_info *ti;
113467468Snon	int lun;
113567468Snon	int alloc;
113667468Snon{
113779697Snon	struct scsi_low_softc *slp = ti->ti_sc;
113867468Snon	struct lun_info *li;
113967468Snon
114067468Snon	li = LIST_FIRST(&ti->ti_litab);
114167468Snon	if (li != NULL)
114267468Snon	{
114367468Snon		if (li->li_lun == lun)
114467468Snon			return li;
114567468Snon
114667468Snon		while ((li = LIST_NEXT(li, lun_chain)) != NULL)
114767468Snon		{
114867468Snon			if (li->li_lun == lun)
114967468Snon			{
115067468Snon				LIST_REMOVE(li, lun_chain);
115167468Snon				LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
115267468Snon				return li;
115367468Snon			}
115467468Snon		}
115567468Snon	}
115667468Snon
115767468Snon	if (alloc == 0)
115867468Snon		return li;
115967468Snon
116079697Snon	li = SCSI_LOW_MALLOC(ti->ti_lunsize);
116167468Snon	if (li == NULL)
1162106890Simp		panic("no lun info mem");
116367468Snon
1164240172Sjhb	bzero(li, ti->ti_lunsize);
116567468Snon	li->li_lun = lun;
116667468Snon	li->li_ti = ti;
116767468Snon
116879697Snon	li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
116979697Snon			  SCSI_LOW_QTAG;
117079697Snon	li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
117179697Snon	li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
117279697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
117379697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
117479697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
117579697Snon
117679697Snon	li->li_qtagbits = (u_int) -1;
117779697Snon
117879697Snon	TAILQ_INIT(&li->li_discq);
117967468Snon	LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
118067468Snon
118179697Snon	/* host specific structure initialization per lun */
118279697Snon	if (slp->sl_funcs->scsi_low_lun_init != NULL)
118379697Snon		(*slp->sl_funcs->scsi_low_lun_init)
118479697Snon			(slp, ti, li, SCSI_LOW_INFO_ALLOC);
118579697Snon	scsi_low_calcf_lun(li);
118667468Snon	return li;
118767468Snon}
118867468Snon
118967468Snon/**************************************************************
119067468Snon * allocate targ_info
119167468Snon **************************************************************/
119267468Snonstatic struct targ_info *
119379697Snonscsi_low_alloc_ti(slp, targ)
119467468Snon	struct scsi_low_softc *slp;
119579697Snon	int targ;
119667468Snon{
119767468Snon	struct targ_info *ti;
119867468Snon
119971999Sphk	if (TAILQ_FIRST(&slp->sl_titab) == NULL)
120067468Snon		TAILQ_INIT(&slp->sl_titab);
120167468Snon
120279697Snon	ti = SCSI_LOW_MALLOC(slp->sl_targsize);
120367468Snon	if (ti == NULL)
1204240325Sjhb		panic("%s short of memory", device_get_nameunit(slp->sl_dev));
120567468Snon
1206240172Sjhb	bzero(ti, slp->sl_targsize);
120767468Snon	ti->ti_id = targ;
120867468Snon	ti->ti_sc = slp;
120967468Snon
121067468Snon	slp->sl_ti[targ] = ti;
121167468Snon	TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
121267468Snon	LIST_INIT(&ti->ti_litab);
121367468Snon
121479697Snon	ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
121579697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
121679697Snon	ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
121779697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
121879697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
121979697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
122073025Snon
122179697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
122279697Snon	{
122379697Snon		(*slp->sl_funcs->scsi_low_targ_init)
122479697Snon			(slp, ti, SCSI_LOW_INFO_ALLOC);
122579697Snon	}
122679697Snon	scsi_low_calcf_target(ti);
122767468Snon	return ti;
122867468Snon}
122967468Snon
123067468Snonstatic void
123167468Snonscsi_low_free_ti(slp)
123267468Snon	struct scsi_low_softc *slp;
123367468Snon{
123467468Snon	struct targ_info *ti, *tib;
123567468Snon	struct lun_info *li, *nli;
123667468Snon
123771999Sphk	for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
123867468Snon	{
123967468Snon		for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
124067468Snon		{
124179697Snon			if (slp->sl_funcs->scsi_low_lun_init != NULL)
124279697Snon			{
124379697Snon				(*slp->sl_funcs->scsi_low_lun_init)
124479697Snon					(slp, ti, li, SCSI_LOW_INFO_DEALLOC);
124579697Snon			}
124667468Snon			nli = LIST_NEXT(li, lun_chain);
124779697Snon			SCSI_LOW_FREE(li);
124867468Snon		}
124979697Snon
125079697Snon		if (slp->sl_funcs->scsi_low_targ_init != NULL)
125179697Snon		{
125279697Snon			(*slp->sl_funcs->scsi_low_targ_init)
125379697Snon				(slp, ti, SCSI_LOW_INFO_DEALLOC);
125479697Snon		}
125579697Snon		tib = TAILQ_NEXT(ti, ti_chain);
125679697Snon		SCSI_LOW_FREE(ti);
125767468Snon	}
125867468Snon}
125967468Snon
126067468Snon/**************************************************************
126167468Snon * timeout
126267468Snon **************************************************************/
126367468Snonvoid
126479697Snonscsi_low_bus_idle(slp)
126579697Snon	struct scsi_low_softc *slp;
126679697Snon{
126779697Snon
126879697Snon	slp->sl_retry_sel = 0;
126979697Snon	if (slp->sl_Tnexus == NULL)
127079697Snon		scsi_low_start(slp);
127179697Snon}
127279697Snon
127379697Snonstatic void
127467468Snonscsi_low_timeout(arg)
127567468Snon	void *arg;
127667468Snon{
127767468Snon	struct scsi_low_softc *slp = arg;
127879697Snon	int s;
127979697Snon
1280240172Sjhb	s = splcam();
128179697Snon	(void) scsi_low_timeout_check(slp);
128279697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
128379697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
128479697Snon	splx(s);
128579697Snon}
128679697Snon
128779697Snonstatic int
128879697Snonscsi_low_timeout_check(slp)
128979697Snon	struct scsi_low_softc *slp;
129079697Snon{
129167468Snon	struct targ_info *ti;
129279697Snon	struct lun_info *li;
129367468Snon	struct slccb *cb = NULL;		/* XXX */
129467468Snon
129579697Snon	/* selection restart */
129679697Snon	if (slp->sl_retry_sel != 0)
129767468Snon	{
129879697Snon		slp->sl_retry_sel = 0;
129979697Snon		if (slp->sl_Tnexus != NULL)
130079697Snon			goto step1;
130167468Snon
130279697Snon		cb = TAILQ_FIRST(&slp->sl_start);
130379697Snon		if (cb == NULL)
130479697Snon			goto step1;
130579697Snon
130679697Snon		if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
130767468Snon		{
130879697Snon			cb->ccb_flags |= CCB_NORETRY;
130979697Snon			cb->ccb_error |= SELTIMEOUTIO;
131079697Snon			if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1311240325Sjhb				panic("%s: ccb not finished",
1312240325Sjhb				    device_get_nameunit(slp->sl_dev));
131367468Snon		}
131479697Snon
131579697Snon		if (slp->sl_Tnexus == NULL)
131679697Snon			scsi_low_start(slp);
131767468Snon	}
131879697Snon
131979697Snon	/* call hardware timeout */
132079697Snonstep1:
132179697Snon	if (slp->sl_funcs->scsi_low_timeout != NULL)
132267468Snon	{
132379697Snon		(*slp->sl_funcs->scsi_low_timeout) (slp);
132479697Snon	}
132579697Snon
132679697Snon	if (slp->sl_timeout_count ++ <
132779697Snon	    SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
132879697Snon		return 0;
132979697Snon
133079697Snon	slp->sl_timeout_count = 0;
133179697Snon	if (slp->sl_nio > 0)
133279697Snon	{
133379697Snon		if ((cb = slp->sl_Qnexus) != NULL)
133467468Snon		{
133567468Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
133667468Snon			if (cb->ccb_tc < 0)
133767468Snon				goto bus_reset;
133867468Snon		}
133979697Snon		else if (slp->sl_disc == 0)
134067468Snon		{
134179697Snon		        if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
134279697Snon				return 0;
134367468Snon
134479697Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
134579697Snon			if (cb->ccb_tc < 0)
134679697Snon				goto bus_reset;
134779697Snon		}
134879697Snon		else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
134979697Snon		          ti = TAILQ_NEXT(ti, ti_chain))
135079697Snon		{
135179697Snon			if (ti->ti_disc == 0)
135279697Snon				continue;
135367468Snon
135479697Snon			for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
135579697Snon			     li = LIST_NEXT(li, lun_chain))
135667468Snon			{
135779697Snon				for (cb = TAILQ_FIRST(&li->li_discq);
135879697Snon				     cb != NULL;
135979697Snon				     cb = TAILQ_NEXT(cb, ccb_chain))
136079697Snon				{
136179697Snon					cb->ccb_tc -=
136279697Snon						SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
136379697Snon					if (cb->ccb_tc < 0)
136479697Snon						goto bus_reset;
136579697Snon				}
136667468Snon			}
136767468Snon		}
136879697Snon
136967468Snon	}
137079697Snon	else if ((slp->sl_flags & HW_POWERCTRL) != 0)
137179697Snon	{
137279697Snon		if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
137379697Snon			return 0;
137467468Snon
137579697Snon		if (slp->sl_active != 0)
137679697Snon		{
137779697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
137879697Snon			slp->sl_active = 0;
137979697Snon			return 0;
138079697Snon		}
138167468Snon
138279697Snon		slp->sl_powc --;
138379697Snon		if (slp->sl_powc < 0)
138479697Snon		{
138579697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
138679697Snon			slp->sl_flags |= HW_POWDOWN;
138779697Snon			(*slp->sl_funcs->scsi_low_power)
138879697Snon					(slp, SCSI_LOW_POWDOWN);
138979697Snon		}
139079697Snon	}
139179697Snon	return 0;
139267468Snon
139367468Snonbus_reset:
139467468Snon	cb->ccb_error |= TIMEOUTIO;
1395240325Sjhb	device_printf(slp->sl_dev, "slccb (0x%lx) timeout!\n", (u_long) cb);
139667468Snon	scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
139767468Snon	scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
139867468Snon	scsi_low_start(slp);
139979697Snon	return ERESTART;
140067468Snon}
140167468Snon
140267468Snon
140379697Snonstatic int
140479697Snonscsi_low_abort_ccb(slp, cb)
140579697Snon	struct scsi_low_softc *slp;
140679697Snon	struct slccb *cb;
140779697Snon{
140879697Snon	struct targ_info *ti;
140979697Snon	struct lun_info *li;
141079697Snon	u_int msg;
141167468Snon
141279697Snon	if (cb == NULL)
141379697Snon		return EINVAL;
141479697Snon	if ((cb->ccb_omsgoutflag &
141579697Snon	     (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
141679697Snon		return EBUSY;
141767468Snon
141879697Snon	ti = cb->ti;
141979697Snon	li = cb->li;
142079697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
142179697Snon		msg = SCSI_LOW_MSG_ABORT;
142279697Snon	else
142379697Snon		msg = SCSI_LOW_MSG_ABORT_QTAG;
142467468Snon
142579697Snon	cb->ccb_error |= ABORTIO;
142679697Snon	cb->ccb_flags |= CCB_NORETRY;
142779697Snon	scsi_low_ccb_message_assert(cb, msg);
142867468Snon
142979697Snon	if (cb == slp->sl_Qnexus)
143079697Snon	{
143179697Snon		scsi_low_assert_msg(slp, ti, msg, 1);
143279697Snon	}
143379697Snon	else if ((cb->ccb_flags & CCB_DISCQ) != 0)
143479697Snon	{
143579697Snon		if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
1436240325Sjhb			panic("%s: revoked ccb done",
1437240325Sjhb			    device_get_nameunit(slp->sl_dev));
143867468Snon
143979697Snon		cb->ccb_flags |= CCB_STARTQ;
144079697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
144167468Snon
144279697Snon		if (slp->sl_Tnexus == NULL)
144379697Snon			scsi_low_start(slp);
144479697Snon	}
144579697Snon	else
144679697Snon	{
144779697Snon		if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1448240325Sjhb			panic("%s: revoked ccb retried",
1449240325Sjhb			    device_get_nameunit(slp->sl_dev));
145079697Snon	}
145179697Snon	return 0;
145267468Snon}
145367468Snon
145479697Snon/**************************************************************
145579697Snon * Generic SCSI INTERFACE
145679697Snon **************************************************************/
145767468Snonint
145879697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
145967468Snon	struct scsi_low_softc *slp;
146079697Snon	int openings, ntargs, nluns, targsize, lunsize;
146167468Snon{
146267468Snon	struct targ_info *ti;
146367468Snon	struct lun_info *li;
146479697Snon	int s, i, nccb, rv;
146567468Snon
146679697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam;
146779697Snon
146879697Snon	if (slp->sl_osdep_fp == NULL)
1469106890Simp		panic("scsi_low: interface not spcified");
147079697Snon
147167468Snon	if (ntargs > SCSI_LOW_NTARGETS)
147267468Snon	{
147367468Snon		printf("scsi_low: %d targets are too large\n", ntargs);
147467468Snon		printf("change kernel options SCSI_LOW_NTARGETS");
147579697Snon		return EINVAL;
147667468Snon	}
147767468Snon
147879697Snon	if (openings <= 0)
147979697Snon		slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
148079697Snon	else
148179697Snon		slp->sl_openings = openings;
148279697Snon	slp->sl_ntargs = ntargs;
148379697Snon	slp->sl_nluns = nluns;
148479697Snon	slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
148567468Snon
148679697Snon	if (lunsize < sizeof(struct lun_info))
148779697Snon		lunsize = sizeof(struct lun_info);
148879697Snon
148979697Snon	if (targsize < sizeof(struct targ_info))
149079697Snon		targsize = sizeof(struct targ_info);
149179697Snon
149279697Snon	slp->sl_targsize = targsize;
149367468Snon	for (i = 0; i < ntargs; i ++)
149467468Snon	{
149579697Snon		ti = scsi_low_alloc_ti(slp, i);
149679697Snon		ti->ti_lunsize = lunsize;
149767468Snon		li = scsi_low_alloc_li(ti, 0, 1);
149867468Snon	}
149967468Snon
150067468Snon	/* initialize queue */
150179697Snon	nccb = openings * ntargs;
150267468Snon	if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
150367468Snon		nccb = SCSI_LOW_NCCB;
150467468Snon	scsi_low_init_ccbque(nccb);
150567468Snon	TAILQ_INIT(&slp->sl_start);
150667468Snon
150779697Snon	/* call os depend attach */
1508240172Sjhb	s = splcam();
150979697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp);
151079697Snon	if (rv != 0)
151179697Snon	{
151279697Snon		splx(s);
1513240325Sjhb		device_printf(slp->sl_dev,
1514240325Sjhb		    "scsi_low_attach: osdep attach failed\n");
151579697Snon		return EINVAL;
151679697Snon	}
151767468Snon
151879697Snon	/* check hardware */
1519240172Sjhb	DELAY(1000);	/* wait for 1ms */
152079697Snon	if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
152179697Snon	{
152279697Snon		splx(s);
1523240325Sjhb		device_printf(slp->sl_dev,
1524240325Sjhb		    "scsi_low_attach: initialization failed\n");
152579697Snon		return EINVAL;
152679697Snon	}
152767468Snon
152867468Snon	/* start watch dog */
152979697Snon	slp->sl_timeout_count = 0;
153079697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
153179697Snon		 (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
153279697Snon	LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
153367468Snon
153479697Snon	/* fake call */
153579697Snon	scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
153667468Snon
153779697Snon#ifdef	SCSI_LOW_START_UP_CHECK
153879697Snon	/* probing devices */
153979697Snon	scsi_low_start_up(slp);
154079697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
154167468Snon
154279697Snon	/* call os depend attach done*/
154379697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp);
154479697Snon	splx(s);
154579697Snon	return 0;
154667468Snon}
154767468Snon
154867468Snonint
154967468Snonscsi_low_dettach(slp)
155067468Snon	struct scsi_low_softc *slp;
155167468Snon{
155279697Snon	int s, rv;
155367468Snon
1554240172Sjhb	s = splcam();
155579697Snon	if (scsi_low_is_busy(slp) != 0)
155679697Snon	{
155779697Snon		splx(s);
155867468Snon		return EBUSY;
155979697Snon	}
156067468Snon
156179697Snon	scsi_low_deactivate(slp);
156267468Snon
156379697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp);
156479697Snon	if (rv != 0)
156579697Snon	{
156679697Snon		splx(s);
156779697Snon		return EBUSY;
156879697Snon	}
156967468Snon
157067468Snon	scsi_low_free_ti(slp);
157179697Snon	LIST_REMOVE(slp, sl_chain);
157279697Snon	splx(s);
157367468Snon	return 0;
157467468Snon}
157567468Snon
157679697Snon/**************************************************************
157779697Snon * Generic enqueue
157879697Snon **************************************************************/
157979697Snonstatic int
158079697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg)
158179697Snon	struct scsi_low_softc *slp;
158267468Snon	struct targ_info *ti;
158367468Snon	struct lun_info *li;
158467468Snon	struct slccb *cb;
158579697Snon	u_int flags, msg;
158679697Snon{
158767468Snon
158879697Snon	cb->ti = ti;
158979697Snon	cb->li = li;
159067468Snon
159179697Snon	scsi_low_ccb_message_assert(cb, msg);
159267468Snon
159379697Snon	cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
159479697Snon	scsi_low_alloc_qtag(cb);
159567468Snon
159679697Snon	cb->ccb_flags = flags | CCB_STARTQ;
159779697Snon	cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
159879697Snon	cb->ccb_error |= PENDINGIO;
159979697Snon
160079697Snon	if ((flags & CCB_URGENT) != 0)
160179697Snon	{
160279697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
160379697Snon	}
160479697Snon	else
160579697Snon	{
160667468Snon		TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
160779697Snon	}
160867468Snon
160979697Snon	slp->sl_nio ++;
161067468Snon
161179697Snon	if (slp->sl_Tnexus == NULL)
161279697Snon		scsi_low_start(slp);
161379697Snon	return 0;
161479697Snon}
161567468Snon
161679697Snonstatic int
161779697Snonscsi_low_message_enqueue(slp, ti, li, flags)
161879697Snon	struct scsi_low_softc *slp;
161979697Snon	struct targ_info *ti;
162079697Snon	struct lun_info *li;
162179697Snon	u_int flags;
162279697Snon{
162379697Snon	struct slccb *cb;
162479697Snon	u_int tmsgflags;
162567468Snon
162679697Snon	tmsgflags = ti->ti_setup_msg;
162779697Snon	ti->ti_setup_msg = 0;
162867468Snon
162979697Snon	flags |= CCB_NORETRY;
163079697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
163179697Snon		return ENOMEM;
163267468Snon
163379697Snon	cb->osdep = NULL;
163479697Snon	cb->bp = NULL;
163579697Snon	scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
163679697Snon	return 0;
163779697Snon}
163867468Snon
163979697Snon/**************************************************************
164079697Snon * Generic Start & Done
164179697Snon **************************************************************/
164279697Snon#define	SLSC_MODE_SENSE_SHORT   0x1a
164379697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
164479697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
164579697Snon			      sizeof(struct scsi_low_mode_sense_data), 0};
164679697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
164779697Snon			      sizeof(struct scsi_low_inq_data), 0};
164879697Snonstatic u_int8_t unit_ready_cmd[6];
164992770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
165092770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
165192770Salfredstatic int scsi_low_resume(struct scsi_low_softc *);
165279697Snon
165379697Snonstatic void
165479697Snonscsi_low_unit_ready_cmd(cb)
165579697Snon	struct slccb *cb;
165679697Snon{
165779697Snon
165879697Snon	cb->ccb_scp.scp_cmd = unit_ready_cmd;
165979697Snon	cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
166079697Snon	cb->ccb_scp.scp_datalen = 0;
166179697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
166279697Snon	cb->ccb_tcmax = 15;
166367468Snon}
166479697Snon
166567468Snonstatic int
166679697Snonscsi_low_sense_abort_start(slp, ti, li, cb)
166779697Snon	struct scsi_low_softc *slp;
166867468Snon	struct targ_info *ti;
166979697Snon	struct lun_info *li;
167067468Snon	struct slccb *cb;
167179697Snon{
167267468Snon
167379697Snon	cb->ccb_scp.scp_cmdlen = 6;
1674240172Sjhb	bzero(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
167579697Snon	cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
167679697Snon	cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
167779697Snon	cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
167879697Snon	cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
167979697Snon	cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
168079697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
168179697Snon	cb->ccb_tcmax = 15;
168279697Snon	scsi_low_ccb_message_clear(cb);
168379697Snon	if ((cb->ccb_flags & CCB_CLEARQ) != 0)
168467468Snon	{
168579697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
168667468Snon	}
168779697Snon	else
168879697Snon	{
1689240172Sjhb		bzero(&cb->ccb_sense, sizeof(cb->ccb_sense));
169079697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
169179697Snon		scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
169279697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
169379697Snon	}
169467468Snon
169579697Snon	return SCSI_LOW_START_NO_QTAG;
169679697Snon}
169767468Snon
169879697Snonstatic int
169979697Snonscsi_low_setup_start(slp, ti, li, cb)
170079697Snon	struct scsi_low_softc *slp;
170179697Snon	struct targ_info *ti;
170279697Snon	struct lun_info *li;
170379697Snon	struct slccb *cb;
170479697Snon{
170567468Snon
170679697Snon	switch(li->li_state)
170779697Snon	{
170879697Snon	case SCSI_LOW_LUN_SLEEP:
170979697Snon		scsi_low_unit_ready_cmd(cb);
171079697Snon		break;
171167468Snon
171279697Snon	case SCSI_LOW_LUN_START:
171379697Snon		cb->ccb_scp.scp_cmd = ss_cmd;
171479697Snon		cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
171579697Snon		cb->ccb_scp.scp_datalen = 0;
171679697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
171779697Snon		cb->ccb_tcmax = 30;
171879697Snon		break;
171967468Snon
172079697Snon	case SCSI_LOW_LUN_INQ:
172179697Snon		cb->ccb_scp.scp_cmd = inq_cmd;
172279697Snon		cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
172379697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
172479697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
172579697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
172679697Snon		cb->ccb_tcmax = 15;
172779697Snon		break;
172867468Snon
172979697Snon	case SCSI_LOW_LUN_MODEQ:
173079697Snon		cb->ccb_scp.scp_cmd = sms_cmd;
173179697Snon		cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
173279697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
173379697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
173479697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
173579697Snon		cb->ccb_tcmax = 15;
173679697Snon		return SCSI_LOW_START_QTAG;
173767468Snon
173879697Snon	default:
1739240325Sjhb		panic("%s: no setup phase", device_get_nameunit(slp->sl_dev));
174067468Snon	}
174167468Snon
174279697Snon	return SCSI_LOW_START_NO_QTAG;
174367468Snon}
174467468Snon
174579697Snonstatic int
174679697Snonscsi_low_resume(slp)
174779697Snon	struct scsi_low_softc *slp;
174867468Snon{
174967468Snon
175079697Snon	if (slp->sl_flags & HW_RESUME)
175179697Snon		return EJUSTRETURN;
175279697Snon	slp->sl_flags &= ~HW_POWDOWN;
175379697Snon	if (slp->sl_funcs->scsi_low_power != NULL)
175479697Snon	{
175579697Snon		slp->sl_flags |= HW_RESUME;
175679697Snon		slp->sl_rstep = 0;
175779697Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
175879697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
175979697Snon					(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE,
176079697Snon				         SCSI_LOW_TIMEOUT_START);
176179697Snon		return EJUSTRETURN;
176279697Snon	}
176379697Snon	return 0;
176467468Snon}
176567468Snon
176667468Snonstatic void
176767468Snonscsi_low_start(slp)
176867468Snon	struct scsi_low_softc *slp;
176967468Snon{
177067468Snon	struct targ_info *ti;
177167468Snon	struct lun_info *li;
177267468Snon	struct slccb *cb;
177367468Snon	int rv;
177467468Snon
177579697Snon	/* check hardware exists or under initializations ? */
177679697Snon	if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
177767468Snon		return;
177867468Snon
177967468Snon	/* check hardware power up ? */
178067468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
178167468Snon	{
178267468Snon		slp->sl_active ++;
178367468Snon		if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
178467468Snon		{
178579697Snon			if (scsi_low_resume(slp) == EJUSTRETURN)
178667468Snon				return;
178767468Snon		}
178867468Snon	}
178967468Snon
179067468Snon	/* setup nexus */
179167468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
179279697Snon	if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
179367468Snon	{
179467468Snon		scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
1795240325Sjhb		panic("%s: inconsistent", device_get_nameunit(slp->sl_dev));
179667468Snon	}
179767468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
179867468Snon
179979697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
180079697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
180167468Snon	{
180267468Snon		li = cb->li;
180379697Snon
180479697Snon		if (li->li_disc == 0)
180579697Snon		{
180667468Snon			goto scsi_low_cmd_start;
180779697Snon		}
180879697Snon		else if (li->li_nqio > 0)
180979697Snon		{
181079697Snon			if (li->li_nqio < li->li_maxnqio ||
181179697Snon		            (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
181279697Snon				goto scsi_low_cmd_start;
181379697Snon		}
181467468Snon	}
181567468Snon	return;
181667468Snon
181767468Snonscsi_low_cmd_start:
181879697Snon	cb->ccb_flags &= ~CCB_STARTQ;
181979697Snon	TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
182079697Snon	ti = cb->ti;
182167468Snon
182267468Snon	/* clear all error flag bits (for restart) */
182367468Snon	cb->ccb_error = 0;
182479697Snon	cb->ccb_datalen = -1;
182579697Snon	cb->ccb_scp.scp_status = ST_UNKNOWN;
182667468Snon
182767468Snon	/* setup nexus pointer */
182879697Snon	slp->sl_Qnexus = cb;
182979697Snon	slp->sl_Lnexus = li;
183079697Snon	slp->sl_Tnexus = ti;
183167468Snon
183267468Snon	/* initialize msgsys */
183367468Snon	scsi_low_init_msgsys(slp, ti);
183467468Snon
183579697Snon	/* exec cmd */
183679697Snon	if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
183767468Snon	{
183879697Snon		/* CA state or forced abort */
183979697Snon		rv = scsi_low_sense_abort_start(slp, ti, li, cb);
184067468Snon	}
184179697Snon	else if (li->li_state >= SCSI_LOW_LUN_OK)
184267468Snon	{
184379697Snon		cb->ccb_flags &= ~CCB_INTERNAL;
184479697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb);
184579697Snon		if (cb->ccb_msgoutflag != 0)
184679697Snon		{
184779697Snon			scsi_low_ccb_message_exec(slp, cb);
184879697Snon		}
184967468Snon	}
185079697Snon	else
185167468Snon	{
185279697Snon		cb->ccb_flags |= CCB_INTERNAL;
185379697Snon		rv = scsi_low_setup_start(slp, ti, li, cb);
185479697Snon	}
185567468Snon
185679697Snon	/* allocate qtag */
185779697Snon#define	SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
185867468Snon
185979697Snon	if (rv == SCSI_LOW_START_QTAG &&
186079697Snon	    (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
186179697Snon	    li->li_maxnqio > 0)
186279697Snon	{
186379697Snon		u_int qmsg;
186467468Snon
186579697Snon		scsi_low_activate_qtag(cb);
186679697Snon		if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
186779697Snon		     SCSI_LOW_CMD_ORDERED_QTAG) != 0)
186879697Snon			qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
186979697Snon		else if ((cb->ccb_flags & CCB_URGENT) != 0)
187079697Snon			qmsg = SCSI_LOW_MSG_HEAD_QTAG;
187179697Snon		else
187279697Snon			qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
187379697Snon		scsi_low_assert_msg(slp, ti, qmsg, 0);
187467468Snon	}
187567468Snon
187667468Snon	/* timeout */
187767468Snon	if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
187867468Snon		cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
187967468Snon	cb->ccb_tc = cb->ccb_tcmax;
188067468Snon
188167468Snon	/* setup saved scsi data pointer */
188267468Snon	cb->ccb_sscp = cb->ccb_scp;
188367468Snon
188467468Snon	/* setup current scsi pointer */
188567468Snon	slp->sl_scp = cb->ccb_sscp;
188667468Snon	slp->sl_error = cb->ccb_error;
188767468Snon
188879697Snon	/* assert always an identify msg */
188979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
189079697Snon
189179697Snon	/* debug section */
189279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
189379697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
189479697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
189579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
189679697Snon
189767468Snon	/* selection start */
189879697Snon	slp->sl_selid = cb;
189967468Snon	rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
190067468Snon	if (rv == SCSI_LOW_START_OK)
190167468Snon	{
190267468Snon#ifdef	SCSI_LOW_STATICS
190367468Snon		scsi_low_statics.nexus_win ++;
190467468Snon#endif	/* SCSI_LOW_STATICS */
190567468Snon		return;
190667468Snon	}
190767468Snon
190879697Snon	scsi_low_arbit_fail(slp, cb);
190967468Snon#ifdef	SCSI_LOW_STATICS
191067468Snon	scsi_low_statics.nexus_fail ++;
191167468Snon#endif	/* SCSI_LOW_STATICS */
191267468Snon}
191367468Snon
191467468Snonvoid
191579697Snonscsi_low_arbit_fail(slp, cb)
191667468Snon	struct scsi_low_softc *slp;
191779697Snon	struct slccb *cb;
191879697Snon{
191979697Snon	struct targ_info *ti = cb->ti;
192079697Snon
192179697Snon	scsi_low_deactivate_qtag(cb);
192279697Snon	scsi_low_ccb_message_retry(cb);
192379697Snon	cb->ccb_flags |= CCB_STARTQ;
192479697Snon	TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
192579697Snon
192679697Snon	scsi_low_bus_release(slp, ti);
192779697Snon
192879697Snon	cb->ccb_selrcnt ++;
192979697Snon	if (slp->sl_disc == 0)
193079697Snon	{
193179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
1932240325Sjhb		device_printf(slp->sl_dev, "try selection again\n");
193379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
193479697Snon		slp->sl_retry_sel = 1;
193579697Snon	}
193679697Snon}
193779697Snon
193879697Snonstatic void
193979697Snonscsi_low_bus_release(slp, ti)
194079697Snon	struct scsi_low_softc *slp;
194167468Snon	struct targ_info *ti;
194267468Snon{
194367468Snon
194479697Snon	if (ti->ti_disc > 0)
194579697Snon	{
194679697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
194779697Snon	}
194879697Snon	else
194979697Snon	{
195079697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
195179697Snon	}
195279697Snon
195367468Snon	/* clear all nexus pointer */
195479697Snon	slp->sl_Qnexus = NULL;
195579697Snon	slp->sl_Lnexus = NULL;
195679697Snon	slp->sl_Tnexus = NULL;
195767468Snon
195867468Snon	/* clear selection assert */
195967468Snon	slp->sl_selid = NULL;
196067468Snon
196167468Snon	/* clear nexus data */
196267468Snon	slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
196379697Snon
196479697Snon	/* clear phase change counter */
196579697Snon	slp->sl_ph_count = 0;
196667468Snon}
196767468Snon
196867468Snonstatic int
196979697Snonscsi_low_setup_done(slp, cb)
197067468Snon	struct scsi_low_softc *slp;
197167468Snon	struct slccb *cb;
197267468Snon{
197367468Snon	struct targ_info *ti;
197467468Snon	struct lun_info *li;
197567468Snon
197667468Snon	ti = cb->ti;
197767468Snon	li = cb->li;
197879697Snon
197979697Snon	if (cb->ccb_rcnt >= slp->sl_max_retry)
198067468Snon	{
198179697Snon		cb->ccb_error |= ABORTIO;
198279697Snon		return SCSI_LOW_DONE_COMPLETE;
198379697Snon	}
198479697Snon
198579697Snon	/* XXX: special huck for selection timeout */
198679697Snon	if (li->li_state == SCSI_LOW_LUN_SLEEP &&
198779697Snon	    (cb->ccb_error & SELTIMEOUTIO) != 0)
198879697Snon	{
198979697Snon		cb->ccb_error |= ABORTIO;
199079697Snon		return SCSI_LOW_DONE_COMPLETE;
199179697Snon	}
199279697Snon
199379697Snon	switch(li->li_state)
199479697Snon	{
199579697Snon	case SCSI_LOW_LUN_INQ:
199679697Snon		if (cb->ccb_error != 0)
199767468Snon		{
199879697Snon			li->li_diskflags &=
199979697Snon				~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
200079697Snon			if (li->li_lun > 0)
200179697Snon				goto resume;
200279697Snon			ti->ti_diskflags &=
200379697Snon				~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
200467468Snon		}
200579697Snon		else if ((li->li_inq.sd_version & 7) >= 2 ||
200679697Snon		         (li->li_inq.sd_len >= 4))
200767468Snon		{
200879697Snon			if ((li->li_inq.sd_support & 0x2) == 0)
200979697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
201079697Snon			if ((li->li_inq.sd_support & 0x8) == 0)
201179697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
201279697Snon			if (li->li_lun > 0)
201379697Snon				goto resume;
201479697Snon			if ((li->li_inq.sd_support & 0x10) == 0)
201579697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
201679697Snon			if ((li->li_inq.sd_support & 0x20) == 0)
201779697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
201879697Snon			if ((li->li_inq.sd_support & 0x40) == 0)
201979697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
202079697Snon		}
202179697Snon		else
202279697Snon		{
202379697Snon			li->li_diskflags &=
202479697Snon				~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
202579697Snon			if (li->li_lun > 0)
202679697Snon				goto resume;
202779697Snon			ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
202879697Snon		}
202979697Snon		ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
203079697Snonresume:
203179697Snon		scsi_low_calcf_target(ti);
203279697Snon		scsi_low_calcf_lun(li);
203379697Snon		break;
203479697Snon
203579697Snon	case SCSI_LOW_LUN_MODEQ:
203679697Snon		if (cb->ccb_error != 0)
203779697Snon		{
203879697Snon			if (cb->ccb_error & SENSEIO)
203967468Snon			{
204079697Snon#ifdef	SCSI_LOW_DEBUG
204179697Snon				if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
204279697Snon				{
2043225950Sken					int error_code, sense_key, asc, ascq;
2044225950Sken
2045225950Sken					scsi_extract_sense(&cb->ccb_sense,
2046225950Sken							   &error_code,
2047225950Sken							   &sense_key,
2048225950Sken							   &asc,
2049225950Sken							   &ascq);
2050225950Sken					printf("SENSE: [%x][%x][%x][%x]\n",
2051225950Sken					       error_code, sense_key, asc,
2052225950Sken					       ascq);
205379697Snon				}
205479697Snon#endif	/* SCSI_LOW_DEBUG */
205567468Snon			}
205679697Snon			else
205779697Snon			{
205879697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
205979697Snon			}
206079697Snon		}
206179697Snon		else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
206279697Snon		{
206379697Snon			if (li->li_sms.sms_cmp.cmp_qc & 0x02)
206479697Snon				li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
206579697Snon			else
206679697Snon				li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
206779697Snon			if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
206879697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
206979697Snon		}
207079697Snon		li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
207179697Snon		scsi_low_calcf_lun(li);
207279697Snon		break;
207367468Snon
207479697Snon	default:
207579697Snon		break;
207679697Snon	}
207779697Snon
207879697Snon	li->li_state ++;
207979697Snon	if (li->li_state == SCSI_LOW_LUN_OK)
208079697Snon	{
208179697Snon		scsi_low_calcf_target(ti);
208279697Snon		scsi_low_calcf_lun(li);
208379697Snon		if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
208479697Snon	            (slp->sl_show_result & SHOW_CALCF_RES) != 0)
208579697Snon		{
208679697Snon			scsi_low_calcf_show(li);
208779697Snon		}
208879697Snon	}
208979697Snon
209079697Snon	cb->ccb_rcnt --;
209179697Snon	return SCSI_LOW_DONE_RETRY;
209279697Snon}
209379697Snon
209479697Snonstatic int
209579697Snonscsi_low_done(slp, cb)
209679697Snon	struct scsi_low_softc *slp;
209779697Snon	struct slccb *cb;
209879697Snon{
209979697Snon	int rv;
210079697Snon
210179697Snon	if (cb->ccb_error == 0)
210279697Snon	{
210379697Snon		if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
210479697Snon		{
210579697Snon#ifdef	SCSI_LOW_QCLEAR_AFTER_CA
210679697Snon			/* XXX:
210779697Snon			 * SCSI-2 draft suggests
210879697Snon			 * page 0x0a QErr bit determins if
210979697Snon			 * the target aborts or continues
211079697Snon			 * the queueing io's after CA state resolved.
211179697Snon			 * However many targets seem not to support
211279697Snon			 * the page 0x0a. Thus we should manually clear the
211379697Snon			 * queuing io's after CA state.
211479697Snon			 */
211579697Snon			if ((cb->ccb_flags & CCB_CLEARQ) == 0)
211667468Snon			{
211779697Snon				cb->ccb_rcnt --;
211879697Snon				cb->ccb_flags |= CCB_CLEARQ;
211979697Snon				goto retry;
212079697Snon			}
212179697Snon#endif	/* SCSI_LOW_QCLEAR_AFTER_CA */
212279697Snon
212379697Snon			if ((cb->ccb_flags & CCB_SENSE) != 0)
212479697Snon				cb->ccb_error |= (SENSEIO | ABORTIO);
212579697Snon			cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
212679697Snon		}
212779697Snon		else switch (cb->ccb_sscp.scp_status)
212879697Snon		{
212979697Snon		case ST_GOOD:
213079697Snon		case ST_MET:
213179697Snon		case ST_INTERGOOD:
213279697Snon		case ST_INTERMET:
213379697Snon			if (cb->ccb_datalen == 0 ||
213479697Snon			    cb->ccb_scp.scp_datalen == 0)
213567468Snon				break;
213667468Snon
213779697Snon			if (cb->ccb_scp.scp_cmdlen > 0 &&
213879697Snon			    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
213979697Snon			     SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
214079697Snon				break;
214179697Snon
214267468Snon			cb->ccb_error |= PDMAERR;
214367468Snon			break;
214467468Snon
214579697Snon		case ST_BUSY:
214679697Snon		case ST_QUEFULL:
214779697Snon			cb->ccb_error |= (BUSYERR | STATERR);
214879697Snon			break;
214979697Snon
215079697Snon		case ST_CONFLICT:
215179697Snon			cb->ccb_error |= (STATERR | ABORTIO);
215279697Snon			break;
215379697Snon
215467468Snon		case ST_CHKCOND:
215579697Snon		case ST_CMDTERM:
215679697Snon			if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
215779697Snon			{
215879697Snon				cb->ccb_rcnt --;
215973025Snon				cb->ccb_flags |= CCB_SENSE;
216073025Snon				goto retry;
216173025Snon			}
216279697Snon			cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
216373025Snon			break;
216467468Snon
216579697Snon		case ST_UNKNOWN:
216667468Snon		default:
216767468Snon			cb->ccb_error |= FATALIO;
216867468Snon			break;
216967468Snon		}
217067468Snon	}
217167468Snon	else
217267468Snon	{
217379697Snon		if (cb->ccb_flags & CCB_SENSE)
217467468Snon		{
217579697Snon			cb->ccb_error |= (SENSEERR | ABORTIO);
217667468Snon		}
217779697Snon		cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
217879697Snon	}
217967468Snon
218079697Snon	/* internal ccb */
218179697Snon	if ((cb->ccb_flags & CCB_INTERNAL) != 0)
218279697Snon	{
218379697Snon		if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
218479697Snon			goto retry;
218567468Snon	}
218667468Snon
218779697Snon	/* check a ccb msgout flag */
218879697Snon	if (cb->ccb_omsgoutflag != 0)
218967468Snon	{
219079697Snon#define	SCSI_LOW_MSG_ABORT_OK	(SCSI_LOW_MSG_ABORT | \
219179697Snon				 SCSI_LOW_MSG_ABORT_QTAG | \
219279697Snon				 SCSI_LOW_MSG_CLEAR_QTAG | \
219379697Snon				 SCSI_LOW_MSG_TERMIO)
219479697Snon
219579697Snon		if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
219667468Snon		{
219779697Snon			cb->ccb_error |= ABORTIO;
219867468Snon		}
219967468Snon	}
220067468Snon
220179697Snon	/* call OS depend done */
220279697Snon	if (cb->osdep != NULL)
220367468Snon	{
220479697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb);
220579697Snon		if (rv == EJUSTRETURN)
220679697Snon			goto retry;
220767468Snon	}
220879697Snon	else if (cb->ccb_error != 0)
220967468Snon	{
221079697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
221179697Snon			cb->ccb_error |= ABORTIO;
221279697Snon
221379697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
221479697Snon		    (cb->ccb_error & ABORTIO) == 0)
221567468Snon			goto retry;
221667468Snon	}
221779697Snon
221879697Snon	/* free our target */
221979697Snon#ifdef	SCSI_LOW_DEBUG
222079697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
222167468Snon	{
222279697Snon		printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
222379697Snon		scsi_low_print(slp, NULL);
222467468Snon	}
222579697Snon#endif	/* SCSI_LOW_DEBUG */
222667468Snon
222779697Snon	scsi_low_deactivate_qtag(cb);
222879697Snon	scsi_low_dealloc_qtag(cb);
222967468Snon	scsi_low_free_ccb(cb);
223079697Snon	slp->sl_nio --;
223167468Snon	return SCSI_LOW_DONE_COMPLETE;
223267468Snon
223367468Snonretry:
223479697Snon#ifdef	SCSI_LOW_DEBUG
223579697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
223667468Snon	{
223779697Snon		printf("** SCSI_LOW_DONE_RETRY ===============\n");
223879697Snon		scsi_low_print(slp, NULL);
223967468Snon	}
224079697Snon#endif	/* SCSI_LOW_DEBUG */
224179697Snon
224279697Snon	cb->ccb_rcnt ++;
224379697Snon	scsi_low_deactivate_qtag(cb);
224479697Snon	scsi_low_ccb_message_retry(cb);
224567468Snon	return SCSI_LOW_DONE_RETRY;
224667468Snon}
224767468Snon
224867468Snon/**************************************************************
224967468Snon * Reset
225067468Snon **************************************************************/
225167468Snonstatic void
225279697Snonscsi_low_reset_nexus_target(slp, ti, fdone)
225379697Snon	struct scsi_low_softc *slp;
225479697Snon	struct targ_info *ti;
225579697Snon	int fdone;
225667468Snon{
225779697Snon	struct lun_info *li;
225867468Snon
225979697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
226079697Snon	     li = LIST_NEXT(li, lun_chain))
226179697Snon	{
226279697Snon		scsi_low_reset_nexus_lun(slp, li, fdone);
226379697Snon		li->li_state = SCSI_LOW_LUN_SLEEP;
226479697Snon		li->li_maxnqio = 0;
226579697Snon	}
226679697Snon
226779697Snon	ti->ti_disc = 0;
226879697Snon	ti->ti_setup_msg = 0;
226979697Snon	ti->ti_setup_msg_done = 0;
227079697Snon
227179697Snon	ti->ti_osynch.offset = ti->ti_osynch.period = 0;
227279697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
227379697Snon
227479697Snon	ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
227579697Snon	ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
227679697Snon
227779697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
227879697Snon	{
227979697Snon		((*slp->sl_funcs->scsi_low_targ_init)
228079697Snon			(slp, ti, SCSI_LOW_INFO_REVOKE));
228179697Snon	}
228279697Snon	scsi_low_calcf_target(ti);
228379697Snon
228479697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
228579697Snon	     li = LIST_NEXT(li, lun_chain))
228679697Snon	{
228779697Snon		li->li_flags = 0;
228879697Snon
228979697Snon		li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
229079697Snon		li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
229179697Snon
229279697Snon		if (slp->sl_funcs->scsi_low_lun_init != NULL)
229379697Snon		{
229479697Snon			((*slp->sl_funcs->scsi_low_lun_init)
229579697Snon				(slp, ti, li, SCSI_LOW_INFO_REVOKE));
229679697Snon		}
229779697Snon		scsi_low_calcf_lun(li);
229879697Snon	}
229967468Snon}
230067468Snon
230167468Snonstatic void
230267468Snonscsi_low_reset_nexus(slp, fdone)
230367468Snon	struct scsi_low_softc *slp;
230467468Snon	int fdone;
230567468Snon{
230667468Snon	struct targ_info *ti;
230779697Snon	struct slccb *cb, *topcb;
230867468Snon
230979697Snon	if ((cb = slp->sl_Qnexus) != NULL)
231067468Snon	{
231179697Snon		topcb = scsi_low_revoke_ccb(slp, cb, fdone);
231267468Snon	}
231379697Snon	else
231479697Snon	{
231579697Snon		topcb = NULL;
231679697Snon	}
231767468Snon
231879697Snon	for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
231979697Snon	     ti = TAILQ_NEXT(ti, ti_chain))
232067468Snon	{
232179697Snon		scsi_low_reset_nexus_target(slp, ti, fdone);
232279697Snon		scsi_low_bus_release(slp, ti);
232367468Snon		scsi_low_init_msgsys(slp, ti);
232467468Snon	}
232567468Snon
232679697Snon	if (topcb != NULL)
232779697Snon	{
232879697Snon		topcb->ccb_flags |= CCB_STARTQ;
232979697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
233079697Snon	}
233179697Snon
233279697Snon	slp->sl_disc = 0;
233379697Snon	slp->sl_retry_sel = 0;
233467468Snon	slp->sl_flags &= ~HW_PDMASTART;
233567468Snon}
233667468Snon
233767468Snon/* misc */
233867468Snonstatic int tw_pos;
233967468Snonstatic char tw_chars[] = "|/-\\";
234079697Snon#define	TWIDDLEWAIT		10000
234167468Snon
234267468Snonstatic void
234367468Snonscsi_low_twiddle_wait(void)
234467468Snon{
234567468Snon
234667468Snon	cnputc('\b');
234767468Snon	cnputc(tw_chars[tw_pos++]);
234867468Snon	tw_pos %= (sizeof(tw_chars) - 1);
2349240172Sjhb	DELAY(TWIDDLEWAIT);
235067468Snon}
235167468Snon
235267468Snonvoid
235367468Snonscsi_low_bus_reset(slp)
235467468Snon	struct scsi_low_softc *slp;
235567468Snon{
235667468Snon	int i;
235767468Snon
235867468Snon	(*slp->sl_funcs->scsi_low_bus_reset) (slp);
235967468Snon
2360240325Sjhb	device_printf(slp->sl_dev, "try to reset scsi bus  ");
236167468Snon	for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++)
236267468Snon		scsi_low_twiddle_wait();
236367468Snon	cnputc('\b');
236467468Snon	printf("\n");
236567468Snon}
236667468Snon
236767468Snonint
236867468Snonscsi_low_restart(slp, flags, s)
236967468Snon	struct scsi_low_softc *slp;
237067468Snon	int flags;
237167468Snon	u_char *s;
237267468Snon{
237367468Snon	int error;
237467468Snon
237567468Snon	if (s != NULL)
2376240325Sjhb		device_printf(slp->sl_dev, "scsi bus restart. reason: %s\n", s);
237767468Snon
237867468Snon	if ((error = scsi_low_init(slp, flags)) != 0)
237967468Snon		return error;
238067468Snon
238167468Snon	scsi_low_start(slp);
238267468Snon	return 0;
238367468Snon}
238467468Snon
238567468Snon/**************************************************************
238667468Snon * disconnect and reselect
238767468Snon **************************************************************/
238867468Snon#define	MSGCMD_LUN(msg)	(msg & 0x07)
238967468Snon
239067468Snonstatic struct slccb *
239167468Snonscsi_low_establish_ccb(ti, li, tag)
239267468Snon	struct targ_info *ti;
239367468Snon	struct lun_info *li;
239467468Snon	scsi_low_tag_t tag;
239567468Snon{
239667468Snon	struct scsi_low_softc *slp = ti->ti_sc;
239767468Snon	struct slccb *cb;
239867468Snon
239979697Snon	if (li == NULL)
240079697Snon		return NULL;
240179697Snon
240279697Snon	cb = TAILQ_FIRST(&li->li_discq);
240371999Sphk	for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
240479697Snon		if (cb->ccb_tag == tag)
240567468Snon			goto found;
240667468Snon	return cb;
240767468Snon
240867468Snon	/*
240967468Snon	 * establish our ccb nexus
241067468Snon	 */
241167468Snonfound:
241279697Snon#ifdef	SCSI_LOW_DEBUG
241379697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
241479697Snon	{
2415240325Sjhb		device_printf(slp->sl_dev, "nexus(0x%lx) abort check start\n",
2416240325Sjhb		    (u_long) cb);
241779697Snon		cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
241879697Snon		scsi_low_revoke_ccb(slp, cb, 1);
241979697Snon		return NULL;
242079697Snon	}
242167468Snon
242279697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
242379697Snon	{
242479697Snon		if (cb->ccb_omsgoutflag == 0)
242579697Snon			scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
242679697Snon	}
242779697Snon#endif	/* SCSI_LOW_DEBUG */
242879697Snon
242979697Snon	TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
243079697Snon	cb->ccb_flags &= ~CCB_DISCQ;
243179697Snon	slp->sl_Qnexus = cb;
243279697Snon
243367468Snon	slp->sl_scp = cb->ccb_sscp;
243467468Snon	slp->sl_error |= cb->ccb_error;
243567468Snon
243667468Snon	slp->sl_disc --;
243779697Snon	ti->ti_disc --;
243867468Snon	li->li_disc --;
243967468Snon
244067468Snon	/* inform "ccb nexus established" to the host driver */
244179697Snon	(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
244279697Snon
244379697Snon	/* check msg */
244479697Snon	if (cb->ccb_msgoutflag != 0)
244579697Snon	{
244679697Snon		scsi_low_ccb_message_exec(slp, cb);
244779697Snon	}
244879697Snon
244967468Snon	return cb;
245067468Snon}
245167468Snon
245267468Snonstruct targ_info *
245367468Snonscsi_low_reselected(slp, targ)
245467468Snon	struct scsi_low_softc *slp;
245567468Snon	u_int targ;
245667468Snon{
245767468Snon	struct targ_info *ti;
245879697Snon	struct slccb *cb;
245967468Snon	u_char *s;
246067468Snon
246167468Snon	/*
246267468Snon	 * Check select vs reselected collision.
246367468Snon	 */
246467468Snon
246579697Snon	if ((cb = slp->sl_selid) != NULL)
246667468Snon	{
246779697Snon		scsi_low_arbit_fail(slp, cb);
246867468Snon#ifdef	SCSI_LOW_STATICS
246967468Snon		scsi_low_statics.nexus_conflict ++;
247067468Snon#endif	/* SCSI_LOW_STATICS */
247167468Snon	}
247279697Snon
247379697Snon	/*
247479697Snon	 * Check if no current active nexus.
247579697Snon	 */
247679697Snon	if (slp->sl_Tnexus != NULL)
247767468Snon	{
247867468Snon		s = "host busy";
247967468Snon		goto world_restart;
248067468Snon	}
248167468Snon
248267468Snon	/*
248367468Snon	 * Check a valid target id asserted ?
248467468Snon	 */
248567468Snon	if (targ >= slp->sl_ntargs || targ == slp->sl_hostid)
248667468Snon	{
248767468Snon		s = "scsi id illegal";
248867468Snon		goto world_restart;
248967468Snon	}
249067468Snon
249167468Snon	/*
249267468Snon	 * Check the target scsi status.
249367468Snon	 */
249467468Snon	ti = slp->sl_ti[targ];
249579697Snon	if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
249667468Snon	{
249767468Snon		s = "phase mismatch";
249867468Snon		goto world_restart;
249967468Snon	}
250067468Snon
250167468Snon	/*
250279697Snon	 * Setup init msgsys
250367468Snon	 */
250467468Snon	slp->sl_error = 0;
250567468Snon	scsi_low_init_msgsys(slp, ti);
250667468Snon
250767468Snon	/*
250867468Snon	 * Establish our target nexus
250967468Snon	 */
251067468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
251179697Snon	slp->sl_Tnexus = ti;
251267468Snon#ifdef	SCSI_LOW_STATICS
251367468Snon	scsi_low_statics.nexus_reselected ++;
251467468Snon#endif	/* SCSI_LOW_STATICS */
251567468Snon	return ti;
251667468Snon
251767468Snonworld_restart:
2518240325Sjhb	device_printf(slp->sl_dev, "reselect(%x:unknown) %s\n", targ, s);
251967468Snon	scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
252067468Snon		         "reselect: scsi world confused");
252167468Snon	return NULL;
252267468Snon}
252367468Snon
252467468Snon/**************************************************************
252567468Snon * cmd out pointer setup
252667468Snon **************************************************************/
252767468Snonint
252867468Snonscsi_low_cmd(slp, ti)
252967468Snon	struct scsi_low_softc *slp;
253067468Snon	struct targ_info *ti;
253167468Snon{
253279697Snon	struct slccb *cb = slp->sl_Qnexus;
253367468Snon
253479697Snon	slp->sl_ph_count ++;
253567468Snon	if (cb == NULL)
253667468Snon	{
253767468Snon		/*
253879697Snon		 * no ccb, abort!
253967468Snon		 */
254067468Snon		slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
254167468Snon		slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
254267468Snon		slp->sl_scp.scp_datalen = 0;
254367468Snon		slp->sl_scp.scp_direction = SCSI_LOW_READ;
254479697Snon		slp->sl_error |= FATALIO;
254579697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
254679697Snon		SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
254779697Snon		return EINVAL;
254867468Snon	}
254979697Snon	else
255067468Snon	{
255179697Snon#ifdef	SCSI_LOW_DEBUG
255279697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
255379697Snon		{
255479697Snon			scsi_low_test_cmdlnk(slp, cb);
255579697Snon		}
255679697Snon#endif	/* SCSI_LOW_DEBUG */
255767468Snon	}
255867468Snon	return 0;
255967468Snon}
256067468Snon
256167468Snon/**************************************************************
256267468Snon * data out pointer setup
256367468Snon **************************************************************/
256467468Snonint
256567468Snonscsi_low_data(slp, ti, bp, direction)
256667468Snon	struct scsi_low_softc *slp;
256767468Snon	struct targ_info *ti;
256867468Snon	struct buf **bp;
256967468Snon	int direction;
257067468Snon{
257179697Snon	struct slccb *cb = slp->sl_Qnexus;
257267468Snon
257379697Snon	if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
257467468Snon	{
257579697Snon		*bp = cb->bp;
257679697Snon		return 0;
257767468Snon	}
257867468Snon
257979697Snon	slp->sl_error |= (FATALIO | PDMAERR);
258079697Snon	slp->sl_scp.scp_datalen = 0;
258179697Snon	slp->sl_scp.scp_direction = direction;
258279697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
258379697Snon	if (ti->ti_ophase != ti->ti_phase)
258467468Snon	{
258579697Snon		char *s;
258679697Snon
258779697Snon		if (cb == NULL)
258879697Snon			s = "DATA PHASE: ccb nexus not found";
258979697Snon		else
259079697Snon			s = "DATA PHASE: xfer direction mismatch";
259179697Snon		SCSI_LOW_INFO(slp, ti, s);
259267468Snon	}
259367468Snon
259479697Snon	*bp = NULL;
259579697Snon	return EINVAL;
259667468Snon}
259767468Snon
259867468Snon/**************************************************************
259967468Snon * MSG_SYS
260067468Snon **************************************************************/
260167468Snon#define	MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
260267468Snon#define	MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
260367468Snon#define	MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
260479697Snon#define	MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
260567468Snon#define	MSGIN_DATA_LAST	0x30
260667468Snon
260792770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int);
260892770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int);
260992770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int);
261092770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int);
261167468Snon
261292770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *);
261392770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *);
261492770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *);
261592770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *);
261692770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *);
261792770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *);
261892770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *);
261967468Snon
262067468Snonstruct scsi_low_msgout_data {
262167468Snon	u_int	md_flags;
262267468Snon	u_int8_t md_msg;
262392770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
262492770Salfred	int (*md_errfunc)(struct scsi_low_softc *, u_int);
262579697Snon#define	MSG_RELEASE_ATN	0x0001
262679697Snon	u_int md_condition;
262767468Snon};
262867468Snon
262967468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = {
263079697Snon/* 0 */	{SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
263179697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
263279697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
263379697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
263479697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
263579697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
263679697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
263779697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG,  MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
263879697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
263979697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG,  MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
264079697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL,  MSG_RELEASE_ATN},
264179697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
264279697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
264379697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
264479697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
264579697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0},
264667468Snon};
264767468Snon
264892770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *);
264992770Salfredstatic int scsi_low_synch(struct scsi_low_softc *);
265092770Salfredstatic int scsi_low_wide(struct scsi_low_softc *);
265192770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *);
265292770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *);
265392770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *);
265492770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *);
265592770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *);
265692770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *);
265792770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *);
265892770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *);
265992770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *);
266092770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *);
266192770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *);
266267468Snon
266367468Snonstruct scsi_low_msgin_data {
266467468Snon	u_int md_len;
266592770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
266667468Snon};
266767468Snon
266867468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = {
266967468Snon/* 0 */	{1,	scsi_low_msginfunc_cc},
267067468Snon/* 1 */ {2,	scsi_low_msginfunc_ext},
267167468Snon/* 2 */ {1,	scsi_low_msginfunc_sdp},
267279697Snon/* 3 */ {1,	scsi_low_msginfunc_rp},
267367468Snon/* 4 */ {1,	scsi_low_msginfunc_disc},
267467468Snon/* 5 */ {1,	scsi_low_msginfunc_rejop},
267567468Snon/* 6 */ {1,	scsi_low_msginfunc_rejop},
267667468Snon/* 7 */ {1,	scsi_low_msginfunc_msg_reject},
267767468Snon/* 8 */ {1,	scsi_low_msginfunc_noop},
267867468Snon/* 9 */ {1,	scsi_low_msginfunc_parity},
267979697Snon/* a */ {1,	scsi_low_msginfunc_lcc},
268079697Snon/* b */ {1,	scsi_low_msginfunc_lcc},
268167468Snon/* c */ {1,	scsi_low_msginfunc_rejop},
268267468Snon/* d */ {2,	scsi_low_msginfunc_rejop},
268367468Snon/* e */ {1,	scsi_low_msginfunc_rejop},
268467468Snon/* f */ {1,	scsi_low_msginfunc_rejop},
268567468Snon/* 0x10 */ {1,	scsi_low_msginfunc_rejop},
268667468Snon/* 0x11 */ {1,	scsi_low_msginfunc_rejop},
268767468Snon/* 0x12 */ {1,	scsi_low_msginfunc_rejop},
268867468Snon/* 0x13 */ {1,	scsi_low_msginfunc_rejop},
268967468Snon/* 0x14 */ {1,	scsi_low_msginfunc_rejop},
269067468Snon/* 0x15 */ {1,	scsi_low_msginfunc_rejop},
269167468Snon/* 0x16 */ {1,	scsi_low_msginfunc_rejop},
269267468Snon/* 0x17 */ {1,	scsi_low_msginfunc_rejop},
269367468Snon/* 0x18 */ {1,	scsi_low_msginfunc_rejop},
269467468Snon/* 0x19 */ {1,	scsi_low_msginfunc_rejop},
269567468Snon/* 0x1a */ {1,	scsi_low_msginfunc_rejop},
269667468Snon/* 0x1b */ {1,	scsi_low_msginfunc_rejop},
269767468Snon/* 0x1c */ {1,	scsi_low_msginfunc_rejop},
269867468Snon/* 0x1d */ {1,	scsi_low_msginfunc_rejop},
269967468Snon/* 0x1e */ {1,	scsi_low_msginfunc_rejop},
270067468Snon/* 0x1f */ {1,	scsi_low_msginfunc_rejop},
270179697Snon/* 0x20 */ {2,	scsi_low_msginfunc_simple_qtag},
270267468Snon/* 0x21 */ {2,	scsi_low_msginfunc_rejop},
270367468Snon/* 0x22 */ {2,	scsi_low_msginfunc_rejop},
270479697Snon/* 0x23 */ {2,	scsi_low_msginfunc_i_wide_residue},
270567468Snon/* 0x24 */ {2,	scsi_low_msginfunc_rejop},
270667468Snon/* 0x25 */ {2,	scsi_low_msginfunc_rejop},
270767468Snon/* 0x26 */ {2,	scsi_low_msginfunc_rejop},
270867468Snon/* 0x27 */ {2,	scsi_low_msginfunc_rejop},
270967468Snon/* 0x28 */ {2,	scsi_low_msginfunc_rejop},
271067468Snon/* 0x29 */ {2,	scsi_low_msginfunc_rejop},
271167468Snon/* 0x2a */ {2,	scsi_low_msginfunc_rejop},
271267468Snon/* 0x2b */ {2,	scsi_low_msginfunc_rejop},
271367468Snon/* 0x2c */ {2,	scsi_low_msginfunc_rejop},
271467468Snon/* 0x2d */ {2,	scsi_low_msginfunc_rejop},
271567468Snon/* 0x2e */ {2,	scsi_low_msginfunc_rejop},
271667468Snon/* 0x2f */ {2,	scsi_low_msginfunc_rejop},
271767468Snon/* 0x30 */ {1,	scsi_low_msginfunc_rejop}	/* default rej op */
271867468Snon};
271967468Snon
272067468Snon/**************************************************************
272167468Snon * msgout
272267468Snon **************************************************************/
272367468Snonstatic int
272479697Snonscsi_low_msgfunc_synch(slp)
272579697Snon	struct scsi_low_softc *slp;
272667468Snon{
272779697Snon	struct targ_info *ti = slp->sl_Tnexus;
272867468Snon	int ptr = ti->ti_msgoutlen;
272967468Snon
273067468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
273167468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
273273025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
273373025Snon	ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset;
273467468Snon	return MSG_EXTEND_SYNCHLEN + 2;
273567468Snon}
273667468Snon
273767468Snonstatic int
273879697Snonscsi_low_msgfunc_wide(slp)
273979697Snon	struct scsi_low_softc *slp;
274067468Snon{
274179697Snon	struct targ_info *ti = slp->sl_Tnexus;
274267468Snon	int ptr = ti->ti_msgoutlen;
274367468Snon
274467468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
274567468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
274673025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
274767468Snon	return MSG_EXTEND_WIDELEN + 2;
274867468Snon}
274967468Snon
275067468Snonstatic int
275179697Snonscsi_low_msgfunc_identify(slp)
275279697Snon	struct scsi_low_softc *slp;
275367468Snon{
275479697Snon	struct targ_info *ti = slp->sl_Tnexus;
275579697Snon	struct lun_info *li = slp->sl_Lnexus;
275679697Snon	struct slccb *cb = slp->sl_Qnexus;
275779697Snon	int ptr = ti->ti_msgoutlen;
275879697Snon	u_int8_t msg;
275967468Snon
276079697Snon	msg = MSG_IDENTIFY;
276179697Snon	if (cb == NULL)
276267468Snon	{
276379697Snon		slp->sl_error |= FATALIO;
276479697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
276579697Snon		SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
276667468Snon	}
276767468Snon	else
276867468Snon	{
276979697Snon		if (scsi_low_is_disconnect_ok(cb) != 0)
277079697Snon			msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
277179697Snon		else
277279697Snon			msg |= li->li_lun;
277379697Snon
277479697Snon		if (ti->ti_phase == PH_MSGOUT)
277579697Snon		{
277679697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
277779697Snon			if (cb->ccb_tag == SCSI_LOW_UNKTAG)
277879697Snon			{
277979697Snon				(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
278079697Snon			}
278179697Snon		}
278267468Snon	}
278379697Snon	ti->ti_msgoutstr[ptr + 0] = msg;
278467468Snon	return 1;
278567468Snon}
278667468Snon
278767468Snonstatic int
278879697Snonscsi_low_msgfunc_abort(slp)
278979697Snon	struct scsi_low_softc *slp;
279067468Snon{
279167468Snon
279279697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
279379697Snon	return 1;
279479697Snon}
279579697Snon
279679697Snonstatic int
279779697Snonscsi_low_msgfunc_qabort(slp)
279879697Snon	struct scsi_low_softc *slp;
279979697Snon{
280079697Snon
280179697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
280279697Snon	return 1;
280379697Snon}
280479697Snon
280579697Snonstatic int
280679697Snonscsi_low_msgfunc_reset(slp)
280779697Snon	struct scsi_low_softc *slp;
280879697Snon{
280979697Snon
281079697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
281179697Snon	return 1;
281279697Snon}
281379697Snon
281479697Snonstatic int
281579697Snonscsi_low_msgfunc_qtag(slp)
281679697Snon	struct scsi_low_softc *slp;
281779697Snon{
281879697Snon	struct targ_info *ti = slp->sl_Tnexus;
281979697Snon	struct slccb *cb = slp->sl_Qnexus;
282079697Snon	int ptr = ti->ti_msgoutlen;
282179697Snon
282279697Snon	if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
282367468Snon	{
282467468Snon		ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
282567468Snon		return 1;
282667468Snon	}
282767468Snon	else
282867468Snon	{
282979697Snon		ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
283079697Snon		if (ti->ti_phase == PH_MSGOUT)
283179697Snon		{
283279697Snon			(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
283379697Snon		}
283467468Snon	}
283579697Snon	return 2;
283667468Snon}
283767468Snon
283867468Snon/*
283967468Snon * The following functions are called when targets give unexpected
284067468Snon * responces in msgin (after msgout).
284167468Snon */
284267468Snonstatic int
284379697Snonscsi_low_errfunc_identify(slp, msgflags)
284479697Snon	struct scsi_low_softc *slp;
284567468Snon	u_int msgflags;
284667468Snon{
284767468Snon
284879697Snon	if (slp->sl_Lnexus != NULL)
284979697Snon	{
285079697Snon	        slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
285179697Snon		scsi_low_calcf_lun(slp->sl_Lnexus);
285279697Snon	}
285367468Snon	return 0;
285467468Snon}
285567468Snon
285667468Snonstatic int
285779697Snonscsi_low_errfunc_synch(slp, msgflags)
285879697Snon	struct scsi_low_softc *slp;
285967468Snon	u_int msgflags;
286067468Snon{
286179697Snon	struct targ_info *ti = slp->sl_Tnexus;
286267468Snon
286367468Snon	MSGIN_PERIOD(ti) = 0;
286467468Snon	MSGIN_OFFSET(ti) = 0;
286579697Snon	scsi_low_synch(slp);
286667468Snon	return 0;
286767468Snon}
286867468Snon
286967468Snonstatic int
287079697Snonscsi_low_errfunc_wide(slp, msgflags)
287179697Snon	struct scsi_low_softc *slp;
287267468Snon	u_int msgflags;
287367468Snon{
287479697Snon	struct targ_info *ti = slp->sl_Tnexus;
287579697Snon
287679697Snon	MSGIN_WIDTHP(ti) = 0;
287779697Snon	scsi_low_wide(slp);
287867468Snon	return 0;
287967468Snon}
288067468Snon
288179697Snonstatic int
288279697Snonscsi_low_errfunc_qtag(slp, msgflags)
288379697Snon	struct scsi_low_softc *slp;
288479697Snon	u_int msgflags;
288579697Snon{
288679697Snon
288779697Snon	if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
288879697Snon	{
288979697Snon		if (slp->sl_Qnexus != NULL)
289079697Snon		{
289179697Snon			scsi_low_deactivate_qtag(slp->sl_Qnexus);
289279697Snon		}
289379697Snon		if (slp->sl_Lnexus != NULL)
289479697Snon		{
289579697Snon			slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
289679697Snon			scsi_low_calcf_lun(slp->sl_Lnexus);
289779697Snon		}
2898240325Sjhb		device_printf(slp->sl_dev, "scsi_low: qtag msg rejected\n");
289979697Snon	}
290079697Snon	return 0;
290179697Snon}
290279697Snon
290379697Snon
290467468Snonint
290579697Snonscsi_low_msgout(slp, ti, fl)
290667468Snon	struct scsi_low_softc *slp;
290767468Snon	struct targ_info *ti;
290879697Snon	u_int fl;
290967468Snon{
291067468Snon	struct scsi_low_msgout_data *mdp;
291167468Snon	int len = 0;
291267468Snon
291379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
291479697Snon	if (ti != slp->sl_Tnexus)
291579697Snon	{
291679697Snon		scsi_low_print(slp, NULL);
291779697Snon		panic("scsi_low_msgout: Target nexus inconsistent");
291879697Snon	}
291979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
292079697Snon
292179697Snon	slp->sl_ph_count ++;
292279697Snon	if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
292379697Snon	{
2924240325Sjhb		device_printf(slp->sl_dev, "too many phase changes\n");
292579697Snon		slp->sl_error |= FATALIO;
292679697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
292779697Snon	}
292879697Snon
292967468Snon	/* STEP I.
293067468Snon	 * Scsi phase changes.
293167468Snon	 * Previously msgs asserted are accepted by our target or
293267468Snon	 * processed by scsi_low_msgin.
293367468Snon	 * Thus clear all saved informations.
293467468Snon	 */
293579697Snon	if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
293667468Snon	{
293767468Snon		ti->ti_omsgflags = 0;
293867468Snon		ti->ti_emsgflags = 0;
293967468Snon	}
294079697Snon	else if (slp->sl_atten == 0)
294179697Snon	{
294267468Snon	/* STEP II.
294367468Snon	 * We did not assert attention, however still our target required
294467468Snon	 * msgs. Resend previous msgs.
294567468Snon	 */
294667468Snon		ti->ti_msgflags |= ti->ti_omsgflags;
294779697Snon		ti->ti_omsgflags = 0;
294867468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
2949240325Sjhb		device_printf(slp->sl_dev, "scsi_low_msgout: retry msgout\n");
295067468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
295167468Snon	}
295267468Snon
295367468Snon	/* STEP III.
295479697Snon	 * We have no msgs. send MSG_NOOP (OK?)
295567468Snon	 */
295679697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
295767468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
295867468Snon
295967468Snon	/* STEP IV.
296067468Snon	 * Process all msgs
296167468Snon	 */
296267468Snon	ti->ti_msgoutlen = 0;
296379697Snon	slp->sl_clear_atten = 0;
296467468Snon	mdp = &scsi_low_msgout_data[0];
296567468Snon	for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
296667468Snon	{
296767468Snon		if ((ti->ti_msgflags & mdp->md_flags) != 0)
296867468Snon		{
296967468Snon			ti->ti_omsgflags |= mdp->md_flags;
297067468Snon			ti->ti_msgflags &= ~mdp->md_flags;
297167468Snon			ti->ti_emsgflags = mdp->md_flags;
297267468Snon
297367468Snon			ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
297467468Snon			if (mdp->md_msgfunc != NULL)
297579697Snon				len = (*mdp->md_msgfunc) (slp);
297667468Snon			else
297767468Snon				len = 1;
297867468Snon
297979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
298079697Snon			scsi_low_msg_log_write(&ti->ti_log_msgout,
298179697Snon			       &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
298279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
298379697Snon
298467468Snon			ti->ti_msgoutlen += len;
298579697Snon			if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
298679697Snon			{
298779697Snon				slp->sl_clear_atten = 1;
298879697Snon				break;
298979697Snon			}
299079697Snon
299179697Snon			if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
299267468Snon			    ti->ti_msgflags == 0)
299367468Snon				break;
299479697Snon
299567468Snon			if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
299667468Snon				break;
299767468Snon		}
299867468Snon	}
299967468Snon
300079697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
300179697Snon		slp->sl_clear_atten = 1;
300267468Snon
300367468Snon	return ti->ti_msgoutlen;
300467468Snon}
300567468Snon
300667468Snon/**************************************************************
300767468Snon * msgin
300867468Snon **************************************************************/
300967468Snonstatic int
301079697Snonscsi_low_msginfunc_noop(slp)
301179697Snon	struct scsi_low_softc *slp;
301267468Snon{
301367468Snon
301467468Snon	return 0;
301567468Snon}
301667468Snon
301767468Snonstatic int
301879697Snonscsi_low_msginfunc_rejop(slp)
301979697Snon	struct scsi_low_softc *slp;
302067468Snon{
302179697Snon	struct targ_info *ti = slp->sl_Tnexus;
302267468Snon	u_int8_t msg = ti->ti_msgin[0];
302367468Snon
3024240325Sjhb	device_printf(slp->sl_dev, "MSGIN: msg 0x%x rejected\n", (u_int) msg);
302567468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
302667468Snon	return 0;
302767468Snon}
302867468Snon
302967468Snonstatic int
303079697Snonscsi_low_msginfunc_cc(slp)
303179697Snon	struct scsi_low_softc *slp;
303267468Snon{
303379697Snon	struct lun_info *li;
303467468Snon
303567468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
303679697Snon
303779697Snon	/* validate status */
303879697Snon	if (slp->sl_Qnexus == NULL)
303979697Snon		return ENOENT;
304079697Snon
304179697Snon	slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
304279697Snon 	li = slp->sl_Lnexus;
304379697Snon	switch (slp->sl_scp.scp_status)
304479697Snon	{
304579697Snon	case ST_GOOD:
304679697Snon		li->li_maxnqio = li->li_maxnexus;
304779697Snon		break;
304879697Snon
304979697Snon	case ST_CHKCOND:
305079697Snon		li->li_maxnqio = 0;
305179697Snon		if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
305279697Snon			scsi_low_reset_nexus_lun(slp, li, 0);
305379697Snon		break;
305479697Snon
305579697Snon	case ST_BUSY:
305679697Snon		li->li_maxnqio = 0;
305779697Snon		break;
305879697Snon
305979697Snon	case ST_QUEFULL:
306079697Snon		if (li->li_maxnexus >= li->li_nqio)
306179697Snon			li->li_maxnexus = li->li_nqio - 1;
306279697Snon		li->li_maxnqio = li->li_maxnexus;
306379697Snon		break;
306479697Snon
306579697Snon	case ST_INTERGOOD:
306679697Snon	case ST_INTERMET:
306779697Snon		slp->sl_error |= MSGERR;
306879697Snon		break;
306979697Snon
307079697Snon	default:
307179697Snon		break;
307279697Snon	}
307367468Snon	return 0;
307467468Snon}
307567468Snon
307667468Snonstatic int
307779697Snonscsi_low_msginfunc_lcc(slp)
307879697Snon	struct scsi_low_softc *slp;
307979697Snon{
308067468Snon	struct targ_info *ti;
308179697Snon	struct lun_info *li;
308279697Snon	struct slccb *ncb, *cb;
308379697Snon
308479697Snon	ti = slp->sl_Tnexus;
308579697Snon 	li = slp->sl_Lnexus;
308679697Snon	if ((cb = slp->sl_Qnexus) == NULL)
308779697Snon		goto bad;
308879697Snon
308979697Snon	cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
309079697Snon	switch (slp->sl_scp.scp_status)
309179697Snon	{
309279697Snon	case ST_INTERGOOD:
309379697Snon	case ST_INTERMET:
309479697Snon		li->li_maxnqio = li->li_maxnexus;
309579697Snon		break;
309679697Snon
309779697Snon	default:
309879697Snon		slp->sl_error |= MSGERR;
309979697Snon		break;
310079697Snon	}
310179697Snon
310279697Snon	if ((li->li_flags & SCSI_LOW_LINK) == 0)
310379697Snon		goto bad;
310479697Snon
310579697Snon	cb->ccb_error |= slp->sl_error;
310679697Snon	if (cb->ccb_error != 0)
310779697Snon		goto bad;
310879697Snon
310979697Snon	for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
311079697Snon	     ncb = TAILQ_NEXT(ncb, ccb_chain))
311179697Snon	{
311279697Snon		if (ncb->li == li)
311379697Snon			goto cmd_link_start;
311479697Snon	}
311579697Snon
311679697Snon
311779697Snonbad:
311879697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
311979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
312079697Snon	return EIO;
312179697Snon
312279697Snoncmd_link_start:
312379697Snon	ncb->ccb_flags &= ~CCB_STARTQ;
312479697Snon	TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
312579697Snon
312679697Snon	scsi_low_dealloc_qtag(ncb);
312779697Snon	ncb->ccb_tag = cb->ccb_tag;
312879697Snon	ncb->ccb_otag = cb->ccb_otag;
312979697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
313079697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
313179697Snon	if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
3132240325Sjhb		panic("%s: linked ccb retried",
3133240325Sjhb		    device_get_nameunit(slp->sl_dev));
313479697Snon
313579697Snon	slp->sl_Qnexus = ncb;
313679697Snon	slp->sl_ph_count = 0;
313779697Snon
313879697Snon	ncb->ccb_error = 0;
313979697Snon	ncb->ccb_datalen = -1;
314079697Snon	ncb->ccb_scp.scp_status = ST_UNKNOWN;
314179697Snon	ncb->ccb_flags &= ~CCB_INTERNAL;
314279697Snon
314379697Snon	scsi_low_init_msgsys(slp, ti);
314479697Snon
314579697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb);
314679697Snon
314779697Snon	if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
314879697Snon		ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
314979697Snon	ncb->ccb_tc = ncb->ccb_tcmax;
315079697Snon
315179697Snon	/* setup saved scsi data pointer */
315279697Snon	ncb->ccb_sscp = ncb->ccb_scp;
315379697Snon	slp->sl_scp = ncb->ccb_sscp;
315479697Snon	slp->sl_error = ncb->ccb_error;
315579697Snon
315679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
315779697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
315879697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
315979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
316079697Snon	return EJUSTRETURN;
316179697Snon}
316279697Snon
316379697Snonstatic int
316479697Snonscsi_low_msginfunc_disc(slp)
316579697Snon	struct scsi_low_softc *slp;
316667468Snon{
316767468Snon
316867468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
316967468Snon	return 0;
317067468Snon}
317167468Snon
317267468Snonstatic int
317379697Snonscsi_low_msginfunc_sdp(slp)
317479697Snon	struct scsi_low_softc *slp;
317567468Snon{
317679697Snon	struct slccb *cb = slp->sl_Qnexus;
317767468Snon
317879697Snon	if (cb != NULL)
317979697Snon	{
318079697Snon		cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
318179697Snon		cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
318279697Snon	}
318367468Snon	else
318479697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
318567468Snon	return 0;
318667468Snon}
318767468Snon
318867468Snonstatic int
318979697Snonscsi_low_msginfunc_rp(slp)
319079697Snon	struct scsi_low_softc *slp;
319167468Snon{
319267468Snon
319379697Snon	if (slp->sl_Qnexus != NULL)
319479697Snon		slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
319567468Snon	else
319679697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
319767468Snon	return 0;
319867468Snon}
319967468Snon
320067468Snonstatic int
320179697Snonscsi_low_synch(slp)
320279697Snon	struct scsi_low_softc *slp;
320367468Snon{
320479697Snon	struct targ_info *ti = slp->sl_Tnexus;
320579697Snon	u_int period = 0, offset = 0, speed;
320667468Snon	u_char *s;
320767468Snon	int error;
320867468Snon
320979697Snon	if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
321079697Snon	     MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
321179697Snon	     MSGIN_OFFSET(ti) == 0)
321267468Snon	{
321367468Snon		if ((offset = MSGIN_OFFSET(ti)) != 0)
321467468Snon			period = MSGIN_PERIOD(ti);
321567468Snon		s = offset ? "synchronous" : "async";
321667468Snon	}
321767468Snon	else
321867468Snon	{
321967468Snon		/* XXX:
322067468Snon		 * Target seems to be brain damaged.
322167468Snon		 * Force async transfer.
322267468Snon		 */
322373025Snon		ti->ti_maxsynch.period = 0;
322473025Snon		ti->ti_maxsynch.offset = 0;
3225240325Sjhb		device_printf(slp->sl_dev,
3226240325Sjhb		    "target brain damaged. async transfer\n");
322767468Snon		return EINVAL;
322867468Snon	}
322967468Snon
323073025Snon	ti->ti_maxsynch.period = period;
323173025Snon	ti->ti_maxsynch.offset = offset;
323267468Snon
323367468Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH);
323467468Snon	if (error != 0)
323567468Snon	{
323667468Snon		/* XXX:
323767468Snon		 * Current period and offset are not acceptable
323867468Snon		 * for our adapter.
323967468Snon		 * The adapter changes max synch and max offset.
324067468Snon		 */
3241240325Sjhb		device_printf(slp->sl_dev,
3242240325Sjhb		    "synch neg failed. retry synch msg neg ...\n");
324367468Snon		return error;
324467468Snon	}
324567468Snon
324679697Snon	ti->ti_osynch = ti->ti_maxsynch;
324779697Snon	if (offset > 0)
324879697Snon	{
324979697Snon		ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
325079697Snon	}
325179697Snon
325267468Snon	/* inform data */
325379697Snon	if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
325467468Snon	{
325579697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
325679697Snon		struct slccb *cb = slp->sl_Qnexus;
325779697Snon
325879697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
325979697Snon			return 0;
326079697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
326179697Snon
3262240325Sjhb		device_printf(slp->sl_dev,
3263240325Sjhb		    "(%d:*): <%s> offset %d period %dns ",
3264240325Sjhb		    ti->ti_id, s, offset, period * 4);
326579697Snon
326679697Snon		if (period != 0)
326779697Snon		{
326879697Snon			speed = 1000 * 10 / (period * 4);
326979697Snon			printf("%d.%d M/s", speed / 10, speed % 10);
327079697Snon		}
327179697Snon		printf("\n");
327267468Snon	}
327379697Snon	return 0;
327479697Snon}
327567468Snon
327679697Snonstatic int
327779697Snonscsi_low_wide(slp)
327879697Snon	struct scsi_low_softc *slp;
327979697Snon{
328079697Snon	struct targ_info *ti = slp->sl_Tnexus;
328179697Snon	int error;
328279697Snon
328379697Snon	ti->ti_width = MSGIN_WIDTHP(ti);
328479697Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
328579697Snon	if (error != 0)
328679697Snon	{
328779697Snon		/* XXX:
328879697Snon		 * Current width is not acceptable for our adapter.
328979697Snon		 * The adapter changes max width.
329079697Snon		 */
3291240325Sjhb		device_printf(slp->sl_dev,
3292240325Sjhb		    "wide neg failed. retry wide msg neg ...\n");
329379697Snon		return error;
329479697Snon	}
329579697Snon
329679697Snon	ti->ti_owidth = ti->ti_width;
329779697Snon	if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
329879697Snon	{
329979697Snon		ti->ti_setup_msg_done |=
330079697Snon			(SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
330179697Snon	}
330279697Snon
330379697Snon	/* inform data */
330479697Snon	if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
330579697Snon	{
330679697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
330779697Snon		struct slccb *cb = slp->sl_Qnexus;
330879697Snon
330979697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
331079697Snon			return 0;
331179697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
331279697Snon
3313240325Sjhb		device_printf(slp->sl_dev, "(%d:*): transfer width %d bits\n",
3314240325Sjhb		    ti->ti_id, 1 << (3 + ti->ti_width));
331579697Snon	}
331667468Snon	return 0;
331767468Snon}
331867468Snon
331967468Snonstatic int
332079697Snonscsi_low_msginfunc_simple_qtag(slp)
332179697Snon	struct scsi_low_softc *slp;
332267468Snon{
332379697Snon	struct targ_info *ti = slp->sl_Tnexus;
332479697Snon	scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
332579697Snon
332679697Snon	if (slp->sl_Qnexus != NULL)
332779697Snon	{
332879697Snon		if (slp->sl_Qnexus->ccb_tag != etag)
332979697Snon		{
333079697Snon			slp->sl_error |= FATALIO;
333179697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
333279697Snon			SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
333379697Snon		}
333479697Snon	}
333579697Snon	else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
333679697Snon	{
333779697Snon#ifdef	SCSI_LOW_DEBUG
333879697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
333979697Snon			return 0;
334079697Snon#endif	/* SCSI_LOW_DEBUG */
334179697Snon
334279697Snon		slp->sl_error |= FATALIO;
334379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
334479697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
334579697Snon	}
334679697Snon	return 0;
334779697Snon}
334879697Snon
334979697Snonstatic int
335079697Snonscsi_low_msginfunc_i_wide_residue(slp)
335179697Snon	struct scsi_low_softc *slp;
335279697Snon{
335379697Snon	struct targ_info *ti = slp->sl_Tnexus;
335479697Snon	struct slccb *cb = slp->sl_Qnexus;
335579697Snon	int res = (int) ti->ti_msgin[1];
335679697Snon
335779697Snon	if (cb == NULL || res <= 0 ||
335879697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
335979697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
336079697Snon		return EINVAL;
336179697Snon
336279697Snon	if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
336379697Snon		return EINVAL;
336479697Snon
336579697Snon	slp->sl_scp.scp_datalen += res;
336679697Snon	slp->sl_scp.scp_data -= res;
336779697Snon	scsi_low_data_finish(slp);
336879697Snon	return 0;
336979697Snon}
337079697Snon
337179697Snonstatic int
337279697Snonscsi_low_msginfunc_ext(slp)
337379697Snon	struct scsi_low_softc *slp;
337479697Snon{
337579697Snon	struct slccb *cb = slp->sl_Qnexus;
337679697Snon	struct lun_info *li = slp->sl_Lnexus;
337779697Snon	struct targ_info *ti = slp->sl_Tnexus;
337867468Snon	int count, retry;
337967468Snon	u_int32_t *ptr;
338067468Snon
338167468Snon	if (ti->ti_msginptr == 2)
338267468Snon	{
338367468Snon		ti->ti_msginlen = ti->ti_msgin[1] + 2;
338467468Snon		return 0;
338567468Snon	}
338667468Snon
338767468Snon	switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
338867468Snon	{
338967468Snon	case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
339067468Snon		if (cb == NULL)
339167468Snon			break;
339267468Snon
339367468Snon		ptr = (u_int32_t *)(&ti->ti_msgin[3]);
339467468Snon		count = (int) htonl((long) (*ptr));
339567468Snon		if(slp->sl_scp.scp_datalen - count < 0 ||
339667468Snon		   slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen)
339767468Snon			break;
339867468Snon
339967468Snon		slp->sl_scp.scp_datalen -= count;
340067468Snon		slp->sl_scp.scp_data += count;
340167468Snon		return 0;
340267468Snon
340367468Snon	case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
340467468Snon		if (li == NULL)
340567468Snon			break;
340667468Snon
340779697Snon		retry = scsi_low_synch(slp);
340867468Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
340967468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
341079697Snon
341179697Snon#ifdef	SCSI_LOW_DEBUG
341279697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
341379697Snon		{
341479697Snon			scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
341579697Snon		}
341679697Snon#endif	/* SCSI_LOW_DEBUG */
341767468Snon		return 0;
341867468Snon
341967468Snon	case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
342067468Snon		if (li == NULL)
342167468Snon			break;
342267468Snon
342379697Snon		retry = scsi_low_wide(slp);
342479697Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
342579697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
342679697Snon
342767468Snon		return 0;
342867468Snon
342967468Snon	default:
343067468Snon		break;
343167468Snon	}
343267468Snon
343367468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
343467468Snon	return EINVAL;
343567468Snon}
343667468Snon
343767468Snonstatic int
343879697Snonscsi_low_msginfunc_parity(slp)
343979697Snon	struct scsi_low_softc *slp;
344067468Snon{
344179697Snon	struct targ_info *ti = slp->sl_Tnexus;
344267468Snon
344379697Snon	/* only I -> T, invalid! */
344479697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
344567468Snon	return 0;
344667468Snon}
344767468Snon
344867468Snonstatic int
344979697Snonscsi_low_msginfunc_msg_reject(slp)
345079697Snon	struct scsi_low_softc *slp;
345167468Snon{
345279697Snon	struct targ_info *ti = slp->sl_Tnexus;
345367468Snon	struct scsi_low_msgout_data *mdp;
345467468Snon	u_int msgflags;
345567468Snon
345679697Snon	if (ti->ti_emsgflags != 0)
345767468Snon	{
3458240325Sjhb		device_printf(slp->sl_dev, "msg flags [0x%x] rejected\n",
3459240325Sjhb		    ti->ti_emsgflags);
346067468Snon		msgflags = SCSI_LOW_MSG_REJECT;
346167468Snon		mdp = &scsi_low_msgout_data[0];
346267468Snon		for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
346367468Snon		{
346467468Snon			if ((ti->ti_emsgflags & mdp->md_flags) != 0)
346567468Snon			{
346667468Snon				ti->ti_emsgflags &= ~mdp->md_flags;
346767468Snon				if (mdp->md_errfunc != NULL)
346879697Snon					(*mdp->md_errfunc) (slp, msgflags);
346967468Snon				break;
347067468Snon			}
347167468Snon		}
347279697Snon		return 0;
347367468Snon	}
347479697Snon	else
347579697Snon	{
347679697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
347779697Snon		slp->sl_error |= MSGERR;
347879697Snon	}
347979697Snon	return EINVAL;
348067468Snon}
348167468Snon
348279697Snonint
348367468Snonscsi_low_msgin(slp, ti, c)
348467468Snon	struct scsi_low_softc *slp;
348567468Snon	struct targ_info *ti;
348679697Snon	u_int c;
348767468Snon{
348867468Snon	struct scsi_low_msgin_data *sdp;
348967468Snon	struct lun_info *li;
349067468Snon	u_int8_t msg;
349167468Snon
349279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
349379697Snon	if (ti != slp->sl_Tnexus)
349479697Snon	{
349579697Snon		scsi_low_print(slp, NULL);
349679697Snon		panic("scsi_low_msgin: Target nexus inconsistent");
349779697Snon	}
349879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
349979697Snon
350067468Snon	/*
350167468Snon	 * Phase changes, clear the pointer.
350267468Snon	 */
350367468Snon	if (ti->ti_ophase != ti->ti_phase)
350467468Snon	{
350567468Snon		MSGINPTR_CLR(ti);
350679697Snon		ti->ti_msgin_parity_error = 0;
350779697Snon
350879697Snon		slp->sl_ph_count ++;
350979697Snon		if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
351079697Snon		{
3511240325Sjhb			device_printf(slp->sl_dev, "too many phase changes\n");
351279697Snon			slp->sl_error |= FATALIO;
351379697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
351479697Snon		}
351567468Snon	}
351667468Snon
351767468Snon	/*
351867468Snon	 * Store a current messages byte into buffer and
351967468Snon	 * wait for the completion of the current msg.
352067468Snon	 */
352179697Snon	ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
352267468Snon	if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
352367468Snon	{
352467468Snon		ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
352567468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
352667468Snon	}
352767468Snon
352867468Snon	/*
352979697Snon	 * Check parity errors.
353079697Snon	 */
353179697Snon	if ((c & SCSI_LOW_DATA_PE) != 0)
353279697Snon	{
353379697Snon		ti->ti_msgin_parity_error ++;
353479697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
353579697Snon		goto out;
353679697Snon	}
353779697Snon
353879697Snon	if (ti->ti_msgin_parity_error != 0)
353979697Snon		goto out;
354079697Snon
354179697Snon	/*
354267468Snon	 * Calculate messages length.
354367468Snon	 */
354467468Snon	msg = ti->ti_msgin[0];
354567468Snon	if (msg < MSGIN_DATA_LAST)
354667468Snon		sdp = &scsi_low_msgin_data[msg];
354767468Snon	else
354867468Snon		sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST];
354967468Snon
355067468Snon	if (ti->ti_msginlen == 0)
355167468Snon	{
355267468Snon		ti->ti_msginlen = sdp->md_len;
355367468Snon	}
355467468Snon
355567468Snon	/*
355667468Snon	 * Check comletion.
355767468Snon	 */
355867468Snon	if (ti->ti_msginptr < ti->ti_msginlen)
355979697Snon		return EJUSTRETURN;
356067468Snon
356167468Snon	/*
356267468Snon	 * Do process.
356367468Snon	 */
356467468Snon	if ((msg & MSG_IDENTIFY) == 0)
356567468Snon	{
356679697Snon		if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
356779697Snon			return EJUSTRETURN;
356867468Snon	}
356967468Snon	else
357067468Snon	{
357179697Snon		li = slp->sl_Lnexus;
357267468Snon		if (li == NULL)
357367468Snon		{
357479697Snon			li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
357567468Snon			if (li == NULL)
357667468Snon				goto badlun;
357779697Snon			slp->sl_Lnexus = li;
357879697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
357967468Snon		}
358079697Snon		else
358179697Snon		{
358279697Snon			if (MSGCMD_LUN(msg) != li->li_lun)
358379697Snon				goto badlun;
358479697Snon		}
358567468Snon
358679697Snon		if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
358767468Snon		{
358867468Snon			if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
358979697Snon			{
359079697Snon#ifdef	SCSI_LOW_DEBUG
359179697Snon				if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
359279697Snon				{
359379697Snon					goto out;
359479697Snon				}
359579697Snon#endif	/* SCSI_LOW_DEBUG */
359667468Snon				goto badlun;
359779697Snon			}
359867468Snon		}
359967468Snon	}
360079697Snon	goto out;
360167468Snon
360267468Snon	/*
360379697Snon	 * Msg process completed, reset msgin pointer and assert ATN if desired.
360467468Snon	 */
360579697Snonbadlun:
360679697Snon	slp->sl_error |= FATALIO;
360779697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
360879697Snon	SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
360979697Snon
361079697Snonout:
361179697Snon	if (ti->ti_msginptr < ti->ti_msginlen)
361279697Snon		return EJUSTRETURN;
361379697Snon
361479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
361579697Snon	scsi_low_msg_log_write(&ti->ti_log_msgin,
361679697Snon			       &ti->ti_msgin[0], ti->ti_msginlen);
361779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
361879697Snon
361979697Snon	MSGINPTR_CLR(ti);
362079697Snon	return 0;
362179697Snon}
362279697Snon
362379697Snon/**********************************************************
362479697Snon * disconnect
362579697Snon **********************************************************/
362679697Snonint
362779697Snonscsi_low_disconnected(slp, ti)
362879697Snon	struct scsi_low_softc *slp;
362979697Snon	struct targ_info *ti;
363079697Snon{
363179697Snon	struct slccb *cb = slp->sl_Qnexus;
363279697Snon
363379697Snon	/* check phase completion */
363479697Snon	switch (slp->sl_msgphase)
363567468Snon	{
363679697Snon	case MSGPH_RESET:
363779697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
363879697Snon		scsi_low_msginfunc_cc(slp);
363979697Snon		scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
364079697Snon		goto io_resume;
364167468Snon
364279697Snon	case MSGPH_ABORT:
364379697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
364479697Snon		scsi_low_msginfunc_cc(slp);
364579697Snon		scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
364679697Snon		goto io_resume;
364779697Snon
364879697Snon	case MSGPH_TERM:
364979697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
365079697Snon		scsi_low_msginfunc_cc(slp);
365179697Snon		goto io_resume;
365279697Snon
365379697Snon	case MSGPH_DISC:
365479697Snon		if (cb != NULL)
365567468Snon		{
365679697Snon			struct lun_info *li;
365779697Snon
365879697Snon			li = cb->li;
365979697Snon			TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
366079697Snon			cb->ccb_flags |= CCB_DISCQ;
366179697Snon			cb->ccb_error |= slp->sl_error;
366279697Snon			li->li_disc ++;
366379697Snon			ti->ti_disc ++;
366479697Snon			slp->sl_disc ++;
366579697Snon		}
366679697Snon
366779697Snon#ifdef	SCSI_LOW_STATICS
366879697Snon		scsi_low_statics.nexus_disconnected ++;
366979697Snon#endif	/* SCSI_LOW_STATICS */
367079697Snon
367179697Snon#ifdef	SCSI_LOW_DEBUG
367279697Snon		if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
367379697Snon		{
367479697Snon			printf("## SCSI_LOW_DISCONNECTED ===============\n");
367579697Snon			scsi_low_print(slp, NULL);
367679697Snon		}
367779697Snon#endif	/* SCSI_LOW_DEBUG */
367879697Snon		break;
367979697Snon
368079697Snon	case MSGPH_NULL:
368179697Snon		slp->sl_error |= FATALIO;
368279697Snon		if (ti->ti_phase == PH_SELSTART)
368379697Snon			slp->sl_error |= SELTIMEOUTIO;
368479697Snon		else
368579697Snon			slp->sl_error |= UBFERR;
368679697Snon		/* fall through */
368779697Snon
368879697Snon	case MSGPH_LCTERM:
368979697Snon	case MSGPH_CMDC:
369079697Snonio_resume:
369179697Snon		if (cb == NULL)
369279697Snon			break;
369379697Snon
369479697Snon#ifdef	SCSI_LOW_DEBUG
369579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
369679697Snon		{
369779697Snon			if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
369879697Snon			    (cb->ccb_msgoutflag != 0 ||
369979697Snon			     (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
370079697Snon			{
370179697Snon				scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
370279697Snon			}
370379697Snon		}
370479697Snon#endif	/* SCSI_LOW_DEBUG */
370579697Snon
370679697Snon		cb->ccb_error |= slp->sl_error;
370779697Snon		if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
370879697Snon		{
370979697Snon			cb->ccb_flags |= CCB_STARTQ;
371079697Snon			TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
371179697Snon		}
371279697Snon		break;
371379697Snon	}
371479697Snon
371579697Snon	scsi_low_bus_release(slp, ti);
371679697Snon	scsi_low_start(slp);
371779697Snon	return 1;
371879697Snon}
371979697Snon
372079697Snon/**********************************************************
372179697Snon * TAG operations
372279697Snon **********************************************************/
3723104094Sphkstatic int
372479697Snonscsi_low_alloc_qtag(cb)
372579697Snon	struct slccb *cb;
372679697Snon{
372779697Snon	struct lun_info *li = cb->li;
372879697Snon	scsi_low_tag_t etag;
372979697Snon
373079697Snon	if (cb->ccb_otag != SCSI_LOW_UNKTAG)
373179697Snon		return 0;
373279697Snon
373379697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
373479697Snon	etag = ffs(li->li_qtagbits);
373579697Snon	if (etag == 0)
373679697Snon		return ENOSPC;
373779697Snon
373879697Snon	li->li_qtagbits &= ~(1 << (etag - 1));
373979697Snon	cb->ccb_otag = etag;
374079697Snon	return 0;
374179697Snon
374279697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
374379697Snon	for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
374479697Snon		if (li->li_qtagarray[li->li_qd] == 0)
374579697Snon			goto found;
374679697Snon
374779697Snon	for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
374879697Snon		if (li->li_qtagarray[li->li_qd] == 0)
374979697Snon			goto found;
375079697Snon
375179697Snon	return ENOSPC;
375279697Snon
375379697Snonfound:
375479697Snon	li->li_qtagarray[li->li_qd] ++;
375579697Snon	cb->ccb_otag = (li->li_qd ++);
375679697Snon	return 0;
375779697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
375879697Snon}
375979697Snon
3760104094Sphkstatic int
376179697Snonscsi_low_dealloc_qtag(cb)
376279697Snon	struct slccb *cb;
376379697Snon{
376479697Snon	struct lun_info *li = cb->li;
376579697Snon	scsi_low_tag_t etag;
376679697Snon
376779697Snon	if (cb->ccb_otag == SCSI_LOW_UNKTAG)
376879697Snon		return 0;
376979697Snon
377079697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
377179697Snon	etag = cb->ccb_otag - 1;
377267468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
377379697Snon	if (etag >= sizeof(li->li_qtagbits) * NBBY)
377479697Snon		panic("scsi_low_dealloc_tag: illegal tag");
377567468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
377679697Snon	li->li_qtagbits |= (1 << etag);
377779697Snon
377879697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
377979697Snon	etag = cb->ccb_otag;
378079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
378179697Snon	if (etag >= SCSI_LOW_MAXNEXUS)
378279697Snon		panic("scsi_low_dealloc_tag: illegal tag");
378379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
378479697Snon	li->li_qtagarray[etag] --;
378579697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
378679697Snon
378779697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
378879697Snon	return 0;
378979697Snon}
379079697Snon
3791104094Sphkstatic struct slccb *
379279697Snonscsi_low_revoke_ccb(slp, cb, fdone)
379379697Snon	struct scsi_low_softc *slp;
379479697Snon	struct slccb *cb;
379579697Snon	int fdone;
379679697Snon{
379779697Snon	struct targ_info *ti = cb->ti;
379879697Snon	struct lun_info *li = cb->li;
379979697Snon
380079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
380179697Snon	if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
380279697Snon	    (CCB_STARTQ | CCB_DISCQ))
380379697Snon	{
3804240325Sjhb		panic("%s: ccb in both queue",
3805240325Sjhb		    device_get_nameunit(slp->sl_dev));
380667468Snon	}
380779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
380867468Snon
380979697Snon	if ((cb->ccb_flags & CCB_STARTQ) != 0)
381079697Snon	{
381179697Snon		TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
381279697Snon	}
381379697Snon
381479697Snon	if ((cb->ccb_flags & CCB_DISCQ) != 0)
381579697Snon	{
381679697Snon		TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
381779697Snon		li->li_disc --;
381879697Snon		ti->ti_disc --;
381979697Snon		slp->sl_disc --;
382079697Snon	}
382179697Snon
382279697Snon	cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
382379697Snon			   CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
382479697Snon
382579697Snon	if (fdone != 0 &&
382679697Snon	    (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
382779697Snon	     (cb->ccb_flags & CCB_NORETRY) != 0))
382879697Snon	{
382979697Snon		cb->ccb_error |= FATALIO;
383079697Snon		cb->ccb_flags &= ~CCB_AUTOSENSE;
383179697Snon		if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
3832240325Sjhb			panic("%s: done ccb retried",
3833240325Sjhb			    device_get_nameunit(slp->sl_dev));
383479697Snon		return NULL;
383579697Snon	}
383679697Snon	else
383779697Snon	{
383879697Snon		cb->ccb_error |= PENDINGIO;
383979697Snon		scsi_low_deactivate_qtag(cb);
384079697Snon		scsi_low_ccb_message_retry(cb);
384179697Snon		cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
384279697Snon		return cb;
384379697Snon	}
384467468Snon}
384567468Snon
3846104094Sphkstatic void
384779697Snonscsi_low_reset_nexus_lun(slp, li, fdone)
384879697Snon	struct scsi_low_softc *slp;
384979697Snon	struct lun_info *li;
385079697Snon	int fdone;
385179697Snon{
385279697Snon	struct slccb *cb, *ncb, *ecb;
385379697Snon
385479697Snon	if (li == NULL)
385579697Snon		return;
385679697Snon
385779697Snon	ecb = NULL;
385879697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
385979697Snon	{
386079697Snon		ncb = TAILQ_NEXT(cb, ccb_chain);
386179697Snon		cb = scsi_low_revoke_ccb(slp, cb, fdone);
386279697Snon		if (cb != NULL)
386379697Snon		{
386479697Snon			/*
386579697Snon			 * presumely keep ordering of io
386679697Snon			 */
386779697Snon			cb->ccb_flags |= CCB_STARTQ;
386879697Snon			if (ecb == NULL)
386979697Snon			{
387079697Snon				TAILQ_INSERT_HEAD(&slp->sl_start,\
387179697Snon						  cb, ccb_chain);
387279697Snon			}
387379697Snon			else
387479697Snon			{
387579697Snon				TAILQ_INSERT_AFTER(&slp->sl_start,\
387679697Snon						   ecb, cb, ccb_chain);
387779697Snon			}
387879697Snon			ecb = cb;
387979697Snon		}
388079697Snon	}
388179697Snon}
388279697Snon
388367468Snon/**************************************************************
388467468Snon * Qurik setup
388567468Snon **************************************************************/
388667468Snonstatic void
388779697Snonscsi_low_calcf_lun(li)
388867468Snon	struct lun_info *li;
388967468Snon{
389079697Snon	struct targ_info *ti = li->li_ti;
389167468Snon	struct scsi_low_softc *slp = ti->ti_sc;
389279697Snon	u_int cfgflags, diskflags;
389367468Snon
389479697Snon	if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
389579697Snon		cfgflags = li->li_cfgflags;
389679697Snon	else
389779697Snon		cfgflags = 0;
389879697Snon
389979697Snon	diskflags = li->li_diskflags & li->li_quirks;
390079697Snon
390179697Snon	/* disconnect */
390267468Snon	li->li_flags &= ~SCSI_LOW_DISC;
390367468Snon	if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
390479697Snon	    (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
390579697Snon	    (cfgflags & SCSI_LOW_DISC) != 0)
390667468Snon		li->li_flags |= SCSI_LOW_DISC;
390767468Snon
390879697Snon	/* parity */
390967468Snon	li->li_flags |= SCSI_LOW_NOPARITY;
391067468Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
391179697Snon	    (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
391279697Snon	    (cfgflags & SCSI_LOW_NOPARITY) == 0)
391367468Snon		li->li_flags &= ~SCSI_LOW_NOPARITY;
391467468Snon
391579697Snon	/* qtag */
391679697Snon	if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
391779697Snon	    (cfgflags & SCSI_LOW_QTAG) != 0 &&
391879697Snon	    (diskflags & SCSI_LOW_DISK_QTAG) != 0)
391979697Snon	{
392079697Snon		li->li_flags |= SCSI_LOW_QTAG;
392179697Snon		li->li_maxnexus = SCSI_LOW_MAXNEXUS;
392279697Snon		li->li_maxnqio = li->li_maxnexus;
392379697Snon	}
392479697Snon	else
392579697Snon	{
392679697Snon		li->li_flags &= ~SCSI_LOW_QTAG;
392779697Snon		li->li_maxnexus = 0;
392879697Snon		li->li_maxnqio = li->li_maxnexus;
392979697Snon	}
393079697Snon
393179697Snon	/* cmd link */
393279697Snon	li->li_flags &= ~SCSI_LOW_LINK;
393379697Snon	if ((cfgflags & SCSI_LOW_LINK) != 0 &&
393479697Snon	    (diskflags & SCSI_LOW_DISK_LINK) != 0)
393579697Snon		li->li_flags |= SCSI_LOW_LINK;
393679697Snon
393779697Snon	/* compatible flags */
393867468Snon	li->li_flags &= ~SCSI_LOW_SYNC;
393979697Snon	if (ti->ti_maxsynch.offset > 0)
394079697Snon		li->li_flags |= SCSI_LOW_SYNC;
394179697Snon
394279697Snon#ifdef	SCSI_LOW_DEBUG
394379697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
394467468Snon	{
394579697Snon		scsi_low_calcf_show(li);
394667468Snon	}
394779697Snon#endif	/* SCSI_LOW_DEBUG */
394879697Snon}
394979697Snon
395079697Snonstatic void
395179697Snonscsi_low_calcf_target(ti)
395279697Snon	struct targ_info *ti;
395379697Snon{
395479697Snon	struct scsi_low_softc *slp = ti->ti_sc;
395579697Snon	u_int offset, period, diskflags;
395679697Snon
395779697Snon	diskflags = ti->ti_diskflags & ti->ti_quirks;
395879697Snon
395979697Snon	/* synch */
396079697Snon	if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
396179697Snon	    (diskflags & SCSI_LOW_DISK_SYNC) != 0)
396279697Snon	{
396379697Snon		offset = ti->ti_maxsynch.offset;
396479697Snon		period = ti->ti_maxsynch.period;
396579697Snon		if (offset == 0 || period == 0)
396679697Snon			offset = period = 0;
396779697Snon	}
396867468Snon	else
396979697Snon	{
397079697Snon		offset = period = 0;
397179697Snon	}
397267468Snon
397379697Snon	ti->ti_maxsynch.offset = offset;
397479697Snon	ti->ti_maxsynch.period = period;
397579697Snon
397679697Snon	/* wide */
397779697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
397879697Snon	     ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
397979697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
398079697Snon
398179697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
398279697Snon	    ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
398379697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
398479697Snon
398579697Snon	if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
398667468Snon	{
398779697Snon		if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
398879697Snon		    ti->ti_maxsynch.period != ti->ti_osynch.period)
398979697Snon			ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
399079697Snon		if (ti->ti_width != ti->ti_owidth)
399179697Snon			ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
399279697Snon
399379697Snon		ti->ti_osynch = ti->ti_maxsynch;
399479697Snon		ti->ti_owidth = ti->ti_width;
399567468Snon	}
399667468Snon
399779697Snon#ifdef	SCSI_LOW_DEBUG
399879697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
399979697Snon	{
4000240325Sjhb		device_printf(slp->sl_dev,
4001240325Sjhb			"(%d:*): max period(%dns) offset(%d) width(%d)\n",
4002240325Sjhb			ti->ti_id,
400379697Snon			ti->ti_maxsynch.period * 4,
400479697Snon			ti->ti_maxsynch.offset,
400579697Snon			ti->ti_width);
400679697Snon	}
400779697Snon#endif	/* SCSI_LOW_DEBUG */
400867468Snon}
400967468Snon
401079697Snonstatic void
401179697Snonscsi_low_calcf_show(li)
401279697Snon	struct lun_info *li;
401379697Snon{
401479697Snon	struct targ_info *ti = li->li_ti;
401579697Snon	struct scsi_low_softc *slp = ti->ti_sc;
401679697Snon
4017240325Sjhb	device_printf(slp->sl_dev,
4018240325Sjhb		"(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
4019240325Sjhb		ti->ti_id, li->li_lun,
402079697Snon		ti->ti_maxsynch.period * 4,
402179697Snon		ti->ti_maxsynch.offset,
402279697Snon		ti->ti_width,
402379697Snon		li->li_flags, SCSI_LOW_BITS);
402479697Snon}
402579697Snon
402679697Snon#ifdef	SCSI_LOW_START_UP_CHECK
402779697Snon/**************************************************************
402879697Snon * scsi world start up
402979697Snon **************************************************************/
403092770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *);
403179697Snon
403267468Snonstatic int
403379697Snonscsi_low_start_up(slp)
403479697Snon	struct scsi_low_softc *slp;
403567468Snon{
403667468Snon	struct targ_info *ti;
403767468Snon	struct lun_info *li;
403879697Snon	struct slccb *cb;
403979697Snon	int target, lun;
404067468Snon
4041240325Sjhb	device_printf(slp->sl_dev, "scsi_low: probing all devices ....\n");
404267468Snon
404379697Snon	for (target = 0; target < slp->sl_ntargs; target ++)
404479697Snon	{
404579697Snon		if (target == slp->sl_hostid)
404679697Snon		{
404779697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
404879697Snon			{
4049240325Sjhb				device_printf(slp->sl_dev,
4050240325Sjhb				    "scsi_low: target %d (host card)\n",
4051240325Sjhb				    target);
405279697Snon			}
405379697Snon			continue;
405479697Snon		}
405567468Snon
405679697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
405779697Snon		{
4058240325Sjhb			device_printf(slp->sl_dev, "scsi_low: target %d lun ",
4059240325Sjhb			    target);
406079697Snon		}
406167468Snon
406279697Snon		ti = slp->sl_ti[target];
406379697Snon		for (lun = 0; lun < slp->sl_nluns; lun ++)
406479697Snon		{
406579697Snon			if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
406679697Snon				break;
406779697Snon
406879697Snon			cb->osdep = NULL;
406979697Snon			cb->bp = NULL;
407079697Snon
407179697Snon			li = scsi_low_alloc_li(ti, lun, 1);
407279697Snon
407379697Snon			scsi_low_enqueue(slp, ti, li, cb,
407479697Snon					 CCB_AUTOSENSE | CCB_POLLED, 0);
407579697Snon
407679697Snon			scsi_low_poll(slp, cb);
407779697Snon
407879697Snon			if (li->li_state != SCSI_LOW_LUN_OK)
407979697Snon				break;
408079697Snon
408179697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
408279697Snon			{
408379697Snon				printf("%d ", lun);
408479697Snon			}
408579697Snon		}
408679697Snon
408779697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
408879697Snon		{
408979697Snon			printf("\n");
409079697Snon		}
409179697Snon	}
409267468Snon	return 0;
409367468Snon}
409467468Snon
409579697Snonstatic int
409679697Snonscsi_low_poll(slp, cb)
409779697Snon	struct scsi_low_softc *slp;
409879697Snon	struct slccb *cb;
409979697Snon{
410079697Snon	int tcount;
410179697Snon
410279697Snon	tcount = 0;
410379697Snon	while (slp->sl_nio > 0)
410479697Snon	{
4105240172Sjhb		DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
410679697Snon
410779697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
410879697Snon		if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
410979697Snon			continue;
411079697Snon
411179697Snon		tcount = 0;
411279697Snon		scsi_low_timeout_check(slp);
411379697Snon	}
411479697Snon
411579697Snon	return 0;
411679697Snon}
411779697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
411879697Snon
411967468Snon/**********************************************************
412067468Snon * DEBUG SECTION
412167468Snon **********************************************************/
412279697Snon#ifdef	SCSI_LOW_DEBUG
412367468Snonstatic void
412479697Snonscsi_low_test_abort(slp, ti, li)
412579697Snon	struct scsi_low_softc *slp;
412679697Snon	struct targ_info *ti;
412779697Snon	struct lun_info *li;
412879697Snon{
412979697Snon	struct slccb *acb;
413079697Snon
413179697Snon	if (li->li_disc > 1)
413279697Snon	{
413379697Snon		acb = TAILQ_FIRST(&li->li_discq);
413479697Snon		if (scsi_low_abort_ccb(slp, acb) == 0)
413579697Snon		{
4136240325Sjhb			device_printf(slp->sl_dev,
4137240325Sjhb			    "aborting ccb(0x%lx) start\n", (u_long) acb);
413879697Snon		}
413979697Snon	}
414079697Snon}
414179697Snon
414279697Snonstatic void
414379697Snonscsi_low_test_atten(slp, ti, msg)
414479697Snon	struct scsi_low_softc *slp;
414579697Snon	struct targ_info *ti;
414679697Snon	u_int msg;
414779697Snon{
414879697Snon
414979697Snon	if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
415079697Snon		scsi_low_assert_msg(slp, ti, msg, 0);
415179697Snon	else
4152240325Sjhb		device_printf(slp->sl_dev, "atten check OK\n");
415379697Snon}
415479697Snon
415579697Snonstatic void
415679697Snonscsi_low_test_cmdlnk(slp, cb)
415779697Snon	struct scsi_low_softc *slp;
415879697Snon	struct slccb *cb;
415979697Snon{
416079697Snon#define	SCSI_LOW_CMDLNK_NOK	(CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
416179697Snon
416279697Snon	if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
416379697Snon		return;
416479697Snon
416579697Snon	memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
416679697Snon	       slp->sl_scp.scp_cmdlen);
416779697Snon	cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
416879697Snon	slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
416979697Snon}
417079697Snon#endif	/* SCSI_LOW_DEBUG */
417179697Snon
417279697Snon/* static */ void
417367468Snonscsi_low_info(slp, ti, s)
417467468Snon	struct scsi_low_softc *slp;
417567468Snon	struct targ_info *ti;
417667468Snon	u_char *s;
417767468Snon{
417867468Snon
417979697Snon	if (slp == NULL)
418079697Snon		slp = LIST_FIRST(&sl_tab);
418179697Snon	if (s == NULL)
418279697Snon		s = "no message";
418379697Snon
418479697Snon	printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
418567468Snon	if (ti == NULL)
418667468Snon	{
418779697Snon		for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
418879697Snon		     ti = TAILQ_NEXT(ti, ti_chain))
418979697Snon		{
419067468Snon			scsi_low_print(slp, ti);
419179697Snon		}
419267468Snon	}
419367468Snon	else
419479697Snon	{
419567468Snon		scsi_low_print(slp, ti);
419679697Snon	}
419767468Snon}
419867468Snon
419967468Snonstatic u_char *phase[] =
420067468Snon{
420167468Snon	"FREE", "ARBSTART", "SELSTART", "SELECTED",
420267468Snon	"CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL"
420367468Snon};
420467468Snon
420567468Snonvoid
420667468Snonscsi_low_print(slp, ti)
420767468Snon	struct scsi_low_softc *slp;
420867468Snon	struct targ_info *ti;
420967468Snon{
421079697Snon	struct lun_info *li;
421179697Snon	struct slccb *cb;
421279697Snon	struct sc_p *sp;
421367468Snon
421479697Snon	if (ti == NULL || ti == slp->sl_Tnexus)
421579697Snon	{
421679697Snon		ti = slp->sl_Tnexus;
421779697Snon		li = slp->sl_Lnexus;
421879697Snon		cb = slp->sl_Qnexus;
421979697Snon	}
422079697Snon	else
422179697Snon	{
422279697Snon		li = LIST_FIRST(&ti->ti_litab);
422379697Snon		cb = TAILQ_FIRST(&li->li_discq);
422479697Snon	}
422579697Snon 	sp = &slp->sl_scp;
422667468Snon
4227240325Sjhb	device_printf(slp->sl_dev,
4228240325Sjhb	    "=== NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
4229240325Sjhb	    (u_long) ti, (u_long) li, (u_long) cb, slp->sl_nio);
423067468Snon
423167468Snon	/* target stat */
423267468Snon	if (ti != NULL)
423367468Snon	{
423479697Snon		u_int flags = 0, maxnqio = 0, nqio = 0;
4235265632Smav		int lun = CAM_LUN_WILDCARD;
423667468Snon
423767468Snon		if (li != NULL)
423867468Snon		{
423967468Snon			lun = li->li_lun;
424067468Snon			flags = li->li_flags;
424179697Snon			maxnqio = li->li_maxnqio;
424279697Snon			nqio = li->li_nqio;
424367468Snon		}
424467468Snon
4245240325Sjhb		device_printf(slp->sl_dev,
4246240325Sjhb		       "(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
424767468Snon		       ti->ti_id, lun, phase[(int) ti->ti_ophase],
424879697Snon		       phase[(int) ti->ti_phase], ti->ti_disc,
424979697Snon		       nqio, maxnqio);
425067468Snon
425179697Snon		if (cb != NULL)
425279697Snon		{
425379697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
425479697Snon		       (u_int) cb->ccb_scp.scp_cmd[0],
425579697Snon		       cb->ccb_scp.scp_cmdlen,
425679697Snon		       cb->ccb_datalen,
425779697Snon		       cb->ccb_scp.scp_datalen,
425879697Snon		       (u_int) cb->ccb_sscp.scp_status,
425979697Snon		       cb->ccb_error, SCSI_LOW_ERRORBITS);
426079697Snon		}
426167468Snon
426279697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
426379697Snon	       (u_int) (ti->ti_msginptr),
426479697Snon	       (u_int) (ti->ti_msgin[0]),
426579697Snon	       (u_int) (ti->ti_msgin[1]),
426679697Snon	       (u_int) (ti->ti_msgin[2]),
426779697Snon	       (u_int) (ti->ti_msgin[3]),
426879697Snon	       (u_int) (ti->ti_msgin[4]),
426979697Snon	       slp->sl_atten);
427079697Snon
427167468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
427279697Snon		(u_int) ti->ti_msgflags,
427379697Snon		(u_int) (ti->ti_msgoutstr[0]),
427479697Snon		(u_int) (ti->ti_msgoutstr[1]),
427579697Snon		(u_int) (ti->ti_msgoutstr[2]),
427679697Snon		(u_int) (ti->ti_msgoutstr[3]),
427779697Snon		(u_int) (ti->ti_msgoutstr[4]),
427879697Snon		ti->ti_msgoutlen,
427979697Snon		flags, SCSI_LOW_BITS);
428067468Snon
428179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
428279697Snon		scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
428379697Snon		scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
428479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
428567468Snon
428667468Snon	}
428779697Snon
428879697Snon	printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
428979697Snon	       (u_long) sp->scp_data,
429079697Snon	       sp->scp_datalen,
429179697Snon	       (u_int) sp->scp_status,
429279697Snon	       slp->sl_error, SCSI_LOW_ERRORBITS);
429367468Snon}
4294