scsi_low.c revision 168831
179697Snon/* $NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $ */ 267468Snon/* $NetBSD$ */ 367468Snon 4116162Sobrien#include <sys/cdefs.h> 5116162Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_low.c 168831 2007-04-18 04:58:53Z scottl $"); 6116162Sobrien 767468Snon#define SCSI_LOW_STATICS 879697Snon#define SCSI_LOW_DEBUG 979697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE 1079697Snon#define SCSI_LOW_START_UP_CHECK 1179697Snon 1279697Snon/* #define SCSI_LOW_INFO_DETAIL */ 13116162Sobrien 1479697Snon/* #define SCSI_LOW_QCLEAR_AFTER_CA */ 1579697Snon/* #define SCSI_LOW_FLAGS_QUIRKS_OK */ 1679697Snon 1767468Snon#ifdef __NetBSD__ 1867468Snon#define SCSI_LOW_TARGET_OPEN 1979697Snon#endif /* __NetBSD__ */ 2067468Snon 2179697Snon#ifdef __FreeBSD__ 2279697Snon#define SCSI_LOW_FLAGS_QUIRKS_OK 2379697Snon#endif /* __FreeBSD__ */ 2479697Snon 25139743Simp/*- 2667468Snon * [NetBSD for NEC PC-98 series] 2779697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2867468Snon * NetBSD/pc98 porting staff. All rights reserved. 2979697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 3067468Snon * Naofumi HONDA. All rights reserved. 3179697Snon * 3279697Snon * [Ported for FreeBSD CAM] 3379697Snon * Copyright (c) 2000, 2001 3479697Snon * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. 3579697Snon * All rights reserved. 3667468Snon * 3767468Snon * Redistribution and use in source and binary forms, with or without 3867468Snon * modification, are permitted provided that the following conditions 3967468Snon * are met: 4067468Snon * 1. Redistributions of source code must retain the above copyright 4167468Snon * notice, this list of conditions and the following disclaimer. 4267468Snon * 2. Redistributions in binary form must reproduce the above copyright 4367468Snon * notice, this list of conditions and the following disclaimer in the 4467468Snon * documentation and/or other materials provided with the distribution. 4567468Snon * 3. The name of the author may not be used to endorse or promote products 4667468Snon * derived from this software without specific prior written permission. 4767468Snon * 4867468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4967468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 5067468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 5167468Snon * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 5267468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5367468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 5467468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5567468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 5667468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 5767468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5867468Snon * POSSIBILITY OF SUCH DAMAGE. 5967468Snon */ 6067468Snon 6167468Snon/* <On the nexus establishment> 6267468Snon * When our host is reselected, 6367468Snon * nexus establish processes are little complicated. 6467468Snon * Normal steps are followings: 6579697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus) 6679697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus) 6779697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus) 6867468Snon */ 6967468Snon#include "opt_ddb.h" 7067468Snon 7167468Snon#include <sys/param.h> 7267468Snon#include <sys/systm.h> 7367468Snon#include <sys/kernel.h> 7479697Snon 7573025Snon#ifdef __FreeBSD__ 7673025Snon#if __FreeBSD_version >= 500001 7767468Snon#include <sys/bio.h> 7879697Snon#else 7979697Snon#include <machine/clock.h> 8073025Snon#endif 8179697Snon#endif /* __FreeBSD__ */ 8279697Snon 8367468Snon#include <sys/buf.h> 8467468Snon#include <sys/queue.h> 8567468Snon#include <sys/malloc.h> 8667468Snon#include <sys/errno.h> 8767468Snon 8879697Snon#ifdef __NetBSD__ 8979697Snon#include <sys/device.h> 9067468Snon#include <vm/vm.h> 9167468Snon 9267468Snon#include <machine/bus.h> 9367468Snon#include <machine/intr.h> 9467468Snon#include <machine/dvcfg.h> 9567468Snon 9667468Snon#include <dev/cons.h> 9767468Snon 9867468Snon#include <dev/scsipi/scsipi_all.h> 9967468Snon#include <dev/scsipi/scsipiconf.h> 10067468Snon#include <dev/scsipi/scsipi_disk.h> 10167468Snon#include <dev/scsipi/scsi_all.h> 10267468Snon#include <dev/scsipi/scsiconf.h> 10379697Snon#include <sys/scsiio.h> 10467468Snon 10567468Snon#include <i386/Cbus/dev/scsi_low.h> 10679697Snon#endif /* __NetBSD__ */ 10779697Snon 10867468Snon#ifdef __FreeBSD__ 10967468Snon#include <cam/cam.h> 11067468Snon#include <cam/cam_ccb.h> 11167468Snon#include <cam/cam_sim.h> 11267468Snon#include <cam/cam_debug.h> 11367468Snon#include <cam/cam_periph.h> 114147723Savatar#include <cam/cam_xpt_periph.h> 11567468Snon 11667468Snon#include <cam/scsi/scsi_all.h> 11773025Snon#include <cam/scsi/scsi_message.h> 11867468Snon 11967468Snon#include <cam/scsi/scsi_low.h> 12067468Snon 12167468Snon#include <sys/cons.h> 12279697Snon#endif /* __FreeBSD__ */ 12367468Snon 12479697Snon/************************************************************** 12579697Snon * Constants 12679697Snon **************************************************************/ 12779697Snon#define SCSI_LOW_POLL_HZ 1000 12867468Snon 12979697Snon/* functions return values */ 13079697Snon#define SCSI_LOW_START_NO_QTAG 0 13179697Snon#define SCSI_LOW_START_QTAG 1 13279697Snon 13367468Snon#define SCSI_LOW_DONE_COMPLETE 0 13467468Snon#define SCSI_LOW_DONE_RETRY 1 13567468Snon 13679697Snon/* internal disk flags */ 13779697Snon#define SCSI_LOW_DISK_DISC 0x00000001 13879697Snon#define SCSI_LOW_DISK_QTAG 0x00000002 13979697Snon#define SCSI_LOW_DISK_LINK 0x00000004 14079697Snon#define SCSI_LOW_DISK_PARITY 0x00000008 14179697Snon#define SCSI_LOW_DISK_SYNC 0x00010000 14279697Snon#define SCSI_LOW_DISK_WIDE_16 0x00020000 14379697Snon#define SCSI_LOW_DISK_WIDE_32 0x00040000 14479697Snon#define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32) 14579697Snon#define SCSI_LOW_DISK_LFLAGS 0x0000ffff 14679697Snon#define SCSI_LOW_DISK_TFLAGS 0xffff0000 14779697Snon 148147723SavatarMALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers"); 149147723Savatar 15079697Snon/************************************************************** 15179697Snon * Declarations 15279697Snon **************************************************************/ 15392770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *); 15492770Salfredstatic void scsi_low_engage(void *); 15592770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t); 15692770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *); 15792770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *); 15892770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *); 15992770Salfredstatic void scsi_low_twiddle_wait(void); 16092770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int); 16192770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int); 16292770Salfredstatic void scsi_low_calcf_lun(struct lun_info *); 16392770Salfredstatic void scsi_low_calcf_target(struct targ_info *); 16492770Salfredstatic void scsi_low_calcf_show(struct lun_info *); 16592770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int); 16692770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int); 16792770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int); 16892770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int); 16992770Salfredstatic void scsi_low_start(struct scsi_low_softc *); 17092770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *); 17167468Snon 17292770Salfredstatic int scsi_low_alloc_qtag(struct slccb *); 17392770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *); 17492770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int); 17592770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int); 17692770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *); 17792770Salfredstatic void scsi_low_timeout(void *); 17892770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *); 17979697Snon#ifdef SCSI_LOW_START_UP_CHECK 18092770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *); 18179697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 18292770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *); 18392770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int); 18479697Snon 18579697Snonint scsi_low_version_major = 2; 18679697Snonint scsi_low_version_minor = 17; 18779697Snon 18879697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab); 18979697Snon 19079697Snon/************************************************************** 19179697Snon * Debug, Run test and Statics 19279697Snon **************************************************************/ 19379697Snon#ifdef SCSI_LOW_INFO_DETAIL 19479697Snon#define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s)) 19579697Snon#else /* !SCSI_LOW_INFO_DETAIL */ 19679697Snon#define SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s)) 19779697Snon#endif /* !SCSI_LOW_INFO_DETAIL */ 19879697Snon 19967468Snon#ifdef SCSI_LOW_STATICS 20089113Smsmithstatic struct scsi_low_statics { 20167468Snon int nexus_win; 20267468Snon int nexus_fail; 20367468Snon int nexus_disconnected; 20467468Snon int nexus_reselected; 20567468Snon int nexus_conflict; 20667468Snon} scsi_low_statics; 20767468Snon#endif /* SCSI_LOW_STATICS */ 20879697Snon 20979697Snon#ifdef SCSI_LOW_DEBUG 21079697Snon#define SCSI_LOW_DEBUG_DONE 0x00001 21179697Snon#define SCSI_LOW_DEBUG_DISC 0x00002 21279697Snon#define SCSI_LOW_DEBUG_SENSE 0x00004 21379697Snon#define SCSI_LOW_DEBUG_CALCF 0x00008 21479697Snon#define SCSI_LOW_DEBUG_ACTION 0x10000 21579697Snonint scsi_low_debug = 0; 21679697Snon 21779697Snon#define SCSI_LOW_MAX_ATTEN_CHECK 32 21879697Snon#define SCSI_LOW_ATTEN_CHECK 0x0001 21979697Snon#define SCSI_LOW_CMDLNK_CHECK 0x0002 22079697Snon#define SCSI_LOW_ABORT_CHECK 0x0004 22179697Snon#define SCSI_LOW_NEXUS_CHECK 0x0008 22279697Snonint scsi_low_test = 0; 22379697Snonint scsi_low_test_id = 0; 22479697Snon 22592770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *); 22692770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *); 22792770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int); 22879697Snon#define SCSI_LOW_DEBUG_TEST_GO(fl, id) \ 22979697Snon ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 23079697Snon#define SCSI_LOW_DEBUG_GO(fl, id) \ 23179697Snon ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 23279697Snon#endif /* SCSI_LOW_DEBUG */ 23379697Snon 23467468Snon/************************************************************** 23579697Snon * CCB 23679697Snon **************************************************************/ 23779697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) 23879697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain) 23979697Snon 24079697Snon/************************************************************** 24179697Snon * Inline functions 24279697Snon **************************************************************/ 24379697Snon#define SCSI_LOW_INLINE static __inline 24492770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *); 24592770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *); 24692770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int); 24792770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *); 24892770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *); 24992770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *); 25092770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *); 25179697Snon 25279697SnonSCSI_LOW_INLINE void 25379697Snonscsi_low_activate_qtag(cb) 25479697Snon struct slccb *cb; 25579697Snon{ 25679697Snon struct lun_info *li = cb->li; 25779697Snon 25879697Snon if (cb->ccb_tag != SCSI_LOW_UNKTAG) 25979697Snon return; 26079697Snon 26179697Snon li->li_nqio ++; 26279697Snon cb->ccb_tag = cb->ccb_otag; 26379697Snon} 26479697Snon 26579697SnonSCSI_LOW_INLINE void 26679697Snonscsi_low_deactivate_qtag(cb) 26779697Snon struct slccb *cb; 26879697Snon{ 26979697Snon struct lun_info *li = cb->li; 27079697Snon 27179697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 27279697Snon return; 27379697Snon 27479697Snon li->li_nqio --; 27579697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 27679697Snon} 27779697Snon 27879697SnonSCSI_LOW_INLINE void 27979697Snonscsi_low_ccb_message_exec(slp, cb) 28079697Snon struct scsi_low_softc *slp; 28179697Snon struct slccb *cb; 28279697Snon{ 28379697Snon 28479697Snon scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0); 28579697Snon cb->ccb_msgoutflag = 0; 28679697Snon} 28779697Snon 28879697SnonSCSI_LOW_INLINE void 28979697Snonscsi_low_ccb_message_assert(cb, msg) 29079697Snon struct slccb *cb; 29179697Snon u_int msg; 29279697Snon{ 29379697Snon 29479697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg; 29579697Snon} 29679697Snon 29779697SnonSCSI_LOW_INLINE void 29879697Snonscsi_low_ccb_message_retry(cb) 29979697Snon struct slccb *cb; 30079697Snon{ 30179697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag; 30279697Snon} 30379697Snon 30479697SnonSCSI_LOW_INLINE void 30579697Snonscsi_low_ccb_message_clear(cb) 30679697Snon struct slccb *cb; 30779697Snon{ 30879697Snon cb->ccb_msgoutflag = 0; 30979697Snon} 31079697Snon 31179697SnonSCSI_LOW_INLINE void 31279697Snonscsi_low_init_msgsys(slp, ti) 31379697Snon struct scsi_low_softc *slp; 31479697Snon struct targ_info *ti; 31579697Snon{ 31679697Snon 31779697Snon ti->ti_msginptr = 0; 31879697Snon ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; 31979697Snon SCSI_LOW_DEASSERT_ATN(slp); 32079697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 32179697Snon} 32279697Snon 32379697Snon/*============================================================= 32479697Snon * START OF OS switch (All OS depend fucntions should be here) 32579697Snon =============================================================*/ 32679697Snon/* common os depend utitlities */ 32779697Snon#define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001 32879697Snon#define SCSI_LOW_CMD_ORDERED_QTAG 0x0002 32979697Snon#define SCSI_LOW_CMD_ABORT_WARNING 0x0004 33079697Snon 33179697Snonstatic u_int8_t scsi_low_cmd_flags[256] = { 33279697Snon/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 33379697Snon/*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 33479697Snon/*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 33579697Snon/*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5, 33679697Snon/*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 33779697Snon}; 33879697Snon 33979697Snonstruct scsi_low_error_code { 34079697Snon int error_bits; 34179697Snon int error_code; 34279697Snon}; 34379697Snon 34492770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *); 34592770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *); 34679697Snon 34779697Snonstatic struct slccb * 34879697Snonscsi_low_find_ccb(slp, target, lun, osdep) 34979697Snon struct scsi_low_softc *slp; 35079697Snon u_int target, lun; 35179697Snon void *osdep; 35279697Snon{ 35379697Snon struct targ_info *ti; 35479697Snon struct lun_info *li; 35579697Snon struct slccb *cb; 35679697Snon 35779697Snon ti = slp->sl_ti[target]; 35879697Snon li = scsi_low_alloc_li(ti, lun, 0); 35979697Snon if (li == NULL) 36079697Snon return NULL; 36179697Snon 36279697Snon if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep) 36379697Snon return cb; 36479697Snon 36579697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 36679697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 36779697Snon { 36879697Snon if (cb->osdep == osdep) 36979697Snon return cb; 37079697Snon } 37179697Snon 37279697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; 37379697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 37479697Snon { 37579697Snon if (cb->osdep == osdep) 37679697Snon return cb; 37779697Snon } 37879697Snon return NULL; 37979697Snon} 38079697Snon 38179697Snonstatic int 38279697Snonscsi_low_translate_error_code(cb, tp) 38379697Snon struct slccb *cb; 38479697Snon struct scsi_low_error_code *tp; 38579697Snon{ 38679697Snon 38779697Snon if (cb->ccb_error == 0) 38879697Snon return tp->error_code; 38979697Snon 39079697Snon for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++) 39179697Snon ; 39279697Snon return tp->error_code; 39379697Snon} 39479697Snon 39579697Snon#ifdef SCSI_LOW_INTERFACE_XS 39679697Snon/************************************************************** 39779697Snon * SCSI INTERFACE (XS) 39879697Snon **************************************************************/ 39979697Snon#define SCSI_LOW_MINPHYS 0x10000 400147723Savatar#define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) 401147723Savatar#define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) 40279697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb((flags)) 40379697Snon#define SCSI_LOW_XS_POLL_HZ 1000 40479697Snon 40592770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *); 40692770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *); 40779697Snon#ifdef SCSI_LOW_TARGET_OPEN 40892770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *); 40979697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 41092770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *); 41192770Salfredstatic int scsi_low_enable_xs(void *, int); 41292770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *); 41379697Snon 41492770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *); 41592770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *); 41692770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *); 41792770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *); 41892770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *); 41992770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int); 42092770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int); 42192770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int); 42279697Snon 42379697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = { 42479697Snon scsi_low_attach_xs, 42579697Snon scsi_low_world_start_xs, 42679697Snon scsi_low_dettach_xs, 42779697Snon scsi_low_ccb_setup_xs, 42879697Snon scsi_low_done_xs, 42979697Snon scsi_low_timeout_xs 43079697Snon}; 43179697Snon 43279697Snonstruct scsipi_device scsi_low_dev = { 43379697Snon NULL, /* Use default error handler */ 43479697Snon NULL, /* have a queue, served by this */ 43579697Snon NULL, /* have no async handler */ 43679697Snon NULL, /* Use default 'done' routine */ 43779697Snon}; 43879697Snon 43979697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = { 44079697Snon {0, XS_NOERROR}, 44179697Snon {SENSEIO, XS_SENSE}, 44279697Snon {BUSYERR, XS_BUSY }, 44379697Snon {SELTIMEOUTIO, XS_SELTIMEOUT}, 44479697Snon {TIMEOUTIO, XS_TIMEOUT}, 44579697Snon {-1, XS_DRIVER_STUFFUP} 44679697Snon}; 44779697Snon 44879697Snonstatic int 44979697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p) 45079697Snon struct scsipi_link *link; 45179697Snon u_long cmd; 45279697Snon caddr_t addr; 45379697Snon int flag; 45479697Snon struct proc *p; 45579697Snon{ 45679697Snon struct scsi_low_softc *slp; 45779697Snon int s, error = ENOTTY; 45879697Snon 45979697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 46079697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 46179697Snon return ENXIO; 46279697Snon 46379697Snon if (cmd == SCBUSIORESET) 46479697Snon { 46579697Snon s = SCSI_LOW_SPLSCSI(); 46679697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 46779697Snon splx(s); 46879697Snon error = 0; 46979697Snon } 47079697Snon else if (slp->sl_funcs->scsi_low_ioctl != 0) 47179697Snon { 47279697Snon error = (*slp->sl_funcs->scsi_low_ioctl) 47379697Snon (slp, cmd, addr, flag, p); 47479697Snon } 47579697Snon 47679697Snon return error; 47779697Snon} 47879697Snon 47979697Snonstatic int 48079697Snonscsi_low_enable_xs(arg, enable) 48179697Snon void *arg; 48279697Snon int enable; 48379697Snon{ 48479697Snon struct scsi_low_softc *slp = arg; 48579697Snon 48679697Snon if (enable != 0) 48779697Snon { 48879697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 48979697Snon return ENXIO; 49079697Snon } 49179697Snon else 49279697Snon { 49379697Snon if ((slp->sl_flags & HW_INACTIVE) != 0 || 49479697Snon (slp->sl_flags & HW_POWERCTRL) == 0) 49579697Snon return 0; 49679697Snon 49779697Snon slp->sl_flags |= HW_POWDOWN; 49879697Snon if (slp->sl_funcs->scsi_low_power != NULL) 49979697Snon { 50079697Snon (*slp->sl_funcs->scsi_low_power) 50179697Snon (slp, SCSI_LOW_POWDOWN); 50279697Snon } 50379697Snon } 50479697Snon return 0; 50579697Snon} 50679697Snon 50779697Snonstatic void 50879697Snonscsi_low_scsi_minphys_xs(bp) 50979697Snon struct buf *bp; 51079697Snon{ 51179697Snon 51279697Snon if (bp->b_bcount > SCSI_LOW_MINPHYS) 51379697Snon bp->b_bcount = SCSI_LOW_MINPHYS; 51479697Snon minphys(bp); 51579697Snon} 51679697Snon 51779697Snonstatic int 51879697Snonscsi_low_poll_xs(slp, cb) 51979697Snon struct scsi_low_softc *slp; 52079697Snon struct slccb *cb; 52179697Snon{ 52279697Snon struct scsipi_xfer *xs = cb->osdep; 52379697Snon int tcount; 52479697Snon 52579697Snon cb->ccb_flags |= CCB_NOSDONE; 52679697Snon tcount = 0; 52779697Snon 52879697Snon while (slp->sl_nio > 0) 52979697Snon { 53079697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ); 53179697Snon 53279697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 53379697Snon 53479697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 53579697Snon { 53679697Snon cb->ccb_flags |= CCB_NORETRY; 53779697Snon cb->ccb_error |= FATALIO; 53879697Snon (void) scsi_low_revoke_ccb(slp, cb, 1); 53979697Snon printf("%s: hardware inactive in poll mode\n", 54079697Snon slp->sl_xname); 54179697Snon } 54279697Snon 54379697Snon if ((xs->flags & ITSDONE) != 0) 54479697Snon break; 54579697Snon 54679697Snon if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 54779697Snon continue; 54879697Snon 54979697Snon tcount = 0; 55079697Snon scsi_low_timeout_check(slp); 55179697Snon } 55279697Snon 55379697Snon xs->flags |= ITSDONE; 55479697Snon scsipi_done(xs); 55579697Snon return COMPLETE; 55679697Snon} 55779697Snon 55879697Snonstatic int 55979697Snonscsi_low_scsi_cmd_xs(xs) 56079697Snon struct scsipi_xfer *xs; 56179697Snon{ 56279697Snon struct scsipi_link *splp = xs->sc_link; 56379697Snon struct scsi_low_softc *slp = splp->adapter_softc; 56479697Snon struct targ_info *ti; 56579697Snon struct lun_info *li; 56679697Snon struct slccb *cb; 56779697Snon int s, targ, lun, flags, rv; 56879697Snon 56979697Snon if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL) 57079697Snon return TRY_AGAIN_LATER; 57179697Snon 57279697Snon targ = splp->scsipi_scsi.target, 57379697Snon lun = splp->scsipi_scsi.lun; 57479697Snon ti = slp->sl_ti[targ]; 57579697Snon 57679697Snon cb->osdep = xs; 57779697Snon cb->bp = xs->bp; 57879697Snon 57979697Snon if ((xs->flags & SCSI_POLL) == 0) 58079697Snon flags = CCB_AUTOSENSE; 58179697Snon else 58279697Snon flags = CCB_AUTOSENSE | CCB_POLLED; 58379697Snon 58479697Snon 58579697Snon s = SCSI_LOW_SPLSCSI(); 58679697Snon li = scsi_low_alloc_li(ti, lun, 1); 58779697Snon if ((u_int) splp->quirks != li->li_sloi.sloi_quirks) 58879697Snon { 58979697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks); 59079697Snon } 59179697Snon 59279697Snon if ((xs->flags & SCSI_RESET) != 0) 59379697Snon { 59479697Snon flags |= CCB_NORETRY | CCB_URGENT; 59579697Snon scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET); 59679697Snon } 59779697Snon else 59879697Snon { 59979697Snon if (ti->ti_setup_msg != 0) 60079697Snon { 60179697Snon scsi_low_message_enqueue(slp, ti, li, flags); 60279697Snon } 60379697Snon 60479697Snon flags |= CCB_SCSIIO; 60579697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 60679697Snon } 60779697Snon 60879697Snon#ifdef SCSI_LOW_DEBUG 60979697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0) 61079697Snon { 61179697Snon scsi_low_test_abort(slp, ti, li); 61279697Snon } 61379697Snon#endif /* SCSI_LOW_DEBUG */ 61479697Snon 61579697Snon if ((cb->ccb_flags & CCB_POLLED) != 0) 61679697Snon { 61779697Snon rv = scsi_low_poll_xs(slp, cb); 61879697Snon } 61979697Snon else 62079697Snon { 62179697Snon rv = SUCCESSFULLY_QUEUED; 62279697Snon } 62379697Snon splx(s); 62479697Snon return rv; 62579697Snon} 62679697Snon 62779697Snonstatic int 62879697Snonscsi_low_attach_xs(slp) 62979697Snon struct scsi_low_softc *slp; 63079697Snon{ 63179697Snon struct scsipi_adapter *sap; 63279697Snon struct scsipi_link *splp; 63379697Snon 63479697Snon strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16); 63579697Snon 63679697Snon sap = SCSI_LOW_MALLOC(sizeof(*sap)); 63779697Snon if (sap == NULL) 63879697Snon return ENOMEM; 63979697Snon splp = SCSI_LOW_MALLOC(sizeof(*splp)); 64079697Snon if (splp == NULL) 64179697Snon return ENOMEM; 64279697Snon 64379697Snon SCSI_LOW_BZERO(sap, sizeof(*sap)); 64479697Snon SCSI_LOW_BZERO(splp, sizeof(*splp)); 64579697Snon 64679697Snon sap->scsipi_cmd = scsi_low_scsi_cmd_xs; 64779697Snon sap->scsipi_minphys = scsi_low_scsi_minphys_xs; 64879697Snon sap->scsipi_enable = scsi_low_enable_xs; 64979697Snon sap->scsipi_ioctl = scsi_low_ioctl_xs; 65079697Snon#ifdef SCSI_LOW_TARGET_OPEN 65179697Snon sap->open_target_lu = scsi_low_target_open; 65279697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 65379697Snon 65479697Snon splp->adapter_softc = slp; 65579697Snon splp->scsipi_scsi.adapter_target = slp->sl_hostid; 65679697Snon splp->scsipi_scsi.max_target = slp->sl_ntargs - 1; 65779697Snon splp->scsipi_scsi.max_lun = slp->sl_nluns - 1; 65879697Snon splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 65979697Snon splp->openings = slp->sl_openings; 66079697Snon splp->type = BUS_SCSI; 66179697Snon splp->adapter_softc = slp; 66279697Snon splp->adapter = sap; 66379697Snon splp->device = &scsi_low_dev; 66479697Snon 66579697Snon slp->sl_si.si_splp = splp; 66679697Snon slp->sl_show_result = SHOW_ALL_NEG; 66779697Snon return 0; 66879697Snon} 66979697Snon 67079697Snonstatic int 67179697Snonscsi_low_world_start_xs(slp) 67279697Snon struct scsi_low_softc *slp; 67379697Snon{ 67479697Snon 67579697Snon return 0; 67679697Snon} 67779697Snon 67879697Snonstatic int 67979697Snonscsi_low_dettach_xs(slp) 68079697Snon struct scsi_low_softc *slp; 68179697Snon{ 68279697Snon 68379697Snon /* 68479697Snon * scsipi does not have dettach bus fucntion. 68579697Snon * 68679697Snon scsipi_dettach_scsibus(slp->sl_si.si_splp); 68779697Snon */ 68879697Snon return 0; 68979697Snon} 69079697Snon 69179697Snonstatic int 69279697Snonscsi_low_ccb_setup_xs(slp, cb) 69379697Snon struct scsi_low_softc *slp; 69479697Snon struct slccb *cb; 69579697Snon{ 69679697Snon struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep; 69779697Snon 69879697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 69979697Snon { 70079697Snon cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; 70179697Snon cb->ccb_scp.scp_cmdlen = xs->cmdlen; 70279697Snon cb->ccb_scp.scp_data = xs->data; 70379697Snon cb->ccb_scp.scp_datalen = xs->datalen; 70479697Snon cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? 70579697Snon SCSI_LOW_WRITE : SCSI_LOW_READ; 70679697Snon cb->ccb_tcmax = xs->timeout / 1000; 70779697Snon } 70879697Snon else 70979697Snon { 71079697Snon scsi_low_unit_ready_cmd(cb); 71179697Snon } 71279697Snon return SCSI_LOW_START_QTAG; 71379697Snon} 71479697Snon 71579697Snonstatic int 71679697Snonscsi_low_done_xs(slp, cb) 71779697Snon struct scsi_low_softc *slp; 71879697Snon struct slccb *cb; 71979697Snon{ 72079697Snon struct scsipi_xfer *xs; 72179697Snon 72279697Snon xs = (struct scsipi_xfer *) cb->osdep; 72379697Snon if (cb->ccb_error == 0) 72479697Snon { 72579697Snon xs->error = XS_NOERROR; 72679697Snon xs->resid = 0; 72779697Snon } 72879697Snon else 72979697Snon { 73079697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 73179697Snon cb->ccb_error |= ABORTIO; 73279697Snon 73379697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 73479697Snon (cb->ccb_error & ABORTIO) == 0) 73579697Snon return EJUSTRETURN; 73679697Snon 73779697Snon if ((cb->ccb_error & SENSEIO) != 0) 73879697Snon { 73979697Snon xs->sense.scsi_sense = cb->ccb_sense; 74079697Snon } 74179697Snon 74279697Snon xs->error = scsi_low_translate_error_code(cb, 74379697Snon &scsi_low_error_code_xs[0]); 74479697Snon 74579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 74679697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 74779697Snon cb->ccb_scp.scp_cmdlen > 0 && 74879697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 74979697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 75079697Snon { 75179697Snon printf("%s: WARNING: scsi_low IO abort\n", 75279697Snon slp->sl_xname); 75379697Snon scsi_low_print(slp, NULL); 75479697Snon } 75579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 75679697Snon } 75779697Snon 75879697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 75979697Snon xs->status = 0; /* XXX */ 76079697Snon else 76179697Snon xs->status = cb->ccb_scp.scp_status; 76279697Snon 76379697Snon xs->flags |= ITSDONE; 76479697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 76579697Snon scsipi_done(xs); 76679697Snon 76779697Snon return 0; 76879697Snon} 76979697Snon 77079697Snonstatic void 77179697Snonscsi_low_timeout_xs(slp, ch, action) 77279697Snon struct scsi_low_softc *slp; 77379697Snon int ch; 77479697Snon int action; 77579697Snon{ 77679697Snon 77779697Snon switch (ch) 77879697Snon { 77979697Snon case SCSI_LOW_TIMEOUT_CH_IO: 78079697Snon switch (action) 78179697Snon { 78279697Snon case SCSI_LOW_TIMEOUT_START: 78379697Snon timeout(scsi_low_timeout, slp, 78479697Snon hz / SCSI_LOW_TIMEOUT_HZ); 78579697Snon break; 78679697Snon case SCSI_LOW_TIMEOUT_STOP: 78779697Snon untimeout(scsi_low_timeout, slp); 78879697Snon break; 78979697Snon } 79079697Snon break; 79179697Snon 79279697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 79379697Snon switch (action) 79479697Snon { 79579697Snon case SCSI_LOW_TIMEOUT_START: 79679697Snon timeout(scsi_low_engage, slp, 1); 79779697Snon break; 79879697Snon case SCSI_LOW_TIMEOUT_STOP: 79979697Snon untimeout(scsi_low_engage, slp); 80079697Snon break; 80179697Snon } 80279697Snon break; 80379697Snon 80479697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 80579697Snon break; 80679697Snon } 80779697Snon} 80879697Snon 80979697Snonu_int 81079697Snonscsi_low_translate_quirks_xs(quirks) 81179697Snon u_int quirks; 81279697Snon{ 81379697Snon u_int flags; 81479697Snon 81579697Snon flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS; 81679697Snon 81779697Snon#ifdef SDEV_NODISC 81879697Snon if (quirks & SDEV_NODISC) 81979697Snon flags &= ~SCSI_LOW_DISK_DISC; 82079697Snon#endif /* SDEV_NODISC */ 82179697Snon#ifdef SDEV_NOPARITY 82279697Snon if (quirks & SDEV_NOPARITY) 82379697Snon flags &= ~SCSI_LOW_DISK_PARITY; 82479697Snon#endif /* SDEV_NOPARITY */ 82579697Snon#ifdef SDEV_NOCMDLNK 82679697Snon if (quirks & SDEV_NOCMDLNK) 82779697Snon flags &= ~SCSI_LOW_DISK_LINK; 82879697Snon#endif /* SDEV_NOCMDLNK */ 82979697Snon#ifdef SDEV_NOTAG 83079697Snon if (quirks & SDEV_NOTAG) 83179697Snon flags &= ~SCSI_LOW_DISK_QTAG; 83279697Snon#endif /* SDEV_NOTAG */ 83379697Snon#ifdef SDEV_NOSYNC 83479697Snon if (quirks & SDEV_NOSYNC) 83579697Snon flags &= ~SCSI_LOW_DISK_SYNC; 83679697Snon#endif /* SDEV_NOSYNC */ 83779697Snon 83879697Snon return flags; 83979697Snon} 84079697Snon 84179697Snonstatic void 84279697Snonscsi_low_setup_quirks_xs(ti, li, flags) 84379697Snon struct targ_info *ti; 84479697Snon struct lun_info *li; 84579697Snon u_int flags; 84679697Snon{ 84779697Snon u_int quirks; 84879697Snon 84979697Snon li->li_sloi.sloi_quirks = flags; 85079697Snon quirks = scsi_low_translate_quirks_xs(flags); 85179697Snon ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS; 85279697Snon li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS; 85379697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 85479697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 85579697Snon scsi_low_calcf_target(ti); 85679697Snon scsi_low_calcf_lun(li); 85779697Snon scsi_low_calcf_show(li); 85879697Snon} 85979697Snon 86079697Snon#ifdef SCSI_LOW_TARGET_OPEN 86179697Snonstatic int 86279697Snonscsi_low_target_open(link, cf) 86379697Snon struct scsipi_link *link; 86479697Snon struct cfdata *cf; 86579697Snon{ 86679697Snon u_int target = link->scsipi_scsi.target; 86779697Snon u_int lun = link->scsipi_scsi.lun; 86879697Snon struct scsi_low_softc *slp; 86979697Snon struct targ_info *ti; 87079697Snon struct lun_info *li; 87179697Snon 87279697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 87379697Snon ti = slp->sl_ti[target]; 87479697Snon li = scsi_low_alloc_li(ti, lun, 0); 87579697Snon if (li == NULL) 87679697Snon return 0; 87779697Snon 87879697Snon li->li_cfgflags = cf->cf_flags; 87979697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks); 88079697Snon return 0; 88179697Snon} 88279697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 88379697Snon 88479697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 88579697Snon 88679697Snon#ifdef SCSI_LOW_INTERFACE_CAM 88779697Snon/************************************************************** 88879697Snon * SCSI INTERFACE (CAM) 88979697Snon **************************************************************/ 890147723Savatar#define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) 891147723Savatar#define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) 89279697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb() 89379697Snon 89492770Salfredstatic void scsi_low_poll_cam(struct cam_sim *); 89592770Salfredstatic void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *); 89692770Salfredstatic void scsi_low_rescan_bus_cam(struct scsi_low_softc *); 89792770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *); 89879697Snon 89992770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *); 90092770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *); 90192770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *); 90292770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *); 90392770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *); 90492770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int); 90579697Snon 90679697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = { 90779697Snon scsi_low_attach_cam, 90879697Snon scsi_low_world_start_cam, 90979697Snon scsi_low_dettach_cam, 91079697Snon scsi_low_ccb_setup_cam, 91179697Snon scsi_low_done_cam, 91279697Snon scsi_low_timeout_cam 91379697Snon}; 91479697Snon 91579697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = { 91679697Snon {0, CAM_REQ_CMP}, 91779697Snon {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR}, 91879697Snon {SENSEERR, CAM_AUTOSENSE_FAIL}, 91979697Snon {UACAERR, CAM_SCSI_STATUS_ERROR}, 92079697Snon {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR}, 92179697Snon {SELTIMEOUTIO, CAM_SEL_TIMEOUT}, 92279697Snon {TIMEOUTIO, CAM_CMD_TIMEOUT}, 92379697Snon {PDMAERR, CAM_DATA_RUN_ERR}, 92479697Snon {PARITYERR, CAM_UNCOR_PARITY}, 92579697Snon {UBFERR, CAM_UNEXP_BUSFREE}, 92679697Snon {ABORTIO, CAM_REQ_ABORTED}, 92779697Snon {-1, CAM_UNREC_HBA_ERROR} 92879697Snon}; 92979697Snon 93079697Snon#define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim))) 93179697Snon 93279697Snon/* XXX: 93379697Snon * Please check a polling hz, currently we assume scsi_low_poll() is 93479697Snon * called each 1 ms. 93579697Snon */ 93679697Snon#define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */ 93779697Snon 93879697Snonstatic void 93979697Snonscsi_low_poll_cam(sim) 94079697Snon struct cam_sim *sim; 94179697Snon{ 94279697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 94379697Snon 94479697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 94579697Snon 94679697Snon if (slp->sl_si.si_poll_count ++ >= 94779697Snon SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 94879697Snon { 94979697Snon slp->sl_si.si_poll_count = 0; 95079697Snon scsi_low_timeout_check(slp); 95179697Snon } 95279697Snon} 95379697Snon 95479697Snonstatic void 95579697Snonscsi_low_cam_rescan_callback(periph, ccb) 95679697Snon struct cam_periph *periph; 95779697Snon union ccb *ccb; 95879697Snon{ 95979697Snon 96079697Snon xpt_free_path(ccb->ccb_h.path); 961147723Savatar xpt_free_ccb(ccb); 96279697Snon} 96379697Snon 96479697Snonstatic void 96579697Snonscsi_low_rescan_bus_cam(slp) 96679697Snon struct scsi_low_softc *slp; 96779697Snon{ 96879697Snon struct cam_path *path; 969168831Sscottl union ccb *ccb = xpt_alloc_ccb(); 97079697Snon cam_status status; 97179697Snon 97279697Snon bzero(ccb, sizeof(union ccb)); 97379697Snon 97479697Snon status = xpt_create_path(&path, xpt_periph, 97579697Snon cam_sim_path(slp->sl_si.sim), -1, 0); 97679697Snon if (status != CAM_REQ_CMP) 97779697Snon return; 97879697Snon 97979697Snon xpt_setup_ccb(&ccb->ccb_h, path, 5); 98079697Snon ccb->ccb_h.func_code = XPT_SCAN_BUS; 98179697Snon ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; 98279697Snon ccb->crcn.flags = CAM_FLAG_NONE; 98379697Snon xpt_action(ccb); 98479697Snon} 98579697Snon 98679697Snonvoid 98779697Snonscsi_low_scsi_action_cam(sim, ccb) 98879697Snon struct cam_sim *sim; 98979697Snon union ccb *ccb; 99079697Snon{ 99179697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 99279697Snon struct targ_info *ti; 99379697Snon struct lun_info *li; 99479697Snon struct slccb *cb; 99579697Snon u_int lun, flags, msg, target; 99679697Snon int s, rv; 99779697Snon 99879697Snon target = (u_int) (ccb->ccb_h.target_id); 99979697Snon lun = (u_int) ccb->ccb_h.target_lun; 100079697Snon 100179697Snon#ifdef SCSI_LOW_DEBUG 100279697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0) 100379697Snon { 100479697Snon printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n", 100579697Snon slp->sl_xname, ccb->ccb_h.func_code, target, lun); 100679697Snon } 100779697Snon#endif /* SCSI_LOW_DEBUG */ 100879697Snon 100979697Snon switch (ccb->ccb_h.func_code) { 101079697Snon case XPT_SCSI_IO: /* Execute the requested I/O operation */ 101179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 101279697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 101379697Snon { 101479697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 101579697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 101679697Snon xpt_done(ccb); 101779697Snon return; 101879697Snon } 101979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 102079697Snon 102179697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { 102279697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 102379697Snon xpt_done(ccb); 102479697Snon return; 102579697Snon } 102679697Snon 102779697Snon ti = slp->sl_ti[target]; 102879697Snon cb->osdep = ccb; 102979697Snon cb->bp = NULL; 103079697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 103179697Snon flags = CCB_AUTOSENSE | CCB_SCSIIO; 103279697Snon else 103379697Snon flags = CCB_SCSIIO; 103479697Snon 103579697Snon s = SCSI_LOW_SPLSCSI(); 103679697Snon li = scsi_low_alloc_li(ti, lun, 1); 103779697Snon 103879697Snon if (ti->ti_setup_msg != 0) 103979697Snon { 104079697Snon scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE); 104179697Snon } 104279697Snon 104379697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 104479697Snon 104579697Snon#ifdef SCSI_LOW_DEBUG 104679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0) 104779697Snon { 104879697Snon scsi_low_test_abort(slp, ti, li); 104979697Snon } 105079697Snon#endif /* SCSI_LOW_DEBUG */ 105179697Snon splx(s); 105279697Snon break; 105379697Snon 105479697Snon case XPT_EN_LUN: /* Enable LUN as a target */ 105579697Snon case XPT_TARGET_IO: /* Execute target I/O request */ 105679697Snon case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 105779697Snon case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 105879697Snon /* XXX Implement */ 105979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 106079697Snon xpt_done(ccb); 106179697Snon break; 106279697Snon 106379697Snon case XPT_ABORT: /* Abort the specified CCB */ 106479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 106579697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 106679697Snon { 106779697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 106879697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 106979697Snon xpt_done(ccb); 107079697Snon return; 107179697Snon } 107279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 107379697Snon 107479697Snon s = SCSI_LOW_SPLSCSI(); 107579697Snon cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb); 107679697Snon rv = scsi_low_abort_ccb(slp, cb); 107779697Snon splx(s); 107879697Snon 107979697Snon if (rv == 0) 108079697Snon ccb->ccb_h.status = CAM_REQ_CMP; 108179697Snon else 108279697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 108379697Snon xpt_done(ccb); 108479697Snon break; 108579697Snon 108679697Snon case XPT_SET_TRAN_SETTINGS: { 1087163816Smjacob struct ccb_trans_settings_scsi *scsi; 1088163816Smjacob struct ccb_trans_settings_spi *spi; 108979697Snon struct ccb_trans_settings *cts; 109079697Snon u_int val; 109179697Snon 109279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 109379697Snon if (target == CAM_TARGET_WILDCARD) 109479697Snon { 109579697Snon printf("%s: invalid target\n", slp->sl_xname); 109679697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 109779697Snon xpt_done(ccb); 109879697Snon return; 109979697Snon } 110079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 110179697Snon cts = &ccb->cts; 110279697Snon ti = slp->sl_ti[target]; 110379697Snon if (lun == CAM_LUN_WILDCARD) 110479697Snon lun = 0; 110579697Snon 110679697Snon s = SCSI_LOW_SPLSCSI(); 1107163816Smjacob scsi = &cts->proto_specific.scsi; 1108163816Smjacob spi = &cts->xport_specific.spi; 1109163816Smjacob if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH | 1110163816Smjacob CTS_SPI_VALID_SYNC_RATE | 1111163816Smjacob CTS_SPI_VALID_SYNC_OFFSET)) != 0) 1112163816Smjacob { 1113163816Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 1114163816Smjacob val = spi->bus_width; 1115163816Smjacob if (val < ti->ti_width) 1116163816Smjacob ti->ti_width = val; 1117163816Smjacob } 1118163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_RATE) { 1119163816Smjacob val = spi->sync_period; 1120163816Smjacob if (val == 0 || val > ti->ti_maxsynch.period) 1121163816Smjacob ti->ti_maxsynch.period = val; 1122163816Smjacob } 1123163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 1124163816Smjacob val = spi->sync_offset; 1125163816Smjacob if (val < ti->ti_maxsynch.offset) 1126163816Smjacob ti->ti_maxsynch.offset = val; 1127163816Smjacob } 1128163816Smjacob ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 1129163816Smjacob scsi_low_calcf_target(ti); 1130163816Smjacob } 1131163816Smjacob 1132163816Smjacob if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 || 1133163816Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 1134163816Smjacob 1135163816Smjacob li = scsi_low_alloc_li(ti, lun, 1); 1136163816Smjacob if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) { 1137163816Smjacob li->li_quirks |= SCSI_LOW_DISK_DISC; 1138163816Smjacob } else { 1139163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_DISC; 1140163816Smjacob } 1141163816Smjacob 1142163816Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 1143163816Smjacob li->li_quirks |= SCSI_LOW_DISK_QTAG; 1144163816Smjacob } else { 1145163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_QTAG; 1146163816Smjacob } 1147163816Smjacob li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 1148163816Smjacob scsi_low_calcf_target(ti); 1149163816Smjacob scsi_low_calcf_lun(li); 1150163816Smjacob if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) 1151163816Smjacob scsi_low_calcf_show(li); 1152163816Smjacob } 115379697Snon splx(s); 115479697Snon 115579697Snon ccb->ccb_h.status = CAM_REQ_CMP; 115679697Snon xpt_done(ccb); 115779697Snon break; 115879697Snon } 115979697Snon 116079697Snon case XPT_GET_TRAN_SETTINGS: { 116179697Snon struct ccb_trans_settings *cts; 116279697Snon u_int diskflags; 116379697Snon 116479697Snon cts = &ccb->cts; 116579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 116679697Snon if (target == CAM_TARGET_WILDCARD) 116779697Snon { 116879697Snon printf("%s: invalid target\n", slp->sl_xname); 116979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 117079697Snon xpt_done(ccb); 117179697Snon return; 117279697Snon } 117379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 117479697Snon ti = slp->sl_ti[target]; 117579697Snon if (lun == CAM_LUN_WILDCARD) 117679697Snon lun = 0; 117779697Snon 117879697Snon s = SCSI_LOW_SPLSCSI(); 117979697Snon li = scsi_low_alloc_li(ti, lun, 1); 118079697Snon if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) { 118179697Snon struct ccb_trans_settings_scsi *scsi = 118279697Snon &cts->proto_specific.scsi; 118379697Snon struct ccb_trans_settings_spi *spi = 118479697Snon &cts->xport_specific.spi; 118579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 118679697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 118779697Snon { 118879697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 118979697Snon printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n", 119079697Snon slp->sl_xname); 119179697Snon goto settings_out; 119279697Snon } 119379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 119479697Snon cts->protocol = PROTO_SCSI; 119579697Snon cts->protocol_version = SCSI_REV_2; 119679697Snon cts->transport = XPORT_SPI; 119779697Snon cts->transport_version = 2; 119879697Snon 119979697Snon scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 120079697Snon spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 120179697Snon 120279697Snon diskflags = li->li_diskflags & li->li_cfgflags; 120379697Snon if (diskflags & SCSI_LOW_DISK_DISC) 120479697Snon spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 120579697Snon if (diskflags & SCSI_LOW_DISK_QTAG) 120679697Snon scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 120779697Snon 120879697Snon spi->sync_period = ti->ti_maxsynch.period; 120979697Snon spi->valid |= CTS_SPI_VALID_SYNC_RATE; 121079697Snon spi->sync_offset = ti->ti_maxsynch.offset; 121179697Snon spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 121279697Snon 121379697Snon spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 121479697Snon spi->bus_width = ti->ti_width; 121579697Snon 121679697Snon if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 121779697Snon scsi->valid = CTS_SCSI_VALID_TQ; 121879697Snon spi->valid |= CTS_SPI_VALID_DISC; 121979697Snon } else 122079697Snon scsi->valid = 0; 122179697Snon } else 122279697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 122379697Snonsettings_out: 122479697Snon splx(s); 122579697Snon xpt_done(ccb); 122679697Snon break; 122779697Snon } 122879697Snon 122979697Snon case XPT_CALC_GEOMETRY: { /* not yet HN2 */ 1230116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 123179697Snon xpt_done(ccb); 123279697Snon break; 123379697Snon } 123479697Snon 123579697Snon case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 123679697Snon s = SCSI_LOW_SPLSCSI(); 123779697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 123879697Snon splx(s); 123979697Snon ccb->ccb_h.status = CAM_REQ_CMP; 124079697Snon xpt_done(ccb); 124179697Snon break; 124279697Snon 124379697Snon case XPT_TERM_IO: /* Terminate the I/O process */ 124479697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 124579697Snon xpt_done(ccb); 124679697Snon break; 124779697Snon 124879697Snon case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 124979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 125079697Snon if (target == CAM_TARGET_WILDCARD) 125179697Snon { 125279697Snon printf("%s: invalid target\n", slp->sl_xname); 125379697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 125479697Snon xpt_done(ccb); 125579697Snon return; 125679697Snon } 125779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 125879697Snon 125979697Snon msg = SCSI_LOW_MSG_RESET; 126079697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) 126179697Snon { 126279697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 126379697Snon xpt_done(ccb); 126479697Snon return; 126579697Snon } 126679697Snon 126779697Snon ti = slp->sl_ti[target]; 126879697Snon if (lun == CAM_LUN_WILDCARD) 126979697Snon lun = 0; 127079697Snon cb->osdep = ccb; 127179697Snon cb->bp = NULL; 127279697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 127379697Snon flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT; 127479697Snon else 127579697Snon flags = CCB_NORETRY | CCB_URGENT; 127679697Snon 127779697Snon s = SCSI_LOW_SPLSCSI(); 127879697Snon li = scsi_low_alloc_li(ti, lun, 1); 127979697Snon scsi_low_enqueue(slp, ti, li, cb, flags, msg); 128079697Snon splx(s); 128179697Snon break; 128279697Snon 128379697Snon case XPT_PATH_INQ: { /* Path routing inquiry */ 128479697Snon struct ccb_pathinq *cpi = &ccb->cpi; 128579697Snon 128679697Snon cpi->version_num = scsi_low_version_major; 128779697Snon cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB; 128879697Snon ti = slp->sl_ti[slp->sl_hostid]; /* host id */ 128979697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 129079697Snon cpi->hba_inquiry |= PI_WIDE_16; 129179697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 129279697Snon cpi->hba_inquiry |= PI_WIDE_32; 129379697Snon if (ti->ti_maxsynch.offset > 0) 129479697Snon cpi->hba_inquiry |= PI_SDTR_ABLE; 129579697Snon cpi->target_sprt = 0; 129679697Snon cpi->hba_misc = 0; 129779697Snon cpi->hba_eng_cnt = 0; 129879697Snon cpi->max_target = slp->sl_ntargs - 1; 129979697Snon cpi->max_lun = slp->sl_nluns - 1; 130079697Snon cpi->initiator_id = slp->sl_hostid; 130179697Snon cpi->bus_id = cam_sim_bus(sim); 130279697Snon cpi->base_transfer_speed = 3300; 130379697Snon cpi->transport = XPORT_SPI; 130479697Snon cpi->transport_version = 2; 130579697Snon cpi->protocol = PROTO_SCSI; 130679697Snon cpi->protocol_version = SCSI_REV_2; 130779697Snon strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 130879697Snon strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); 130979697Snon strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 131079697Snon cpi->unit_number = cam_sim_unit(sim); 131179697Snon cpi->ccb_h.status = CAM_REQ_CMP; 131279697Snon xpt_done(ccb); 131379697Snon break; 131479697Snon } 131579697Snon 131679697Snon default: 131779697Snon printf("scsi_low: non support func_code = %d ", 131879697Snon ccb->ccb_h.func_code); 131979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 132079697Snon xpt_done(ccb); 132179697Snon break; 132279697Snon } 132379697Snon} 132479697Snon 132579697Snonstatic int 132679697Snonscsi_low_attach_cam(slp) 132779697Snon struct scsi_low_softc *slp; 132879697Snon{ 132979697Snon struct cam_devq *devq; 133079697Snon int tagged_openings; 133179697Snon 133279697Snon sprintf(slp->sl_xname, "%s%d", 133379697Snon DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev)); 133479697Snon 133579697Snon devq = cam_simq_alloc(SCSI_LOW_NCCB); 133679697Snon if (devq == NULL) 133779697Snon return (ENOMEM); 133879697Snon 133979697Snon /* 134079697Snon * ask the adapter what subunits are present 134179697Snon */ 134279697Snon tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS); 134379697Snon slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, 134479697Snon scsi_low_poll_cam, 134579697Snon DEVPORT_DEVNAME(slp->sl_dev), slp, 1346168752Sscottl DEVPORT_DEVUNIT(slp->sl_dev), &Giant, 134779697Snon slp->sl_openings, tagged_openings, devq); 134879697Snon 134979697Snon if (slp->sl_si.sim == NULL) { 135079697Snon cam_simq_free(devq); 135179697Snon return ENODEV; 135279697Snon } 135379697Snon 135479697Snon if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) { 1355147723Savatar free(slp->sl_si.sim, M_SCSILOW); 135679697Snon return ENODEV; 135779697Snon } 135879697Snon 135979697Snon if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL, 136079697Snon cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD, 136179697Snon CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 136279697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 136379697Snon cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE); 136479697Snon return ENODEV; 136579697Snon } 136679697Snon 136779697Snon slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */ 136879697Snon return 0; 136979697Snon} 137079697Snon 137179697Snonstatic int 137279697Snonscsi_low_world_start_cam(slp) 137379697Snon struct scsi_low_softc *slp; 137479697Snon{ 137579697Snon 137679697Snon if (!cold) 137779697Snon scsi_low_rescan_bus_cam(slp); 137879697Snon return 0; 137979697Snon} 138079697Snon 138179697Snonstatic int 138279697Snonscsi_low_dettach_cam(slp) 138379697Snon struct scsi_low_softc *slp; 138479697Snon{ 138579697Snon 138679697Snon xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL); 138779697Snon xpt_free_path(slp->sl_si.path); 138879697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 138979697Snon cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE); 139079697Snon return 0; 139179697Snon} 139279697Snon 139379697Snonstatic int 139479697Snonscsi_low_ccb_setup_cam(slp, cb) 139579697Snon struct scsi_low_softc *slp; 139679697Snon struct slccb *cb; 139779697Snon{ 139879697Snon union ccb *ccb = (union ccb *) cb->osdep; 139979697Snon 140079697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 140179697Snon { 140279697Snon cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; 140379697Snon cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; 140479697Snon cb->ccb_scp.scp_data = ccb->csio.data_ptr; 140579697Snon cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; 140679697Snon if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 140779697Snon cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; 140879697Snon else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ 140979697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 141079697Snon cb->ccb_tcmax = ccb->ccb_h.timeout / 1000; 141179697Snon } 141279697Snon else 141379697Snon { 141479697Snon scsi_low_unit_ready_cmd(cb); 141579697Snon } 141679697Snon return SCSI_LOW_START_QTAG; 141779697Snon} 141879697Snon 141979697Snonstatic int 142079697Snonscsi_low_done_cam(slp, cb) 142179697Snon struct scsi_low_softc *slp; 142279697Snon struct slccb *cb; 142379697Snon{ 142479697Snon union ccb *ccb; 142579697Snon 142679697Snon ccb = (union ccb *) cb->osdep; 142779697Snon if (cb->ccb_error == 0) 142879697Snon { 142979697Snon ccb->ccb_h.status = CAM_REQ_CMP; 143079697Snon ccb->csio.resid = 0; 143179697Snon } 143279697Snon else 143379697Snon { 143479697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 143579697Snon cb->ccb_error |= ABORTIO; 143679697Snon 143779697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 143879697Snon (cb->ccb_error & ABORTIO) == 0) 143979697Snon return EJUSTRETURN; 144079697Snon 144179697Snon if ((cb->ccb_error & SENSEIO) != 0) 144279697Snon { 144379697Snon memcpy(&ccb->csio.sense_data, 144479697Snon &cb->ccb_sense, 144579697Snon sizeof(ccb->csio.sense_data)); 144679697Snon } 144779697Snon 144879697Snon ccb->ccb_h.status = scsi_low_translate_error_code(cb, 144979697Snon &scsi_low_error_code_cam[0]); 145079697Snon 145179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 145279697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 145379697Snon cb->ccb_scp.scp_cmdlen > 0 && 145479697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 145579697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 145679697Snon { 145779697Snon printf("%s: WARNING: scsi_low IO abort\n", 145879697Snon slp->sl_xname); 145979697Snon scsi_low_print(slp, NULL); 146079697Snon } 146179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 146279697Snon } 146379697Snon 146479697Snon if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0) 146579697Snon ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 146679697Snon 146779697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 146879697Snon ccb->csio.scsi_status = 0; /* XXX */ 146979697Snon else 147079697Snon ccb->csio.scsi_status = cb->ccb_scp.scp_status; 147179697Snon 147279697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 147379697Snon xpt_done(ccb); 147479697Snon return 0; 147579697Snon} 147679697Snon 147779697Snonstatic void 147879697Snonscsi_low_timeout_cam(slp, ch, action) 147979697Snon struct scsi_low_softc *slp; 148079697Snon int ch; 148179697Snon int action; 148279697Snon{ 148379697Snon 148479697Snon switch (ch) 148579697Snon { 148679697Snon case SCSI_LOW_TIMEOUT_CH_IO: 148779697Snon switch (action) 148879697Snon { 148979697Snon case SCSI_LOW_TIMEOUT_START: 149079697Snon slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp, 149179697Snon hz / SCSI_LOW_TIMEOUT_HZ); 149279697Snon break; 149379697Snon case SCSI_LOW_TIMEOUT_STOP: 149479697Snon untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch); 149579697Snon break; 149679697Snon } 149779697Snon break; 149879697Snon 149979697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 150079697Snon switch (action) 150179697Snon { 150279697Snon case SCSI_LOW_TIMEOUT_START: 150379697Snon slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1); 150479697Snon break; 150579697Snon case SCSI_LOW_TIMEOUT_STOP: 150679697Snon untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch); 150779697Snon break; 150879697Snon } 150979697Snon break; 151079697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 151179697Snon break; 151279697Snon } 151379697Snon} 151479697Snon 151579697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 151679697Snon 151779697Snon/*============================================================= 151879697Snon * END OF OS switch (All OS depend fucntions should be above) 151979697Snon =============================================================*/ 152079697Snon 152179697Snon/************************************************************** 152279697Snon * scsi low deactivate and activate 152379697Snon **************************************************************/ 152479697Snonint 152579697Snonscsi_low_is_busy(slp) 152679697Snon struct scsi_low_softc *slp; 152779697Snon{ 152879697Snon 152979697Snon if (slp->sl_nio > 0) 153079697Snon return EBUSY; 153179697Snon return 0; 153279697Snon} 153379697Snon 153479697Snonint 153579697Snonscsi_low_deactivate(slp) 153679697Snon struct scsi_low_softc *slp; 153779697Snon{ 153879697Snon int s; 153979697Snon 154079697Snon s = SCSI_LOW_SPLSCSI(); 154179697Snon slp->sl_flags |= HW_INACTIVE; 154279697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 154379697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP); 154479697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 154579697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 154679697Snon splx(s); 154779697Snon return 0; 154879697Snon} 154979697Snon 155079697Snonint 155179697Snonscsi_low_activate(slp) 155279697Snon struct scsi_low_softc *slp; 155379697Snon{ 155479697Snon int error, s; 155579697Snon 155679697Snon s = SCSI_LOW_SPLSCSI(); 155779697Snon slp->sl_flags &= ~HW_INACTIVE; 155879697Snon if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0) 155979697Snon { 156079697Snon slp->sl_flags |= HW_INACTIVE; 156179697Snon splx(s); 156279697Snon return error; 156379697Snon } 156479697Snon 156579697Snon slp->sl_timeout_count = 0; 156679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 156779697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 156879697Snon splx(s); 156979697Snon return 0; 157079697Snon} 157179697Snon 157279697Snon/************************************************************** 157379697Snon * scsi low log 157479697Snon **************************************************************/ 157579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 157692770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *); 157792770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int); 157892770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int); 157979697Snon 158079697Snonstatic void 158179697Snonscsi_low_msg_log_init(slmlp) 158279697Snon struct scsi_low_msg_log *slmlp; 158379697Snon{ 158479697Snon 158579697Snon slmlp->slml_ptr = 0; 158679697Snon} 158779697Snon 158879697Snonstatic void 158979697Snonscsi_low_msg_log_write(slmlp, datap, len) 159079697Snon struct scsi_low_msg_log *slmlp; 159179697Snon u_int8_t *datap; 159279697Snon int len; 159379697Snon{ 159479697Snon int ptr, ind; 159579697Snon 159679697Snon if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN) 159779697Snon return; 159879697Snon 159979697Snon ptr = slmlp->slml_ptr ++; 160079697Snon for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++) 160179697Snon slmlp->slml_msg[ptr].msg[ind] = datap[ind]; 160279697Snon for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++) 160379697Snon slmlp->slml_msg[ptr].msg[ind] = 0; 160479697Snon} 160579697Snon 160679697Snonstatic void 160779697Snonscsi_low_msg_log_show(slmlp, s, len) 160879697Snon struct scsi_low_msg_log *slmlp; 160979697Snon char *s; 161079697Snon int len; 161179697Snon{ 161279697Snon int ptr, ind; 161379697Snon 161479697Snon printf("%s: (%d) ", s, slmlp->slml_ptr); 161579697Snon for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++) 161679697Snon { 161779697Snon for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]); 161879697Snon ind ++) 161979697Snon { 162079697Snon printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]); 162179697Snon } 162279697Snon printf(">"); 162379697Snon } 162479697Snon printf("\n"); 162579697Snon} 162679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 162779697Snon 162879697Snon/************************************************************** 162967468Snon * power control 163067468Snon **************************************************************/ 163167468Snonstatic void 163267468Snonscsi_low_engage(arg) 163367468Snon void *arg; 163467468Snon{ 163567468Snon struct scsi_low_softc *slp = arg; 163679697Snon int s = SCSI_LOW_SPLSCSI(); 163767468Snon 163867468Snon switch (slp->sl_rstep) 163967468Snon { 164067468Snon case 0: 164167468Snon slp->sl_rstep ++; 164267468Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 164379697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 164479697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START); 164567468Snon break; 164667468Snon 164767468Snon case 1: 164867468Snon slp->sl_rstep ++; 164967468Snon slp->sl_flags &= ~HW_RESUME; 165067468Snon scsi_low_start(slp); 165167468Snon break; 165267468Snon 165367468Snon case 2: 165467468Snon break; 165567468Snon } 165667468Snon splx(s); 165767468Snon} 165867468Snon 165967468Snonstatic int 166067468Snonscsi_low_init(slp, flags) 166167468Snon struct scsi_low_softc *slp; 166267468Snon u_int flags; 166367468Snon{ 166479697Snon int rv = 0; 166567468Snon 166679697Snon slp->sl_flags |= HW_INITIALIZING; 166779697Snon 166879697Snon /* clear power control timeout */ 166967468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 167067468Snon { 167179697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 167279697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 167367468Snon slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); 167467468Snon slp->sl_active = 1; 167567468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 167667468Snon } 167767468Snon 167867468Snon /* reset current nexus */ 167967468Snon scsi_low_reset_nexus(slp, flags); 168067468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 168179697Snon { 168279697Snon rv = EBUSY; 168379697Snon goto out; 168479697Snon } 168567468Snon 168679697Snon if (flags != SCSI_LOW_RESTART_SOFT) 168779697Snon { 168879697Snon rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags)); 168979697Snon } 169067468Snon 169179697Snonout: 169279697Snon slp->sl_flags &= ~HW_INITIALIZING; 169379697Snon return rv; 169467468Snon} 169567468Snon 169667468Snon/************************************************************** 169767468Snon * allocate lun_info 169867468Snon **************************************************************/ 169967468Snonstatic struct lun_info * 170067468Snonscsi_low_alloc_li(ti, lun, alloc) 170167468Snon struct targ_info *ti; 170267468Snon int lun; 170367468Snon int alloc; 170467468Snon{ 170579697Snon struct scsi_low_softc *slp = ti->ti_sc; 170667468Snon struct lun_info *li; 170767468Snon 170867468Snon li = LIST_FIRST(&ti->ti_litab); 170967468Snon if (li != NULL) 171067468Snon { 171167468Snon if (li->li_lun == lun) 171267468Snon return li; 171367468Snon 171467468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 171567468Snon { 171667468Snon if (li->li_lun == lun) 171767468Snon { 171867468Snon LIST_REMOVE(li, lun_chain); 171967468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 172067468Snon return li; 172167468Snon } 172267468Snon } 172367468Snon } 172467468Snon 172567468Snon if (alloc == 0) 172667468Snon return li; 172767468Snon 172879697Snon li = SCSI_LOW_MALLOC(ti->ti_lunsize); 172967468Snon if (li == NULL) 1730106890Simp panic("no lun info mem"); 173167468Snon 173279697Snon SCSI_LOW_BZERO(li, ti->ti_lunsize); 173367468Snon li->li_lun = lun; 173467468Snon li->li_ti = ti; 173567468Snon 173679697Snon li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC | 173779697Snon SCSI_LOW_QTAG; 173879697Snon li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 173979697Snon li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID; 174079697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 174179697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 174279697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 174379697Snon 174479697Snon li->li_qtagbits = (u_int) -1; 174579697Snon 174679697Snon TAILQ_INIT(&li->li_discq); 174767468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 174867468Snon 174979697Snon /* host specific structure initialization per lun */ 175079697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 175179697Snon (*slp->sl_funcs->scsi_low_lun_init) 175279697Snon (slp, ti, li, SCSI_LOW_INFO_ALLOC); 175379697Snon scsi_low_calcf_lun(li); 175467468Snon return li; 175567468Snon} 175667468Snon 175767468Snon/************************************************************** 175867468Snon * allocate targ_info 175967468Snon **************************************************************/ 176067468Snonstatic struct targ_info * 176179697Snonscsi_low_alloc_ti(slp, targ) 176267468Snon struct scsi_low_softc *slp; 176379697Snon int targ; 176467468Snon{ 176567468Snon struct targ_info *ti; 176667468Snon 176771999Sphk if (TAILQ_FIRST(&slp->sl_titab) == NULL) 176867468Snon TAILQ_INIT(&slp->sl_titab); 176967468Snon 177079697Snon ti = SCSI_LOW_MALLOC(slp->sl_targsize); 177167468Snon if (ti == NULL) 1772106890Simp panic("%s short of memory", slp->sl_xname); 177367468Snon 177479697Snon SCSI_LOW_BZERO(ti, slp->sl_targsize); 177567468Snon ti->ti_id = targ; 177667468Snon ti->ti_sc = slp; 177767468Snon 177867468Snon slp->sl_ti[targ] = ti; 177967468Snon TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); 178067468Snon LIST_INIT(&ti->ti_litab); 178167468Snon 178279697Snon ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 178379697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 178479697Snon ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID; 178579697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 178679697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 178779697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 178873025Snon 178979697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 179079697Snon { 179179697Snon (*slp->sl_funcs->scsi_low_targ_init) 179279697Snon (slp, ti, SCSI_LOW_INFO_ALLOC); 179379697Snon } 179479697Snon scsi_low_calcf_target(ti); 179567468Snon return ti; 179667468Snon} 179767468Snon 179867468Snonstatic void 179967468Snonscsi_low_free_ti(slp) 180067468Snon struct scsi_low_softc *slp; 180167468Snon{ 180267468Snon struct targ_info *ti, *tib; 180367468Snon struct lun_info *li, *nli; 180467468Snon 180571999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) 180667468Snon { 180767468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) 180867468Snon { 180979697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 181079697Snon { 181179697Snon (*slp->sl_funcs->scsi_low_lun_init) 181279697Snon (slp, ti, li, SCSI_LOW_INFO_DEALLOC); 181379697Snon } 181467468Snon nli = LIST_NEXT(li, lun_chain); 181579697Snon SCSI_LOW_FREE(li); 181667468Snon } 181779697Snon 181879697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 181979697Snon { 182079697Snon (*slp->sl_funcs->scsi_low_targ_init) 182179697Snon (slp, ti, SCSI_LOW_INFO_DEALLOC); 182279697Snon } 182379697Snon tib = TAILQ_NEXT(ti, ti_chain); 182479697Snon SCSI_LOW_FREE(ti); 182567468Snon } 182667468Snon} 182767468Snon 182867468Snon/************************************************************** 182967468Snon * timeout 183067468Snon **************************************************************/ 183167468Snonvoid 183279697Snonscsi_low_bus_idle(slp) 183379697Snon struct scsi_low_softc *slp; 183479697Snon{ 183579697Snon 183679697Snon slp->sl_retry_sel = 0; 183779697Snon if (slp->sl_Tnexus == NULL) 183879697Snon scsi_low_start(slp); 183979697Snon} 184079697Snon 184179697Snonstatic void 184267468Snonscsi_low_timeout(arg) 184367468Snon void *arg; 184467468Snon{ 184567468Snon struct scsi_low_softc *slp = arg; 184679697Snon int s; 184779697Snon 184879697Snon s = SCSI_LOW_SPLSCSI(); 184979697Snon (void) scsi_low_timeout_check(slp); 185079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 185179697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 185279697Snon splx(s); 185379697Snon} 185479697Snon 185579697Snonstatic int 185679697Snonscsi_low_timeout_check(slp) 185779697Snon struct scsi_low_softc *slp; 185879697Snon{ 185967468Snon struct targ_info *ti; 186079697Snon struct lun_info *li; 186167468Snon struct slccb *cb = NULL; /* XXX */ 186267468Snon 186379697Snon /* selection restart */ 186479697Snon if (slp->sl_retry_sel != 0) 186567468Snon { 186679697Snon slp->sl_retry_sel = 0; 186779697Snon if (slp->sl_Tnexus != NULL) 186879697Snon goto step1; 186967468Snon 187079697Snon cb = TAILQ_FIRST(&slp->sl_start); 187179697Snon if (cb == NULL) 187279697Snon goto step1; 187379697Snon 187479697Snon if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY) 187567468Snon { 187679697Snon cb->ccb_flags |= CCB_NORETRY; 187779697Snon cb->ccb_error |= SELTIMEOUTIO; 187879697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 1879106890Simp panic("%s: ccb not finished", slp->sl_xname); 188067468Snon } 188179697Snon 188279697Snon if (slp->sl_Tnexus == NULL) 188379697Snon scsi_low_start(slp); 188467468Snon } 188579697Snon 188679697Snon /* call hardware timeout */ 188779697Snonstep1: 188879697Snon if (slp->sl_funcs->scsi_low_timeout != NULL) 188967468Snon { 189079697Snon (*slp->sl_funcs->scsi_low_timeout) (slp); 189179697Snon } 189279697Snon 189379697Snon if (slp->sl_timeout_count ++ < 189479697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ) 189579697Snon return 0; 189679697Snon 189779697Snon slp->sl_timeout_count = 0; 189879697Snon if (slp->sl_nio > 0) 189979697Snon { 190079697Snon if ((cb = slp->sl_Qnexus) != NULL) 190167468Snon { 190267468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 190367468Snon if (cb->ccb_tc < 0) 190467468Snon goto bus_reset; 190567468Snon } 190679697Snon else if (slp->sl_disc == 0) 190767468Snon { 190879697Snon if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL) 190979697Snon return 0; 191067468Snon 191179697Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 191279697Snon if (cb->ccb_tc < 0) 191379697Snon goto bus_reset; 191479697Snon } 191579697Snon else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 191679697Snon ti = TAILQ_NEXT(ti, ti_chain)) 191779697Snon { 191879697Snon if (ti->ti_disc == 0) 191979697Snon continue; 192067468Snon 192179697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 192279697Snon li = LIST_NEXT(li, lun_chain)) 192367468Snon { 192479697Snon for (cb = TAILQ_FIRST(&li->li_discq); 192579697Snon cb != NULL; 192679697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 192779697Snon { 192879697Snon cb->ccb_tc -= 192979697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 193079697Snon if (cb->ccb_tc < 0) 193179697Snon goto bus_reset; 193279697Snon } 193367468Snon } 193467468Snon } 193579697Snon 193667468Snon } 193779697Snon else if ((slp->sl_flags & HW_POWERCTRL) != 0) 193879697Snon { 193979697Snon if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) 194079697Snon return 0; 194167468Snon 194279697Snon if (slp->sl_active != 0) 194379697Snon { 194479697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 194579697Snon slp->sl_active = 0; 194679697Snon return 0; 194779697Snon } 194867468Snon 194979697Snon slp->sl_powc --; 195079697Snon if (slp->sl_powc < 0) 195179697Snon { 195279697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 195379697Snon slp->sl_flags |= HW_POWDOWN; 195479697Snon (*slp->sl_funcs->scsi_low_power) 195579697Snon (slp, SCSI_LOW_POWDOWN); 195679697Snon } 195779697Snon } 195879697Snon return 0; 195967468Snon 196067468Snonbus_reset: 196167468Snon cb->ccb_error |= TIMEOUTIO; 196279697Snon printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb); 196367468Snon scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); 196467468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 196567468Snon scsi_low_start(slp); 196679697Snon return ERESTART; 196767468Snon} 196867468Snon 196967468Snon 197079697Snonstatic int 197179697Snonscsi_low_abort_ccb(slp, cb) 197279697Snon struct scsi_low_softc *slp; 197379697Snon struct slccb *cb; 197479697Snon{ 197579697Snon struct targ_info *ti; 197679697Snon struct lun_info *li; 197779697Snon u_int msg; 197867468Snon 197979697Snon if (cb == NULL) 198079697Snon return EINVAL; 198179697Snon if ((cb->ccb_omsgoutflag & 198279697Snon (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0) 198379697Snon return EBUSY; 198467468Snon 198579697Snon ti = cb->ti; 198679697Snon li = cb->li; 198779697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 198879697Snon msg = SCSI_LOW_MSG_ABORT; 198979697Snon else 199079697Snon msg = SCSI_LOW_MSG_ABORT_QTAG; 199167468Snon 199279697Snon cb->ccb_error |= ABORTIO; 199379697Snon cb->ccb_flags |= CCB_NORETRY; 199479697Snon scsi_low_ccb_message_assert(cb, msg); 199567468Snon 199679697Snon if (cb == slp->sl_Qnexus) 199779697Snon { 199879697Snon scsi_low_assert_msg(slp, ti, msg, 1); 199979697Snon } 200079697Snon else if ((cb->ccb_flags & CCB_DISCQ) != 0) 200179697Snon { 200279697Snon if (scsi_low_revoke_ccb(slp, cb, 0) == NULL) 2003106890Simp panic("%s: revoked ccb done", slp->sl_xname); 200467468Snon 200579697Snon cb->ccb_flags |= CCB_STARTQ; 200679697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 200767468Snon 200879697Snon if (slp->sl_Tnexus == NULL) 200979697Snon scsi_low_start(slp); 201079697Snon } 201179697Snon else 201279697Snon { 201379697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 2014106890Simp panic("%s: revoked ccb retried", slp->sl_xname); 201579697Snon } 201679697Snon return 0; 201767468Snon} 201867468Snon 201979697Snon/************************************************************** 202079697Snon * Generic SCSI INTERFACE 202179697Snon **************************************************************/ 202267468Snonint 202379697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize) 202467468Snon struct scsi_low_softc *slp; 202579697Snon int openings, ntargs, nluns, targsize, lunsize; 202667468Snon{ 202767468Snon struct targ_info *ti; 202867468Snon struct lun_info *li; 202979697Snon int s, i, nccb, rv; 203067468Snon 203179697Snon#ifdef SCSI_LOW_INTERFACE_XS 203279697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs; 203379697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 203479697Snon#ifdef SCSI_LOW_INTERFACE_CAM 203579697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam; 203679697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 203779697Snon 203879697Snon if (slp->sl_osdep_fp == NULL) 2039106890Simp panic("scsi_low: interface not spcified"); 204079697Snon 204167468Snon if (ntargs > SCSI_LOW_NTARGETS) 204267468Snon { 204367468Snon printf("scsi_low: %d targets are too large\n", ntargs); 204467468Snon printf("change kernel options SCSI_LOW_NTARGETS"); 204579697Snon return EINVAL; 204667468Snon } 204767468Snon 204879697Snon if (openings <= 0) 204979697Snon slp->sl_openings = (SCSI_LOW_NCCB / ntargs); 205079697Snon else 205179697Snon slp->sl_openings = openings; 205279697Snon slp->sl_ntargs = ntargs; 205379697Snon slp->sl_nluns = nluns; 205479697Snon slp->sl_max_retry = SCSI_LOW_MAX_RETRY; 205567468Snon 205679697Snon if (lunsize < sizeof(struct lun_info)) 205779697Snon lunsize = sizeof(struct lun_info); 205879697Snon 205979697Snon if (targsize < sizeof(struct targ_info)) 206079697Snon targsize = sizeof(struct targ_info); 206179697Snon 206279697Snon slp->sl_targsize = targsize; 206367468Snon for (i = 0; i < ntargs; i ++) 206467468Snon { 206579697Snon ti = scsi_low_alloc_ti(slp, i); 206679697Snon ti->ti_lunsize = lunsize; 206767468Snon li = scsi_low_alloc_li(ti, 0, 1); 206867468Snon } 206967468Snon 207067468Snon /* initialize queue */ 207179697Snon nccb = openings * ntargs; 207267468Snon if (nccb >= SCSI_LOW_NCCB || nccb <= 0) 207367468Snon nccb = SCSI_LOW_NCCB; 207467468Snon scsi_low_init_ccbque(nccb); 207567468Snon TAILQ_INIT(&slp->sl_start); 207667468Snon 207779697Snon /* call os depend attach */ 207879697Snon s = SCSI_LOW_SPLSCSI(); 207979697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp); 208079697Snon if (rv != 0) 208179697Snon { 208279697Snon splx(s); 208379697Snon printf("%s: scsi_low_attach: osdep attach failed\n", 208479697Snon slp->sl_xname); 208579697Snon return EINVAL; 208679697Snon } 208767468Snon 208879697Snon /* check hardware */ 208979697Snon SCSI_LOW_DELAY(1000); /* wait for 1ms */ 209079697Snon if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) 209179697Snon { 209279697Snon splx(s); 209379697Snon printf("%s: scsi_low_attach: initialization failed\n", 209479697Snon slp->sl_xname); 209579697Snon return EINVAL; 209679697Snon } 209767468Snon 209867468Snon /* start watch dog */ 209979697Snon slp->sl_timeout_count = 0; 210079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 210179697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 210279697Snon LIST_INSERT_HEAD(&sl_tab, slp, sl_chain); 210367468Snon 210479697Snon /* fake call */ 210579697Snon scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL)); 210667468Snon 210779697Snon#ifdef SCSI_LOW_START_UP_CHECK 210879697Snon /* probing devices */ 210979697Snon scsi_low_start_up(slp); 211079697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 211167468Snon 211279697Snon /* call os depend attach done*/ 211379697Snon (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp); 211479697Snon splx(s); 211579697Snon return 0; 211667468Snon} 211767468Snon 211867468Snonint 211967468Snonscsi_low_dettach(slp) 212067468Snon struct scsi_low_softc *slp; 212167468Snon{ 212279697Snon int s, rv; 212367468Snon 212479697Snon s = SCSI_LOW_SPLSCSI(); 212579697Snon if (scsi_low_is_busy(slp) != 0) 212679697Snon { 212779697Snon splx(s); 212867468Snon return EBUSY; 212979697Snon } 213067468Snon 213179697Snon scsi_low_deactivate(slp); 213267468Snon 213379697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp); 213479697Snon if (rv != 0) 213579697Snon { 213679697Snon splx(s); 213779697Snon return EBUSY; 213879697Snon } 213967468Snon 214067468Snon scsi_low_free_ti(slp); 214179697Snon LIST_REMOVE(slp, sl_chain); 214279697Snon splx(s); 214367468Snon return 0; 214467468Snon} 214567468Snon 214679697Snon/************************************************************** 214779697Snon * Generic enqueue 214879697Snon **************************************************************/ 214979697Snonstatic int 215079697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg) 215179697Snon struct scsi_low_softc *slp; 215267468Snon struct targ_info *ti; 215367468Snon struct lun_info *li; 215467468Snon struct slccb *cb; 215579697Snon u_int flags, msg; 215679697Snon{ 215767468Snon 215879697Snon cb->ti = ti; 215979697Snon cb->li = li; 216067468Snon 216179697Snon scsi_low_ccb_message_assert(cb, msg); 216267468Snon 216379697Snon cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG; 216479697Snon scsi_low_alloc_qtag(cb); 216567468Snon 216679697Snon cb->ccb_flags = flags | CCB_STARTQ; 216779697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 216879697Snon cb->ccb_error |= PENDINGIO; 216979697Snon 217079697Snon if ((flags & CCB_URGENT) != 0) 217179697Snon { 217279697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 217379697Snon } 217479697Snon else 217579697Snon { 217667468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 217779697Snon } 217867468Snon 217979697Snon slp->sl_nio ++; 218067468Snon 218179697Snon if (slp->sl_Tnexus == NULL) 218279697Snon scsi_low_start(slp); 218379697Snon return 0; 218479697Snon} 218567468Snon 218679697Snonstatic int 218779697Snonscsi_low_message_enqueue(slp, ti, li, flags) 218879697Snon struct scsi_low_softc *slp; 218979697Snon struct targ_info *ti; 219079697Snon struct lun_info *li; 219179697Snon u_int flags; 219279697Snon{ 219379697Snon struct slccb *cb; 219479697Snon u_int tmsgflags; 219567468Snon 219679697Snon tmsgflags = ti->ti_setup_msg; 219779697Snon ti->ti_setup_msg = 0; 219867468Snon 219979697Snon flags |= CCB_NORETRY; 220079697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 220179697Snon return ENOMEM; 220267468Snon 220379697Snon cb->osdep = NULL; 220479697Snon cb->bp = NULL; 220579697Snon scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags); 220679697Snon return 0; 220779697Snon} 220867468Snon 220979697Snon/************************************************************** 221079697Snon * Generic Start & Done 221179697Snon **************************************************************/ 221279697Snon#define SLSC_MODE_SENSE_SHORT 0x1a 221379697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0}; 221479697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0, 221579697Snon sizeof(struct scsi_low_mode_sense_data), 0}; 221679697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0, 221779697Snon sizeof(struct scsi_low_inq_data), 0}; 221879697Snonstatic u_int8_t unit_ready_cmd[6]; 221992770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 222092770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 222192770Salfredstatic int scsi_low_resume(struct scsi_low_softc *); 222279697Snon 222379697Snonstatic void 222479697Snonscsi_low_unit_ready_cmd(cb) 222579697Snon struct slccb *cb; 222679697Snon{ 222779697Snon 222879697Snon cb->ccb_scp.scp_cmd = unit_ready_cmd; 222979697Snon cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); 223079697Snon cb->ccb_scp.scp_datalen = 0; 223179697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 223279697Snon cb->ccb_tcmax = 15; 223367468Snon} 223479697Snon 223567468Snonstatic int 223679697Snonscsi_low_sense_abort_start(slp, ti, li, cb) 223779697Snon struct scsi_low_softc *slp; 223867468Snon struct targ_info *ti; 223979697Snon struct lun_info *li; 224067468Snon struct slccb *cb; 224179697Snon{ 224267468Snon 224379697Snon cb->ccb_scp.scp_cmdlen = 6; 224479697Snon SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen); 224579697Snon cb->ccb_scsi_cmd[0] = REQUEST_SENSE; 224679697Snon cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense); 224779697Snon cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd; 224879697Snon cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; 224979697Snon cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); 225079697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 225179697Snon cb->ccb_tcmax = 15; 225279697Snon scsi_low_ccb_message_clear(cb); 225379697Snon if ((cb->ccb_flags & CCB_CLEARQ) != 0) 225467468Snon { 225579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 225667468Snon } 225779697Snon else 225879697Snon { 225979697Snon SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense)); 226079697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 226179697Snon scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0); 226279697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 226379697Snon } 226467468Snon 226579697Snon return SCSI_LOW_START_NO_QTAG; 226679697Snon} 226767468Snon 226879697Snonstatic int 226979697Snonscsi_low_setup_start(slp, ti, li, cb) 227079697Snon struct scsi_low_softc *slp; 227179697Snon struct targ_info *ti; 227279697Snon struct lun_info *li; 227379697Snon struct slccb *cb; 227479697Snon{ 227567468Snon 227679697Snon switch(li->li_state) 227779697Snon { 227879697Snon case SCSI_LOW_LUN_SLEEP: 227979697Snon scsi_low_unit_ready_cmd(cb); 228079697Snon break; 228167468Snon 228279697Snon case SCSI_LOW_LUN_START: 228379697Snon cb->ccb_scp.scp_cmd = ss_cmd; 228479697Snon cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); 228579697Snon cb->ccb_scp.scp_datalen = 0; 228679697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 228779697Snon cb->ccb_tcmax = 30; 228879697Snon break; 228967468Snon 229079697Snon case SCSI_LOW_LUN_INQ: 229179697Snon cb->ccb_scp.scp_cmd = inq_cmd; 229279697Snon cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd); 229379697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq; 229479697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_inq); 229579697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 229679697Snon cb->ccb_tcmax = 15; 229779697Snon break; 229867468Snon 229979697Snon case SCSI_LOW_LUN_MODEQ: 230079697Snon cb->ccb_scp.scp_cmd = sms_cmd; 230179697Snon cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd); 230279697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms; 230379697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_sms); 230479697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 230579697Snon cb->ccb_tcmax = 15; 230679697Snon return SCSI_LOW_START_QTAG; 230767468Snon 230879697Snon default: 2309106890Simp panic("%s: no setup phase", slp->sl_xname); 231067468Snon } 231167468Snon 231279697Snon return SCSI_LOW_START_NO_QTAG; 231367468Snon} 231467468Snon 231579697Snonstatic int 231679697Snonscsi_low_resume(slp) 231779697Snon struct scsi_low_softc *slp; 231867468Snon{ 231967468Snon 232079697Snon if (slp->sl_flags & HW_RESUME) 232179697Snon return EJUSTRETURN; 232279697Snon slp->sl_flags &= ~HW_POWDOWN; 232379697Snon if (slp->sl_funcs->scsi_low_power != NULL) 232479697Snon { 232579697Snon slp->sl_flags |= HW_RESUME; 232679697Snon slp->sl_rstep = 0; 232779697Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 232879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 232979697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, 233079697Snon SCSI_LOW_TIMEOUT_START); 233179697Snon return EJUSTRETURN; 233279697Snon } 233379697Snon return 0; 233467468Snon} 233567468Snon 233667468Snonstatic void 233767468Snonscsi_low_start(slp) 233867468Snon struct scsi_low_softc *slp; 233967468Snon{ 234067468Snon struct targ_info *ti; 234167468Snon struct lun_info *li; 234267468Snon struct slccb *cb; 234367468Snon int rv; 234467468Snon 234579697Snon /* check hardware exists or under initializations ? */ 234679697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 234767468Snon return; 234867468Snon 234967468Snon /* check hardware power up ? */ 235067468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 235167468Snon { 235267468Snon slp->sl_active ++; 235367468Snon if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) 235467468Snon { 235579697Snon if (scsi_low_resume(slp) == EJUSTRETURN) 235667468Snon return; 235767468Snon } 235867468Snon } 235967468Snon 236067468Snon /* setup nexus */ 236167468Snon#ifdef SCSI_LOW_DIAGNOSTIC 236279697Snon if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus) 236367468Snon { 236467468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 2365106890Simp panic("%s: inconsistent", slp->sl_xname); 236667468Snon } 236767468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 236867468Snon 236979697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 237079697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 237167468Snon { 237267468Snon li = cb->li; 237379697Snon 237479697Snon if (li->li_disc == 0) 237579697Snon { 237667468Snon goto scsi_low_cmd_start; 237779697Snon } 237879697Snon else if (li->li_nqio > 0) 237979697Snon { 238079697Snon if (li->li_nqio < li->li_maxnqio || 238179697Snon (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 238279697Snon goto scsi_low_cmd_start; 238379697Snon } 238467468Snon } 238567468Snon return; 238667468Snon 238767468Snonscsi_low_cmd_start: 238879697Snon cb->ccb_flags &= ~CCB_STARTQ; 238979697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 239079697Snon ti = cb->ti; 239167468Snon 239267468Snon /* clear all error flag bits (for restart) */ 239367468Snon cb->ccb_error = 0; 239479697Snon cb->ccb_datalen = -1; 239579697Snon cb->ccb_scp.scp_status = ST_UNKNOWN; 239667468Snon 239767468Snon /* setup nexus pointer */ 239879697Snon slp->sl_Qnexus = cb; 239979697Snon slp->sl_Lnexus = li; 240079697Snon slp->sl_Tnexus = ti; 240167468Snon 240267468Snon /* initialize msgsys */ 240367468Snon scsi_low_init_msgsys(slp, ti); 240467468Snon 240579697Snon /* exec cmd */ 240679697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 240767468Snon { 240879697Snon /* CA state or forced abort */ 240979697Snon rv = scsi_low_sense_abort_start(slp, ti, li, cb); 241067468Snon } 241179697Snon else if (li->li_state >= SCSI_LOW_LUN_OK) 241267468Snon { 241379697Snon cb->ccb_flags &= ~CCB_INTERNAL; 241479697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb); 241579697Snon if (cb->ccb_msgoutflag != 0) 241679697Snon { 241779697Snon scsi_low_ccb_message_exec(slp, cb); 241879697Snon } 241967468Snon } 242079697Snon else 242167468Snon { 242279697Snon cb->ccb_flags |= CCB_INTERNAL; 242379697Snon rv = scsi_low_setup_start(slp, ti, li, cb); 242479697Snon } 242567468Snon 242679697Snon /* allocate qtag */ 242779697Snon#define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC) 242867468Snon 242979697Snon if (rv == SCSI_LOW_START_QTAG && 243079697Snon (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK && 243179697Snon li->li_maxnqio > 0) 243279697Snon { 243379697Snon u_int qmsg; 243467468Snon 243579697Snon scsi_low_activate_qtag(cb); 243679697Snon if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 243779697Snon SCSI_LOW_CMD_ORDERED_QTAG) != 0) 243879697Snon qmsg = SCSI_LOW_MSG_ORDERED_QTAG; 243979697Snon else if ((cb->ccb_flags & CCB_URGENT) != 0) 244079697Snon qmsg = SCSI_LOW_MSG_HEAD_QTAG; 244179697Snon else 244279697Snon qmsg = SCSI_LOW_MSG_SIMPLE_QTAG; 244379697Snon scsi_low_assert_msg(slp, ti, qmsg, 0); 244467468Snon } 244567468Snon 244667468Snon /* timeout */ 244767468Snon if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 244867468Snon cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 244967468Snon cb->ccb_tc = cb->ccb_tcmax; 245067468Snon 245167468Snon /* setup saved scsi data pointer */ 245267468Snon cb->ccb_sscp = cb->ccb_scp; 245367468Snon 245467468Snon /* setup current scsi pointer */ 245567468Snon slp->sl_scp = cb->ccb_sscp; 245667468Snon slp->sl_error = cb->ccb_error; 245767468Snon 245879697Snon /* assert always an identify msg */ 245979697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); 246079697Snon 246179697Snon /* debug section */ 246279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 246379697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 246479697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 246579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 246679697Snon 246767468Snon /* selection start */ 246879697Snon slp->sl_selid = cb; 246967468Snon rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); 247067468Snon if (rv == SCSI_LOW_START_OK) 247167468Snon { 247267468Snon#ifdef SCSI_LOW_STATICS 247367468Snon scsi_low_statics.nexus_win ++; 247467468Snon#endif /* SCSI_LOW_STATICS */ 247567468Snon return; 247667468Snon } 247767468Snon 247879697Snon scsi_low_arbit_fail(slp, cb); 247967468Snon#ifdef SCSI_LOW_STATICS 248067468Snon scsi_low_statics.nexus_fail ++; 248167468Snon#endif /* SCSI_LOW_STATICS */ 248267468Snon} 248367468Snon 248467468Snonvoid 248579697Snonscsi_low_arbit_fail(slp, cb) 248667468Snon struct scsi_low_softc *slp; 248779697Snon struct slccb *cb; 248879697Snon{ 248979697Snon struct targ_info *ti = cb->ti; 249079697Snon 249179697Snon scsi_low_deactivate_qtag(cb); 249279697Snon scsi_low_ccb_message_retry(cb); 249379697Snon cb->ccb_flags |= CCB_STARTQ; 249479697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 249579697Snon 249679697Snon scsi_low_bus_release(slp, ti); 249779697Snon 249879697Snon cb->ccb_selrcnt ++; 249979697Snon if (slp->sl_disc == 0) 250079697Snon { 250179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 250279697Snon printf("%s: try selection again\n", slp->sl_xname); 250379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 250479697Snon slp->sl_retry_sel = 1; 250579697Snon } 250679697Snon} 250779697Snon 250879697Snonstatic void 250979697Snonscsi_low_bus_release(slp, ti) 251079697Snon struct scsi_low_softc *slp; 251167468Snon struct targ_info *ti; 251267468Snon{ 251367468Snon 251479697Snon if (ti->ti_disc > 0) 251579697Snon { 251679697Snon SCSI_LOW_SETUP_PHASE(ti, PH_DISC); 251779697Snon } 251879697Snon else 251979697Snon { 252079697Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 252179697Snon } 252279697Snon 252367468Snon /* clear all nexus pointer */ 252479697Snon slp->sl_Qnexus = NULL; 252579697Snon slp->sl_Lnexus = NULL; 252679697Snon slp->sl_Tnexus = NULL; 252767468Snon 252867468Snon /* clear selection assert */ 252967468Snon slp->sl_selid = NULL; 253067468Snon 253167468Snon /* clear nexus data */ 253267468Snon slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; 253379697Snon 253479697Snon /* clear phase change counter */ 253579697Snon slp->sl_ph_count = 0; 253667468Snon} 253767468Snon 253867468Snonstatic int 253979697Snonscsi_low_setup_done(slp, cb) 254067468Snon struct scsi_low_softc *slp; 254167468Snon struct slccb *cb; 254267468Snon{ 254367468Snon struct targ_info *ti; 254467468Snon struct lun_info *li; 254567468Snon 254667468Snon ti = cb->ti; 254767468Snon li = cb->li; 254879697Snon 254979697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 255067468Snon { 255179697Snon cb->ccb_error |= ABORTIO; 255279697Snon return SCSI_LOW_DONE_COMPLETE; 255379697Snon } 255479697Snon 255579697Snon /* XXX: special huck for selection timeout */ 255679697Snon if (li->li_state == SCSI_LOW_LUN_SLEEP && 255779697Snon (cb->ccb_error & SELTIMEOUTIO) != 0) 255879697Snon { 255979697Snon cb->ccb_error |= ABORTIO; 256079697Snon return SCSI_LOW_DONE_COMPLETE; 256179697Snon } 256279697Snon 256379697Snon switch(li->li_state) 256479697Snon { 256579697Snon case SCSI_LOW_LUN_INQ: 256679697Snon if (cb->ccb_error != 0) 256767468Snon { 256879697Snon li->li_diskflags &= 256979697Snon ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG); 257079697Snon if (li->li_lun > 0) 257179697Snon goto resume; 257279697Snon ti->ti_diskflags &= 257379697Snon ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE); 257467468Snon } 257579697Snon else if ((li->li_inq.sd_version & 7) >= 2 || 257679697Snon (li->li_inq.sd_len >= 4)) 257767468Snon { 257879697Snon if ((li->li_inq.sd_support & 0x2) == 0) 257979697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 258079697Snon if ((li->li_inq.sd_support & 0x8) == 0) 258179697Snon li->li_diskflags &= ~SCSI_LOW_DISK_LINK; 258279697Snon if (li->li_lun > 0) 258379697Snon goto resume; 258479697Snon if ((li->li_inq.sd_support & 0x10) == 0) 258579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC; 258679697Snon if ((li->li_inq.sd_support & 0x20) == 0) 258779697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16; 258879697Snon if ((li->li_inq.sd_support & 0x40) == 0) 258979697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32; 259079697Snon } 259179697Snon else 259279697Snon { 259379697Snon li->li_diskflags &= 259479697Snon ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK); 259579697Snon if (li->li_lun > 0) 259679697Snon goto resume; 259779697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE; 259879697Snon } 259979697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID; 260079697Snonresume: 260179697Snon scsi_low_calcf_target(ti); 260279697Snon scsi_low_calcf_lun(li); 260379697Snon break; 260479697Snon 260579697Snon case SCSI_LOW_LUN_MODEQ: 260679697Snon if (cb->ccb_error != 0) 260779697Snon { 260879697Snon if (cb->ccb_error & SENSEIO) 260967468Snon { 261079697Snon#ifdef SCSI_LOW_DEBUG 261179697Snon if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) 261279697Snon { 261379697Snon printf("SENSE: [%x][%x][%x][%x][%x]\n", 261479697Snon (u_int) cb->ccb_sense.error_code, 261579697Snon (u_int) cb->ccb_sense.segment, 261679697Snon (u_int) cb->ccb_sense.flags, 261779697Snon (u_int) cb->ccb_sense.add_sense_code, 261879697Snon (u_int) cb->ccb_sense.add_sense_code_qual); 261979697Snon } 262079697Snon#endif /* SCSI_LOW_DEBUG */ 262167468Snon } 262279697Snon else 262379697Snon { 262479697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 262579697Snon } 262679697Snon } 262779697Snon else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a) 262879697Snon { 262979697Snon if (li->li_sms.sms_cmp.cmp_qc & 0x02) 263079697Snon li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR; 263179697Snon else 263279697Snon li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR; 263379697Snon if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0) 263479697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 263579697Snon } 263679697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID; 263779697Snon scsi_low_calcf_lun(li); 263879697Snon break; 263967468Snon 264079697Snon default: 264179697Snon break; 264279697Snon } 264379697Snon 264479697Snon li->li_state ++; 264579697Snon if (li->li_state == SCSI_LOW_LUN_OK) 264679697Snon { 264779697Snon scsi_low_calcf_target(ti); 264879697Snon scsi_low_calcf_lun(li); 264979697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID && 265079697Snon (slp->sl_show_result & SHOW_CALCF_RES) != 0) 265179697Snon { 265279697Snon scsi_low_calcf_show(li); 265379697Snon } 265479697Snon } 265579697Snon 265679697Snon cb->ccb_rcnt --; 265779697Snon return SCSI_LOW_DONE_RETRY; 265879697Snon} 265979697Snon 266079697Snonstatic int 266179697Snonscsi_low_done(slp, cb) 266279697Snon struct scsi_low_softc *slp; 266379697Snon struct slccb *cb; 266479697Snon{ 266579697Snon int rv; 266679697Snon 266779697Snon if (cb->ccb_error == 0) 266879697Snon { 266979697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 267079697Snon { 267179697Snon#ifdef SCSI_LOW_QCLEAR_AFTER_CA 267279697Snon /* XXX: 267379697Snon * SCSI-2 draft suggests 267479697Snon * page 0x0a QErr bit determins if 267579697Snon * the target aborts or continues 267679697Snon * the queueing io's after CA state resolved. 267779697Snon * However many targets seem not to support 267879697Snon * the page 0x0a. Thus we should manually clear the 267979697Snon * queuing io's after CA state. 268079697Snon */ 268179697Snon if ((cb->ccb_flags & CCB_CLEARQ) == 0) 268267468Snon { 268379697Snon cb->ccb_rcnt --; 268479697Snon cb->ccb_flags |= CCB_CLEARQ; 268579697Snon goto retry; 268679697Snon } 268779697Snon#endif /* SCSI_LOW_QCLEAR_AFTER_CA */ 268879697Snon 268979697Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 269079697Snon cb->ccb_error |= (SENSEIO | ABORTIO); 269179697Snon cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ); 269279697Snon } 269379697Snon else switch (cb->ccb_sscp.scp_status) 269479697Snon { 269579697Snon case ST_GOOD: 269679697Snon case ST_MET: 269779697Snon case ST_INTERGOOD: 269879697Snon case ST_INTERMET: 269979697Snon if (cb->ccb_datalen == 0 || 270079697Snon cb->ccb_scp.scp_datalen == 0) 270167468Snon break; 270267468Snon 270379697Snon if (cb->ccb_scp.scp_cmdlen > 0 && 270479697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 270579697Snon SCSI_LOW_CMD_RESIDUAL_CHK) == 0) 270679697Snon break; 270779697Snon 270867468Snon cb->ccb_error |= PDMAERR; 270967468Snon break; 271067468Snon 271179697Snon case ST_BUSY: 271279697Snon case ST_QUEFULL: 271379697Snon cb->ccb_error |= (BUSYERR | STATERR); 271479697Snon break; 271579697Snon 271679697Snon case ST_CONFLICT: 271779697Snon cb->ccb_error |= (STATERR | ABORTIO); 271879697Snon break; 271979697Snon 272067468Snon case ST_CHKCOND: 272179697Snon case ST_CMDTERM: 272279697Snon if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL)) 272379697Snon { 272479697Snon cb->ccb_rcnt --; 272573025Snon cb->ccb_flags |= CCB_SENSE; 272673025Snon goto retry; 272773025Snon } 272879697Snon cb->ccb_error |= (UACAERR | STATERR | ABORTIO); 272973025Snon break; 273067468Snon 273179697Snon case ST_UNKNOWN: 273267468Snon default: 273367468Snon cb->ccb_error |= FATALIO; 273467468Snon break; 273567468Snon } 273667468Snon } 273767468Snon else 273867468Snon { 273979697Snon if (cb->ccb_flags & CCB_SENSE) 274067468Snon { 274179697Snon cb->ccb_error |= (SENSEERR | ABORTIO); 274267468Snon } 274379697Snon cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE); 274479697Snon } 274567468Snon 274679697Snon /* internal ccb */ 274779697Snon if ((cb->ccb_flags & CCB_INTERNAL) != 0) 274879697Snon { 274979697Snon if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY) 275079697Snon goto retry; 275167468Snon } 275267468Snon 275379697Snon /* check a ccb msgout flag */ 275479697Snon if (cb->ccb_omsgoutflag != 0) 275567468Snon { 275679697Snon#define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \ 275779697Snon SCSI_LOW_MSG_ABORT_QTAG | \ 275879697Snon SCSI_LOW_MSG_CLEAR_QTAG | \ 275979697Snon SCSI_LOW_MSG_TERMIO) 276079697Snon 276179697Snon if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0) 276267468Snon { 276379697Snon cb->ccb_error |= ABORTIO; 276467468Snon } 276567468Snon } 276667468Snon 276779697Snon /* call OS depend done */ 276879697Snon if (cb->osdep != NULL) 276967468Snon { 277079697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb); 277179697Snon if (rv == EJUSTRETURN) 277279697Snon goto retry; 277367468Snon } 277479697Snon else if (cb->ccb_error != 0) 277567468Snon { 277679697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 277779697Snon cb->ccb_error |= ABORTIO; 277879697Snon 277979697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 278079697Snon (cb->ccb_error & ABORTIO) == 0) 278167468Snon goto retry; 278267468Snon } 278379697Snon 278479697Snon /* free our target */ 278579697Snon#ifdef SCSI_LOW_DEBUG 278679697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 278767468Snon { 278879697Snon printf(">> SCSI_LOW_DONE_COMPLETE ===============\n"); 278979697Snon scsi_low_print(slp, NULL); 279067468Snon } 279179697Snon#endif /* SCSI_LOW_DEBUG */ 279267468Snon 279379697Snon scsi_low_deactivate_qtag(cb); 279479697Snon scsi_low_dealloc_qtag(cb); 279567468Snon scsi_low_free_ccb(cb); 279679697Snon slp->sl_nio --; 279767468Snon return SCSI_LOW_DONE_COMPLETE; 279867468Snon 279967468Snonretry: 280079697Snon#ifdef SCSI_LOW_DEBUG 280179697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 280267468Snon { 280379697Snon printf("** SCSI_LOW_DONE_RETRY ===============\n"); 280479697Snon scsi_low_print(slp, NULL); 280567468Snon } 280679697Snon#endif /* SCSI_LOW_DEBUG */ 280779697Snon 280879697Snon cb->ccb_rcnt ++; 280979697Snon scsi_low_deactivate_qtag(cb); 281079697Snon scsi_low_ccb_message_retry(cb); 281167468Snon return SCSI_LOW_DONE_RETRY; 281267468Snon} 281367468Snon 281467468Snon/************************************************************** 281567468Snon * Reset 281667468Snon **************************************************************/ 281767468Snonstatic void 281879697Snonscsi_low_reset_nexus_target(slp, ti, fdone) 281979697Snon struct scsi_low_softc *slp; 282079697Snon struct targ_info *ti; 282179697Snon int fdone; 282267468Snon{ 282379697Snon struct lun_info *li; 282467468Snon 282579697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 282679697Snon li = LIST_NEXT(li, lun_chain)) 282779697Snon { 282879697Snon scsi_low_reset_nexus_lun(slp, li, fdone); 282979697Snon li->li_state = SCSI_LOW_LUN_SLEEP; 283079697Snon li->li_maxnqio = 0; 283179697Snon } 283279697Snon 283379697Snon ti->ti_disc = 0; 283479697Snon ti->ti_setup_msg = 0; 283579697Snon ti->ti_setup_msg_done = 0; 283679697Snon 283779697Snon ti->ti_osynch.offset = ti->ti_osynch.period = 0; 283879697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 283979697Snon 284079697Snon ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 284179697Snon ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID; 284279697Snon 284379697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 284479697Snon { 284579697Snon ((*slp->sl_funcs->scsi_low_targ_init) 284679697Snon (slp, ti, SCSI_LOW_INFO_REVOKE)); 284779697Snon } 284879697Snon scsi_low_calcf_target(ti); 284979697Snon 285079697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 285179697Snon li = LIST_NEXT(li, lun_chain)) 285279697Snon { 285379697Snon li->li_flags = 0; 285479697Snon 285579697Snon li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 285679697Snon li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID; 285779697Snon 285879697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 285979697Snon { 286079697Snon ((*slp->sl_funcs->scsi_low_lun_init) 286179697Snon (slp, ti, li, SCSI_LOW_INFO_REVOKE)); 286279697Snon } 286379697Snon scsi_low_calcf_lun(li); 286479697Snon } 286567468Snon} 286667468Snon 286767468Snonstatic void 286867468Snonscsi_low_reset_nexus(slp, fdone) 286967468Snon struct scsi_low_softc *slp; 287067468Snon int fdone; 287167468Snon{ 287267468Snon struct targ_info *ti; 287379697Snon struct slccb *cb, *topcb; 287467468Snon 287579697Snon if ((cb = slp->sl_Qnexus) != NULL) 287667468Snon { 287779697Snon topcb = scsi_low_revoke_ccb(slp, cb, fdone); 287867468Snon } 287979697Snon else 288079697Snon { 288179697Snon topcb = NULL; 288279697Snon } 288367468Snon 288479697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 288579697Snon ti = TAILQ_NEXT(ti, ti_chain)) 288667468Snon { 288779697Snon scsi_low_reset_nexus_target(slp, ti, fdone); 288879697Snon scsi_low_bus_release(slp, ti); 288967468Snon scsi_low_init_msgsys(slp, ti); 289067468Snon } 289167468Snon 289279697Snon if (topcb != NULL) 289379697Snon { 289479697Snon topcb->ccb_flags |= CCB_STARTQ; 289579697Snon TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain); 289679697Snon } 289779697Snon 289879697Snon slp->sl_disc = 0; 289979697Snon slp->sl_retry_sel = 0; 290067468Snon slp->sl_flags &= ~HW_PDMASTART; 290167468Snon} 290267468Snon 290367468Snon/* misc */ 290467468Snonstatic int tw_pos; 290567468Snonstatic char tw_chars[] = "|/-\\"; 290679697Snon#define TWIDDLEWAIT 10000 290767468Snon 290867468Snonstatic void 290967468Snonscsi_low_twiddle_wait(void) 291067468Snon{ 291167468Snon 291267468Snon cnputc('\b'); 291367468Snon cnputc(tw_chars[tw_pos++]); 291467468Snon tw_pos %= (sizeof(tw_chars) - 1); 291579697Snon SCSI_LOW_DELAY(TWIDDLEWAIT); 291667468Snon} 291767468Snon 291867468Snonvoid 291967468Snonscsi_low_bus_reset(slp) 292067468Snon struct scsi_low_softc *slp; 292167468Snon{ 292267468Snon int i; 292367468Snon 292467468Snon (*slp->sl_funcs->scsi_low_bus_reset) (slp); 292567468Snon 292667468Snon printf("%s: try to reset scsi bus ", slp->sl_xname); 292767468Snon for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) 292867468Snon scsi_low_twiddle_wait(); 292967468Snon cnputc('\b'); 293067468Snon printf("\n"); 293167468Snon} 293267468Snon 293367468Snonint 293467468Snonscsi_low_restart(slp, flags, s) 293567468Snon struct scsi_low_softc *slp; 293667468Snon int flags; 293767468Snon u_char *s; 293867468Snon{ 293967468Snon int error; 294067468Snon 294167468Snon if (s != NULL) 294267468Snon printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s); 294367468Snon 294467468Snon if ((error = scsi_low_init(slp, flags)) != 0) 294567468Snon return error; 294667468Snon 294767468Snon scsi_low_start(slp); 294867468Snon return 0; 294967468Snon} 295067468Snon 295167468Snon/************************************************************** 295267468Snon * disconnect and reselect 295367468Snon **************************************************************/ 295467468Snon#define MSGCMD_LUN(msg) (msg & 0x07) 295567468Snon 295667468Snonstatic struct slccb * 295767468Snonscsi_low_establish_ccb(ti, li, tag) 295867468Snon struct targ_info *ti; 295967468Snon struct lun_info *li; 296067468Snon scsi_low_tag_t tag; 296167468Snon{ 296267468Snon struct scsi_low_softc *slp = ti->ti_sc; 296367468Snon struct slccb *cb; 296467468Snon 296579697Snon if (li == NULL) 296679697Snon return NULL; 296779697Snon 296879697Snon cb = TAILQ_FIRST(&li->li_discq); 296971999Sphk for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) 297079697Snon if (cb->ccb_tag == tag) 297167468Snon goto found; 297267468Snon return cb; 297367468Snon 297467468Snon /* 297567468Snon * establish our ccb nexus 297667468Snon */ 297767468Snonfound: 297879697Snon#ifdef SCSI_LOW_DEBUG 297979697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 298079697Snon { 298179697Snon printf("%s: nexus(0x%lx) abort check start\n", 298279697Snon slp->sl_xname, (u_long) cb); 298379697Snon cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT); 298479697Snon scsi_low_revoke_ccb(slp, cb, 1); 298579697Snon return NULL; 298679697Snon } 298767468Snon 298879697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0) 298979697Snon { 299079697Snon if (cb->ccb_omsgoutflag == 0) 299179697Snon scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP); 299279697Snon } 299379697Snon#endif /* SCSI_LOW_DEBUG */ 299479697Snon 299579697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 299679697Snon cb->ccb_flags &= ~CCB_DISCQ; 299779697Snon slp->sl_Qnexus = cb; 299879697Snon 299967468Snon slp->sl_scp = cb->ccb_sscp; 300067468Snon slp->sl_error |= cb->ccb_error; 300167468Snon 300267468Snon slp->sl_disc --; 300379697Snon ti->ti_disc --; 300467468Snon li->li_disc --; 300567468Snon 300667468Snon /* inform "ccb nexus established" to the host driver */ 300779697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 300879697Snon 300979697Snon /* check msg */ 301079697Snon if (cb->ccb_msgoutflag != 0) 301179697Snon { 301279697Snon scsi_low_ccb_message_exec(slp, cb); 301379697Snon } 301479697Snon 301567468Snon return cb; 301667468Snon} 301767468Snon 301867468Snonstruct targ_info * 301967468Snonscsi_low_reselected(slp, targ) 302067468Snon struct scsi_low_softc *slp; 302167468Snon u_int targ; 302267468Snon{ 302367468Snon struct targ_info *ti; 302479697Snon struct slccb *cb; 302567468Snon u_char *s; 302667468Snon 302767468Snon /* 302867468Snon * Check select vs reselected collision. 302967468Snon */ 303067468Snon 303179697Snon if ((cb = slp->sl_selid) != NULL) 303267468Snon { 303379697Snon scsi_low_arbit_fail(slp, cb); 303467468Snon#ifdef SCSI_LOW_STATICS 303567468Snon scsi_low_statics.nexus_conflict ++; 303667468Snon#endif /* SCSI_LOW_STATICS */ 303767468Snon } 303879697Snon 303979697Snon /* 304079697Snon * Check if no current active nexus. 304179697Snon */ 304279697Snon if (slp->sl_Tnexus != NULL) 304367468Snon { 304467468Snon s = "host busy"; 304567468Snon goto world_restart; 304667468Snon } 304767468Snon 304867468Snon /* 304967468Snon * Check a valid target id asserted ? 305067468Snon */ 305167468Snon if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) 305267468Snon { 305367468Snon s = "scsi id illegal"; 305467468Snon goto world_restart; 305567468Snon } 305667468Snon 305767468Snon /* 305867468Snon * Check the target scsi status. 305967468Snon */ 306067468Snon ti = slp->sl_ti[targ]; 306179697Snon if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL) 306267468Snon { 306367468Snon s = "phase mismatch"; 306467468Snon goto world_restart; 306567468Snon } 306667468Snon 306767468Snon /* 306879697Snon * Setup init msgsys 306967468Snon */ 307067468Snon slp->sl_error = 0; 307167468Snon scsi_low_init_msgsys(slp, ti); 307267468Snon 307367468Snon /* 307467468Snon * Establish our target nexus 307567468Snon */ 307667468Snon SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); 307779697Snon slp->sl_Tnexus = ti; 307867468Snon#ifdef SCSI_LOW_STATICS 307967468Snon scsi_low_statics.nexus_reselected ++; 308067468Snon#endif /* SCSI_LOW_STATICS */ 308167468Snon return ti; 308267468Snon 308367468Snonworld_restart: 308467468Snon printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); 308567468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 308667468Snon "reselect: scsi world confused"); 308767468Snon return NULL; 308867468Snon} 308967468Snon 309067468Snon/************************************************************** 309167468Snon * cmd out pointer setup 309267468Snon **************************************************************/ 309367468Snonint 309467468Snonscsi_low_cmd(slp, ti) 309567468Snon struct scsi_low_softc *slp; 309667468Snon struct targ_info *ti; 309767468Snon{ 309879697Snon struct slccb *cb = slp->sl_Qnexus; 309967468Snon 310079697Snon slp->sl_ph_count ++; 310167468Snon if (cb == NULL) 310267468Snon { 310367468Snon /* 310479697Snon * no ccb, abort! 310567468Snon */ 310667468Snon slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 310767468Snon slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); 310867468Snon slp->sl_scp.scp_datalen = 0; 310967468Snon slp->sl_scp.scp_direction = SCSI_LOW_READ; 311079697Snon slp->sl_error |= FATALIO; 311179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 311279697Snon SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found"); 311379697Snon return EINVAL; 311467468Snon } 311579697Snon else 311667468Snon { 311779697Snon#ifdef SCSI_LOW_DEBUG 311879697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id)) 311979697Snon { 312079697Snon scsi_low_test_cmdlnk(slp, cb); 312179697Snon } 312279697Snon#endif /* SCSI_LOW_DEBUG */ 312367468Snon } 312467468Snon return 0; 312567468Snon} 312667468Snon 312767468Snon/************************************************************** 312867468Snon * data out pointer setup 312967468Snon **************************************************************/ 313067468Snonint 313167468Snonscsi_low_data(slp, ti, bp, direction) 313267468Snon struct scsi_low_softc *slp; 313367468Snon struct targ_info *ti; 313467468Snon struct buf **bp; 313567468Snon int direction; 313667468Snon{ 313779697Snon struct slccb *cb = slp->sl_Qnexus; 313867468Snon 313979697Snon if (cb != NULL && direction == cb->ccb_sscp.scp_direction) 314067468Snon { 314179697Snon *bp = cb->bp; 314279697Snon return 0; 314367468Snon } 314467468Snon 314579697Snon slp->sl_error |= (FATALIO | PDMAERR); 314679697Snon slp->sl_scp.scp_datalen = 0; 314779697Snon slp->sl_scp.scp_direction = direction; 314879697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 314979697Snon if (ti->ti_ophase != ti->ti_phase) 315067468Snon { 315179697Snon char *s; 315279697Snon 315379697Snon if (cb == NULL) 315479697Snon s = "DATA PHASE: ccb nexus not found"; 315579697Snon else 315679697Snon s = "DATA PHASE: xfer direction mismatch"; 315779697Snon SCSI_LOW_INFO(slp, ti, s); 315867468Snon } 315967468Snon 316079697Snon *bp = NULL; 316179697Snon return EINVAL; 316267468Snon} 316367468Snon 316467468Snon/************************************************************** 316567468Snon * MSG_SYS 316667468Snon **************************************************************/ 316767468Snon#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} 316867468Snon#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) 316967468Snon#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) 317079697Snon#define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3]) 317167468Snon#define MSGIN_DATA_LAST 0x30 317267468Snon 317392770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int); 317492770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int); 317592770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int); 317692770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int); 317767468Snon 317892770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *); 317992770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *); 318092770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *); 318192770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *); 318292770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *); 318392770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *); 318492770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *); 318567468Snon 318667468Snonstruct scsi_low_msgout_data { 318767468Snon u_int md_flags; 318867468Snon u_int8_t md_msg; 318992770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 319092770Salfred int (*md_errfunc)(struct scsi_low_softc *, u_int); 319179697Snon#define MSG_RELEASE_ATN 0x0001 319279697Snon u_int md_condition; 319367468Snon}; 319467468Snon 319567468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = { 319679697Snon/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN}, 319779697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN}, 319879697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN}, 319979697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN}, 320079697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0}, 320179697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 320279697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN}, 320379697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 320479697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 320579697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 320679697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN}, 320779697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 320879697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN}, 320979697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN}, 321079697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN}, 321179697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0}, 321267468Snon}; 321367468Snon 321492770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *); 321592770Salfredstatic int scsi_low_synch(struct scsi_low_softc *); 321692770Salfredstatic int scsi_low_wide(struct scsi_low_softc *); 321792770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *); 321892770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *); 321992770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *); 322092770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *); 322192770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *); 322292770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *); 322392770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *); 322492770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *); 322592770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *); 322692770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *); 322792770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *); 322867468Snon 322967468Snonstruct scsi_low_msgin_data { 323067468Snon u_int md_len; 323192770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 323267468Snon}; 323367468Snon 323467468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = { 323567468Snon/* 0 */ {1, scsi_low_msginfunc_cc}, 323667468Snon/* 1 */ {2, scsi_low_msginfunc_ext}, 323767468Snon/* 2 */ {1, scsi_low_msginfunc_sdp}, 323879697Snon/* 3 */ {1, scsi_low_msginfunc_rp}, 323967468Snon/* 4 */ {1, scsi_low_msginfunc_disc}, 324067468Snon/* 5 */ {1, scsi_low_msginfunc_rejop}, 324167468Snon/* 6 */ {1, scsi_low_msginfunc_rejop}, 324267468Snon/* 7 */ {1, scsi_low_msginfunc_msg_reject}, 324367468Snon/* 8 */ {1, scsi_low_msginfunc_noop}, 324467468Snon/* 9 */ {1, scsi_low_msginfunc_parity}, 324579697Snon/* a */ {1, scsi_low_msginfunc_lcc}, 324679697Snon/* b */ {1, scsi_low_msginfunc_lcc}, 324767468Snon/* c */ {1, scsi_low_msginfunc_rejop}, 324867468Snon/* d */ {2, scsi_low_msginfunc_rejop}, 324967468Snon/* e */ {1, scsi_low_msginfunc_rejop}, 325067468Snon/* f */ {1, scsi_low_msginfunc_rejop}, 325167468Snon/* 0x10 */ {1, scsi_low_msginfunc_rejop}, 325267468Snon/* 0x11 */ {1, scsi_low_msginfunc_rejop}, 325367468Snon/* 0x12 */ {1, scsi_low_msginfunc_rejop}, 325467468Snon/* 0x13 */ {1, scsi_low_msginfunc_rejop}, 325567468Snon/* 0x14 */ {1, scsi_low_msginfunc_rejop}, 325667468Snon/* 0x15 */ {1, scsi_low_msginfunc_rejop}, 325767468Snon/* 0x16 */ {1, scsi_low_msginfunc_rejop}, 325867468Snon/* 0x17 */ {1, scsi_low_msginfunc_rejop}, 325967468Snon/* 0x18 */ {1, scsi_low_msginfunc_rejop}, 326067468Snon/* 0x19 */ {1, scsi_low_msginfunc_rejop}, 326167468Snon/* 0x1a */ {1, scsi_low_msginfunc_rejop}, 326267468Snon/* 0x1b */ {1, scsi_low_msginfunc_rejop}, 326367468Snon/* 0x1c */ {1, scsi_low_msginfunc_rejop}, 326467468Snon/* 0x1d */ {1, scsi_low_msginfunc_rejop}, 326567468Snon/* 0x1e */ {1, scsi_low_msginfunc_rejop}, 326667468Snon/* 0x1f */ {1, scsi_low_msginfunc_rejop}, 326779697Snon/* 0x20 */ {2, scsi_low_msginfunc_simple_qtag}, 326867468Snon/* 0x21 */ {2, scsi_low_msginfunc_rejop}, 326967468Snon/* 0x22 */ {2, scsi_low_msginfunc_rejop}, 327079697Snon/* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue}, 327167468Snon/* 0x24 */ {2, scsi_low_msginfunc_rejop}, 327267468Snon/* 0x25 */ {2, scsi_low_msginfunc_rejop}, 327367468Snon/* 0x26 */ {2, scsi_low_msginfunc_rejop}, 327467468Snon/* 0x27 */ {2, scsi_low_msginfunc_rejop}, 327567468Snon/* 0x28 */ {2, scsi_low_msginfunc_rejop}, 327667468Snon/* 0x29 */ {2, scsi_low_msginfunc_rejop}, 327767468Snon/* 0x2a */ {2, scsi_low_msginfunc_rejop}, 327867468Snon/* 0x2b */ {2, scsi_low_msginfunc_rejop}, 327967468Snon/* 0x2c */ {2, scsi_low_msginfunc_rejop}, 328067468Snon/* 0x2d */ {2, scsi_low_msginfunc_rejop}, 328167468Snon/* 0x2e */ {2, scsi_low_msginfunc_rejop}, 328267468Snon/* 0x2f */ {2, scsi_low_msginfunc_rejop}, 328367468Snon/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ 328467468Snon}; 328567468Snon 328667468Snon/************************************************************** 328767468Snon * msgout 328867468Snon **************************************************************/ 328967468Snonstatic int 329079697Snonscsi_low_msgfunc_synch(slp) 329179697Snon struct scsi_low_softc *slp; 329267468Snon{ 329379697Snon struct targ_info *ti = slp->sl_Tnexus; 329467468Snon int ptr = ti->ti_msgoutlen; 329567468Snon 329667468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; 329767468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; 329873025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period; 329973025Snon ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset; 330067468Snon return MSG_EXTEND_SYNCHLEN + 2; 330167468Snon} 330267468Snon 330367468Snonstatic int 330479697Snonscsi_low_msgfunc_wide(slp) 330579697Snon struct scsi_low_softc *slp; 330667468Snon{ 330779697Snon struct targ_info *ti = slp->sl_Tnexus; 330867468Snon int ptr = ti->ti_msgoutlen; 330967468Snon 331067468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; 331167468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; 331273025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_width; 331367468Snon return MSG_EXTEND_WIDELEN + 2; 331467468Snon} 331567468Snon 331667468Snonstatic int 331779697Snonscsi_low_msgfunc_identify(slp) 331879697Snon struct scsi_low_softc *slp; 331967468Snon{ 332079697Snon struct targ_info *ti = slp->sl_Tnexus; 332179697Snon struct lun_info *li = slp->sl_Lnexus; 332279697Snon struct slccb *cb = slp->sl_Qnexus; 332379697Snon int ptr = ti->ti_msgoutlen; 332479697Snon u_int8_t msg; 332567468Snon 332679697Snon msg = MSG_IDENTIFY; 332779697Snon if (cb == NULL) 332867468Snon { 332979697Snon slp->sl_error |= FATALIO; 333079697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 333179697Snon SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown"); 333267468Snon } 333367468Snon else 333467468Snon { 333579697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 333679697Snon msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun); 333779697Snon else 333879697Snon msg |= li->li_lun; 333979697Snon 334079697Snon if (ti->ti_phase == PH_MSGOUT) 334179697Snon { 334279697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 334379697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 334479697Snon { 334579697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 334679697Snon } 334779697Snon } 334867468Snon } 334979697Snon ti->ti_msgoutstr[ptr + 0] = msg; 335067468Snon return 1; 335167468Snon} 335267468Snon 335367468Snonstatic int 335479697Snonscsi_low_msgfunc_abort(slp) 335579697Snon struct scsi_low_softc *slp; 335667468Snon{ 335767468Snon 335879697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT); 335979697Snon return 1; 336079697Snon} 336179697Snon 336279697Snonstatic int 336379697Snonscsi_low_msgfunc_qabort(slp) 336479697Snon struct scsi_low_softc *slp; 336579697Snon{ 336679697Snon 336779697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM); 336879697Snon return 1; 336979697Snon} 337079697Snon 337179697Snonstatic int 337279697Snonscsi_low_msgfunc_reset(slp) 337379697Snon struct scsi_low_softc *slp; 337479697Snon{ 337579697Snon 337679697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET); 337779697Snon return 1; 337879697Snon} 337979697Snon 338079697Snonstatic int 338179697Snonscsi_low_msgfunc_qtag(slp) 338279697Snon struct scsi_low_softc *slp; 338379697Snon{ 338479697Snon struct targ_info *ti = slp->sl_Tnexus; 338579697Snon struct slccb *cb = slp->sl_Qnexus; 338679697Snon int ptr = ti->ti_msgoutlen; 338779697Snon 338879697Snon if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG) 338967468Snon { 339067468Snon ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; 339167468Snon return 1; 339267468Snon } 339367468Snon else 339467468Snon { 339579697Snon ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag; 339679697Snon if (ti->ti_phase == PH_MSGOUT) 339779697Snon { 339879697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 339979697Snon } 340067468Snon } 340179697Snon return 2; 340267468Snon} 340367468Snon 340467468Snon/* 340567468Snon * The following functions are called when targets give unexpected 340667468Snon * responces in msgin (after msgout). 340767468Snon */ 340867468Snonstatic int 340979697Snonscsi_low_errfunc_identify(slp, msgflags) 341079697Snon struct scsi_low_softc *slp; 341167468Snon u_int msgflags; 341267468Snon{ 341367468Snon 341479697Snon if (slp->sl_Lnexus != NULL) 341579697Snon { 341679697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC; 341779697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 341879697Snon } 341967468Snon return 0; 342067468Snon} 342167468Snon 342267468Snonstatic int 342379697Snonscsi_low_errfunc_synch(slp, msgflags) 342479697Snon struct scsi_low_softc *slp; 342567468Snon u_int msgflags; 342667468Snon{ 342779697Snon struct targ_info *ti = slp->sl_Tnexus; 342867468Snon 342967468Snon MSGIN_PERIOD(ti) = 0; 343067468Snon MSGIN_OFFSET(ti) = 0; 343179697Snon scsi_low_synch(slp); 343267468Snon return 0; 343367468Snon} 343467468Snon 343567468Snonstatic int 343679697Snonscsi_low_errfunc_wide(slp, msgflags) 343779697Snon struct scsi_low_softc *slp; 343867468Snon u_int msgflags; 343967468Snon{ 344079697Snon struct targ_info *ti = slp->sl_Tnexus; 344179697Snon 344279697Snon MSGIN_WIDTHP(ti) = 0; 344379697Snon scsi_low_wide(slp); 344467468Snon return 0; 344567468Snon} 344667468Snon 344779697Snonstatic int 344879697Snonscsi_low_errfunc_qtag(slp, msgflags) 344979697Snon struct scsi_low_softc *slp; 345079697Snon u_int msgflags; 345179697Snon{ 345279697Snon 345379697Snon if ((msgflags & SCSI_LOW_MSG_REJECT) != 0) 345479697Snon { 345579697Snon if (slp->sl_Qnexus != NULL) 345679697Snon { 345779697Snon scsi_low_deactivate_qtag(slp->sl_Qnexus); 345879697Snon } 345979697Snon if (slp->sl_Lnexus != NULL) 346079697Snon { 346179697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG; 346279697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 346379697Snon } 346479697Snon printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname); 346579697Snon } 346679697Snon return 0; 346779697Snon} 346879697Snon 346979697Snon 347067468Snonint 347179697Snonscsi_low_msgout(slp, ti, fl) 347267468Snon struct scsi_low_softc *slp; 347367468Snon struct targ_info *ti; 347479697Snon u_int fl; 347567468Snon{ 347667468Snon struct scsi_low_msgout_data *mdp; 347767468Snon int len = 0; 347867468Snon 347979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 348079697Snon if (ti != slp->sl_Tnexus) 348179697Snon { 348279697Snon scsi_low_print(slp, NULL); 348379697Snon panic("scsi_low_msgout: Target nexus inconsistent"); 348479697Snon } 348579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 348679697Snon 348779697Snon slp->sl_ph_count ++; 348879697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 348979697Snon { 349079697Snon printf("%s: too many phase changes\n", slp->sl_xname); 349179697Snon slp->sl_error |= FATALIO; 349279697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 349379697Snon } 349479697Snon 349567468Snon /* STEP I. 349667468Snon * Scsi phase changes. 349767468Snon * Previously msgs asserted are accepted by our target or 349867468Snon * processed by scsi_low_msgin. 349967468Snon * Thus clear all saved informations. 350067468Snon */ 350179697Snon if ((fl & SCSI_LOW_MSGOUT_INIT) != 0) 350267468Snon { 350367468Snon ti->ti_omsgflags = 0; 350467468Snon ti->ti_emsgflags = 0; 350567468Snon } 350679697Snon else if (slp->sl_atten == 0) 350779697Snon { 350867468Snon /* STEP II. 350967468Snon * We did not assert attention, however still our target required 351067468Snon * msgs. Resend previous msgs. 351167468Snon */ 351267468Snon ti->ti_msgflags |= ti->ti_omsgflags; 351379697Snon ti->ti_omsgflags = 0; 351467468Snon#ifdef SCSI_LOW_DIAGNOSTIC 351567468Snon printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); 351667468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 351767468Snon } 351867468Snon 351967468Snon /* STEP III. 352079697Snon * We have no msgs. send MSG_NOOP (OK?) 352167468Snon */ 352279697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 352367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); 352467468Snon 352567468Snon /* STEP IV. 352667468Snon * Process all msgs 352767468Snon */ 352867468Snon ti->ti_msgoutlen = 0; 352979697Snon slp->sl_clear_atten = 0; 353067468Snon mdp = &scsi_low_msgout_data[0]; 353167468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 353267468Snon { 353367468Snon if ((ti->ti_msgflags & mdp->md_flags) != 0) 353467468Snon { 353567468Snon ti->ti_omsgflags |= mdp->md_flags; 353667468Snon ti->ti_msgflags &= ~mdp->md_flags; 353767468Snon ti->ti_emsgflags = mdp->md_flags; 353867468Snon 353967468Snon ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; 354067468Snon if (mdp->md_msgfunc != NULL) 354179697Snon len = (*mdp->md_msgfunc) (slp); 354267468Snon else 354367468Snon len = 1; 354467468Snon 354579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 354679697Snon scsi_low_msg_log_write(&ti->ti_log_msgout, 354779697Snon &ti->ti_msgoutstr[ti->ti_msgoutlen], len); 354879697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 354979697Snon 355067468Snon ti->ti_msgoutlen += len; 355179697Snon if ((mdp->md_condition & MSG_RELEASE_ATN) != 0) 355279697Snon { 355379697Snon slp->sl_clear_atten = 1; 355479697Snon break; 355579697Snon } 355679697Snon 355779697Snon if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 || 355867468Snon ti->ti_msgflags == 0) 355967468Snon break; 356079697Snon 356167468Snon if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) 356267468Snon break; 356367468Snon } 356467468Snon } 356567468Snon 356679697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 356779697Snon slp->sl_clear_atten = 1; 356867468Snon 356967468Snon return ti->ti_msgoutlen; 357067468Snon} 357167468Snon 357267468Snon/************************************************************** 357367468Snon * msgin 357467468Snon **************************************************************/ 357567468Snonstatic int 357679697Snonscsi_low_msginfunc_noop(slp) 357779697Snon struct scsi_low_softc *slp; 357867468Snon{ 357967468Snon 358067468Snon return 0; 358167468Snon} 358267468Snon 358367468Snonstatic int 358479697Snonscsi_low_msginfunc_rejop(slp) 358579697Snon struct scsi_low_softc *slp; 358667468Snon{ 358779697Snon struct targ_info *ti = slp->sl_Tnexus; 358867468Snon u_int8_t msg = ti->ti_msgin[0]; 358967468Snon 359079697Snon printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg); 359167468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 359267468Snon return 0; 359367468Snon} 359467468Snon 359567468Snonstatic int 359679697Snonscsi_low_msginfunc_cc(slp) 359779697Snon struct scsi_low_softc *slp; 359867468Snon{ 359979697Snon struct lun_info *li; 360067468Snon 360167468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 360279697Snon 360379697Snon /* validate status */ 360479697Snon if (slp->sl_Qnexus == NULL) 360579697Snon return ENOENT; 360679697Snon 360779697Snon slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status; 360879697Snon li = slp->sl_Lnexus; 360979697Snon switch (slp->sl_scp.scp_status) 361079697Snon { 361179697Snon case ST_GOOD: 361279697Snon li->li_maxnqio = li->li_maxnexus; 361379697Snon break; 361479697Snon 361579697Snon case ST_CHKCOND: 361679697Snon li->li_maxnqio = 0; 361779697Snon if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR) 361879697Snon scsi_low_reset_nexus_lun(slp, li, 0); 361979697Snon break; 362079697Snon 362179697Snon case ST_BUSY: 362279697Snon li->li_maxnqio = 0; 362379697Snon break; 362479697Snon 362579697Snon case ST_QUEFULL: 362679697Snon if (li->li_maxnexus >= li->li_nqio) 362779697Snon li->li_maxnexus = li->li_nqio - 1; 362879697Snon li->li_maxnqio = li->li_maxnexus; 362979697Snon break; 363079697Snon 363179697Snon case ST_INTERGOOD: 363279697Snon case ST_INTERMET: 363379697Snon slp->sl_error |= MSGERR; 363479697Snon break; 363579697Snon 363679697Snon default: 363779697Snon break; 363879697Snon } 363967468Snon return 0; 364067468Snon} 364167468Snon 364267468Snonstatic int 364379697Snonscsi_low_msginfunc_lcc(slp) 364479697Snon struct scsi_low_softc *slp; 364579697Snon{ 364667468Snon struct targ_info *ti; 364779697Snon struct lun_info *li; 364879697Snon struct slccb *ncb, *cb; 364979697Snon 365079697Snon ti = slp->sl_Tnexus; 365179697Snon li = slp->sl_Lnexus; 365279697Snon if ((cb = slp->sl_Qnexus) == NULL) 365379697Snon goto bad; 365479697Snon 365579697Snon cb->ccb_sscp.scp_status = slp->sl_scp.scp_status; 365679697Snon switch (slp->sl_scp.scp_status) 365779697Snon { 365879697Snon case ST_INTERGOOD: 365979697Snon case ST_INTERMET: 366079697Snon li->li_maxnqio = li->li_maxnexus; 366179697Snon break; 366279697Snon 366379697Snon default: 366479697Snon slp->sl_error |= MSGERR; 366579697Snon break; 366679697Snon } 366779697Snon 366879697Snon if ((li->li_flags & SCSI_LOW_LINK) == 0) 366979697Snon goto bad; 367079697Snon 367179697Snon cb->ccb_error |= slp->sl_error; 367279697Snon if (cb->ccb_error != 0) 367379697Snon goto bad; 367479697Snon 367579697Snon for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL; 367679697Snon ncb = TAILQ_NEXT(ncb, ccb_chain)) 367779697Snon { 367879697Snon if (ncb->li == li) 367979697Snon goto cmd_link_start; 368079697Snon } 368179697Snon 368279697Snon 368379697Snonbad: 368479697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM); 368579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 368679697Snon return EIO; 368779697Snon 368879697Snoncmd_link_start: 368979697Snon ncb->ccb_flags &= ~CCB_STARTQ; 369079697Snon TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain); 369179697Snon 369279697Snon scsi_low_dealloc_qtag(ncb); 369379697Snon ncb->ccb_tag = cb->ccb_tag; 369479697Snon ncb->ccb_otag = cb->ccb_otag; 369579697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 369679697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 369779697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 3698106890Simp panic("%s: linked ccb retried", slp->sl_xname); 369979697Snon 370079697Snon slp->sl_Qnexus = ncb; 370179697Snon slp->sl_ph_count = 0; 370279697Snon 370379697Snon ncb->ccb_error = 0; 370479697Snon ncb->ccb_datalen = -1; 370579697Snon ncb->ccb_scp.scp_status = ST_UNKNOWN; 370679697Snon ncb->ccb_flags &= ~CCB_INTERNAL; 370779697Snon 370879697Snon scsi_low_init_msgsys(slp, ti); 370979697Snon 371079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb); 371179697Snon 371279697Snon if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 371379697Snon ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 371479697Snon ncb->ccb_tc = ncb->ccb_tcmax; 371579697Snon 371679697Snon /* setup saved scsi data pointer */ 371779697Snon ncb->ccb_sscp = ncb->ccb_scp; 371879697Snon slp->sl_scp = ncb->ccb_sscp; 371979697Snon slp->sl_error = ncb->ccb_error; 372079697Snon 372179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 372279697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 372379697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 372479697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 372579697Snon return EJUSTRETURN; 372679697Snon} 372779697Snon 372879697Snonstatic int 372979697Snonscsi_low_msginfunc_disc(slp) 373079697Snon struct scsi_low_softc *slp; 373167468Snon{ 373267468Snon 373367468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); 373467468Snon return 0; 373567468Snon} 373667468Snon 373767468Snonstatic int 373879697Snonscsi_low_msginfunc_sdp(slp) 373979697Snon struct scsi_low_softc *slp; 374067468Snon{ 374179697Snon struct slccb *cb = slp->sl_Qnexus; 374267468Snon 374379697Snon if (cb != NULL) 374479697Snon { 374579697Snon cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen; 374679697Snon cb->ccb_sscp.scp_data = slp->sl_scp.scp_data; 374779697Snon } 374867468Snon else 374979697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 375067468Snon return 0; 375167468Snon} 375267468Snon 375367468Snonstatic int 375479697Snonscsi_low_msginfunc_rp(slp) 375579697Snon struct scsi_low_softc *slp; 375667468Snon{ 375767468Snon 375879697Snon if (slp->sl_Qnexus != NULL) 375979697Snon slp->sl_scp = slp->sl_Qnexus->ccb_sscp; 376067468Snon else 376179697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 376267468Snon return 0; 376367468Snon} 376467468Snon 376567468Snonstatic int 376679697Snonscsi_low_synch(slp) 376779697Snon struct scsi_low_softc *slp; 376867468Snon{ 376979697Snon struct targ_info *ti = slp->sl_Tnexus; 377079697Snon u_int period = 0, offset = 0, speed; 377167468Snon u_char *s; 377267468Snon int error; 377367468Snon 377479697Snon if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period && 377579697Snon MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) || 377679697Snon MSGIN_OFFSET(ti) == 0) 377767468Snon { 377867468Snon if ((offset = MSGIN_OFFSET(ti)) != 0) 377967468Snon period = MSGIN_PERIOD(ti); 378067468Snon s = offset ? "synchronous" : "async"; 378167468Snon } 378267468Snon else 378367468Snon { 378467468Snon /* XXX: 378567468Snon * Target seems to be brain damaged. 378667468Snon * Force async transfer. 378767468Snon */ 378873025Snon ti->ti_maxsynch.period = 0; 378973025Snon ti->ti_maxsynch.offset = 0; 379067468Snon printf("%s: target brain damaged. async transfer\n", 379167468Snon slp->sl_xname); 379267468Snon return EINVAL; 379367468Snon } 379467468Snon 379573025Snon ti->ti_maxsynch.period = period; 379673025Snon ti->ti_maxsynch.offset = offset; 379767468Snon 379867468Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); 379967468Snon if (error != 0) 380067468Snon { 380167468Snon /* XXX: 380267468Snon * Current period and offset are not acceptable 380367468Snon * for our adapter. 380467468Snon * The adapter changes max synch and max offset. 380567468Snon */ 380667468Snon printf("%s: synch neg failed. retry synch msg neg ...\n", 380767468Snon slp->sl_xname); 380867468Snon return error; 380967468Snon } 381067468Snon 381179697Snon ti->ti_osynch = ti->ti_maxsynch; 381279697Snon if (offset > 0) 381379697Snon { 381479697Snon ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH; 381579697Snon } 381679697Snon 381767468Snon /* inform data */ 381879697Snon if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0) 381967468Snon { 382079697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 382179697Snon struct slccb *cb = slp->sl_Qnexus; 382279697Snon 382379697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 382479697Snon return 0; 382579697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 382679697Snon 382779697Snon printf("%s(%d:*): <%s> offset %d period %dns ", 382879697Snon slp->sl_xname, ti->ti_id, s, offset, period * 4); 382979697Snon 383079697Snon if (period != 0) 383179697Snon { 383279697Snon speed = 1000 * 10 / (period * 4); 383379697Snon printf("%d.%d M/s", speed / 10, speed % 10); 383479697Snon } 383579697Snon printf("\n"); 383667468Snon } 383779697Snon return 0; 383879697Snon} 383967468Snon 384079697Snonstatic int 384179697Snonscsi_low_wide(slp) 384279697Snon struct scsi_low_softc *slp; 384379697Snon{ 384479697Snon struct targ_info *ti = slp->sl_Tnexus; 384579697Snon int error; 384679697Snon 384779697Snon ti->ti_width = MSGIN_WIDTHP(ti); 384879697Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE); 384979697Snon if (error != 0) 385079697Snon { 385179697Snon /* XXX: 385279697Snon * Current width is not acceptable for our adapter. 385379697Snon * The adapter changes max width. 385479697Snon */ 385579697Snon printf("%s: wide neg failed. retry wide msg neg ...\n", 385679697Snon slp->sl_xname); 385779697Snon return error; 385879697Snon } 385979697Snon 386079697Snon ti->ti_owidth = ti->ti_width; 386179697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 386279697Snon { 386379697Snon ti->ti_setup_msg_done |= 386479697Snon (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE); 386579697Snon } 386679697Snon 386779697Snon /* inform data */ 386879697Snon if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0) 386979697Snon { 387079697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 387179697Snon struct slccb *cb = slp->sl_Qnexus; 387279697Snon 387379697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 387479697Snon return 0; 387579697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 387679697Snon 387779697Snon printf("%s(%d:*): transfer width %d bits\n", 387879697Snon slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width)); 387979697Snon } 388067468Snon return 0; 388167468Snon} 388267468Snon 388367468Snonstatic int 388479697Snonscsi_low_msginfunc_simple_qtag(slp) 388579697Snon struct scsi_low_softc *slp; 388667468Snon{ 388779697Snon struct targ_info *ti = slp->sl_Tnexus; 388879697Snon scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1]; 388979697Snon 389079697Snon if (slp->sl_Qnexus != NULL) 389179697Snon { 389279697Snon if (slp->sl_Qnexus->ccb_tag != etag) 389379697Snon { 389479697Snon slp->sl_error |= FATALIO; 389579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 389679697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch"); 389779697Snon } 389879697Snon } 389979697Snon else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL) 390079697Snon { 390179697Snon#ifdef SCSI_LOW_DEBUG 390279697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id)) 390379697Snon return 0; 390479697Snon#endif /* SCSI_LOW_DEBUG */ 390579697Snon 390679697Snon slp->sl_error |= FATALIO; 390779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0); 390879697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found"); 390979697Snon } 391079697Snon return 0; 391179697Snon} 391279697Snon 391379697Snonstatic int 391479697Snonscsi_low_msginfunc_i_wide_residue(slp) 391579697Snon struct scsi_low_softc *slp; 391679697Snon{ 391779697Snon struct targ_info *ti = slp->sl_Tnexus; 391879697Snon struct slccb *cb = slp->sl_Qnexus; 391979697Snon int res = (int) ti->ti_msgin[1]; 392079697Snon 392179697Snon if (cb == NULL || res <= 0 || 392279697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) || 392379697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3)) 392479697Snon return EINVAL; 392579697Snon 392679697Snon if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen) 392779697Snon return EINVAL; 392879697Snon 392979697Snon slp->sl_scp.scp_datalen += res; 393079697Snon slp->sl_scp.scp_data -= res; 393179697Snon scsi_low_data_finish(slp); 393279697Snon return 0; 393379697Snon} 393479697Snon 393579697Snonstatic int 393679697Snonscsi_low_msginfunc_ext(slp) 393779697Snon struct scsi_low_softc *slp; 393879697Snon{ 393979697Snon struct slccb *cb = slp->sl_Qnexus; 394079697Snon struct lun_info *li = slp->sl_Lnexus; 394179697Snon struct targ_info *ti = slp->sl_Tnexus; 394267468Snon int count, retry; 394367468Snon u_int32_t *ptr; 394467468Snon 394567468Snon if (ti->ti_msginptr == 2) 394667468Snon { 394767468Snon ti->ti_msginlen = ti->ti_msgin[1] + 2; 394867468Snon return 0; 394967468Snon } 395067468Snon 395167468Snon switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) 395267468Snon { 395367468Snon case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): 395467468Snon if (cb == NULL) 395567468Snon break; 395667468Snon 395767468Snon ptr = (u_int32_t *)(&ti->ti_msgin[3]); 395867468Snon count = (int) htonl((long) (*ptr)); 395967468Snon if(slp->sl_scp.scp_datalen - count < 0 || 396067468Snon slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) 396167468Snon break; 396267468Snon 396367468Snon slp->sl_scp.scp_datalen -= count; 396467468Snon slp->sl_scp.scp_data += count; 396567468Snon return 0; 396667468Snon 396767468Snon case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): 396867468Snon if (li == NULL) 396967468Snon break; 397067468Snon 397179697Snon retry = scsi_low_synch(slp); 397267468Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) 397367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 397479697Snon 397579697Snon#ifdef SCSI_LOW_DEBUG 397679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 397779697Snon { 397879697Snon scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH); 397979697Snon } 398079697Snon#endif /* SCSI_LOW_DEBUG */ 398167468Snon return 0; 398267468Snon 398367468Snon case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): 398467468Snon if (li == NULL) 398567468Snon break; 398667468Snon 398779697Snon retry = scsi_low_wide(slp); 398879697Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0) 398979697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 399079697Snon 399167468Snon return 0; 399267468Snon 399367468Snon default: 399467468Snon break; 399567468Snon } 399667468Snon 399767468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 399867468Snon return EINVAL; 399967468Snon} 400067468Snon 400167468Snonstatic int 400279697Snonscsi_low_msginfunc_parity(slp) 400379697Snon struct scsi_low_softc *slp; 400467468Snon{ 400579697Snon struct targ_info *ti = slp->sl_Tnexus; 400667468Snon 400779697Snon /* only I -> T, invalid! */ 400879697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 400967468Snon return 0; 401067468Snon} 401167468Snon 401267468Snonstatic int 401379697Snonscsi_low_msginfunc_msg_reject(slp) 401479697Snon struct scsi_low_softc *slp; 401567468Snon{ 401679697Snon struct targ_info *ti = slp->sl_Tnexus; 401767468Snon struct scsi_low_msgout_data *mdp; 401867468Snon u_int msgflags; 401967468Snon 402079697Snon if (ti->ti_emsgflags != 0) 402167468Snon { 402279697Snon printf("%s: msg flags [0x%x] rejected\n", 402379697Snon slp->sl_xname, ti->ti_emsgflags); 402467468Snon msgflags = SCSI_LOW_MSG_REJECT; 402567468Snon mdp = &scsi_low_msgout_data[0]; 402667468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 402767468Snon { 402867468Snon if ((ti->ti_emsgflags & mdp->md_flags) != 0) 402967468Snon { 403067468Snon ti->ti_emsgflags &= ~mdp->md_flags; 403167468Snon if (mdp->md_errfunc != NULL) 403279697Snon (*mdp->md_errfunc) (slp, msgflags); 403367468Snon break; 403467468Snon } 403567468Snon } 403679697Snon return 0; 403767468Snon } 403879697Snon else 403979697Snon { 404079697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found"); 404179697Snon slp->sl_error |= MSGERR; 404279697Snon } 404379697Snon return EINVAL; 404467468Snon} 404567468Snon 404679697Snonint 404767468Snonscsi_low_msgin(slp, ti, c) 404867468Snon struct scsi_low_softc *slp; 404967468Snon struct targ_info *ti; 405079697Snon u_int c; 405167468Snon{ 405267468Snon struct scsi_low_msgin_data *sdp; 405367468Snon struct lun_info *li; 405467468Snon u_int8_t msg; 405567468Snon 405679697Snon#ifdef SCSI_LOW_DIAGNOSTIC 405779697Snon if (ti != slp->sl_Tnexus) 405879697Snon { 405979697Snon scsi_low_print(slp, NULL); 406079697Snon panic("scsi_low_msgin: Target nexus inconsistent"); 406179697Snon } 406279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 406379697Snon 406467468Snon /* 406567468Snon * Phase changes, clear the pointer. 406667468Snon */ 406767468Snon if (ti->ti_ophase != ti->ti_phase) 406867468Snon { 406967468Snon MSGINPTR_CLR(ti); 407079697Snon ti->ti_msgin_parity_error = 0; 407179697Snon 407279697Snon slp->sl_ph_count ++; 407379697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 407479697Snon { 407579697Snon printf("%s: too many phase changes\n", slp->sl_xname); 407679697Snon slp->sl_error |= FATALIO; 407779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 407879697Snon } 407967468Snon } 408067468Snon 408167468Snon /* 408267468Snon * Store a current messages byte into buffer and 408367468Snon * wait for the completion of the current msg. 408467468Snon */ 408579697Snon ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c; 408667468Snon if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) 408767468Snon { 408867468Snon ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; 408967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 409067468Snon } 409167468Snon 409267468Snon /* 409379697Snon * Check parity errors. 409479697Snon */ 409579697Snon if ((c & SCSI_LOW_DATA_PE) != 0) 409679697Snon { 409779697Snon ti->ti_msgin_parity_error ++; 409879697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); 409979697Snon goto out; 410079697Snon } 410179697Snon 410279697Snon if (ti->ti_msgin_parity_error != 0) 410379697Snon goto out; 410479697Snon 410579697Snon /* 410667468Snon * Calculate messages length. 410767468Snon */ 410867468Snon msg = ti->ti_msgin[0]; 410967468Snon if (msg < MSGIN_DATA_LAST) 411067468Snon sdp = &scsi_low_msgin_data[msg]; 411167468Snon else 411267468Snon sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; 411367468Snon 411467468Snon if (ti->ti_msginlen == 0) 411567468Snon { 411667468Snon ti->ti_msginlen = sdp->md_len; 411767468Snon } 411867468Snon 411967468Snon /* 412067468Snon * Check comletion. 412167468Snon */ 412267468Snon if (ti->ti_msginptr < ti->ti_msginlen) 412379697Snon return EJUSTRETURN; 412467468Snon 412567468Snon /* 412667468Snon * Do process. 412767468Snon */ 412867468Snon if ((msg & MSG_IDENTIFY) == 0) 412967468Snon { 413079697Snon if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN) 413179697Snon return EJUSTRETURN; 413267468Snon } 413367468Snon else 413467468Snon { 413579697Snon li = slp->sl_Lnexus; 413667468Snon if (li == NULL) 413767468Snon { 413879697Snon li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0); 413967468Snon if (li == NULL) 414067468Snon goto badlun; 414179697Snon slp->sl_Lnexus = li; 414279697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 414367468Snon } 414479697Snon else 414579697Snon { 414679697Snon if (MSGCMD_LUN(msg) != li->li_lun) 414779697Snon goto badlun; 414879697Snon } 414967468Snon 415079697Snon if (slp->sl_Qnexus == NULL && li->li_nqio == 0) 415167468Snon { 415267468Snon if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) 415379697Snon { 415479697Snon#ifdef SCSI_LOW_DEBUG 415579697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 415679697Snon { 415779697Snon goto out; 415879697Snon } 415979697Snon#endif /* SCSI_LOW_DEBUG */ 416067468Snon goto badlun; 416179697Snon } 416267468Snon } 416367468Snon } 416479697Snon goto out; 416567468Snon 416667468Snon /* 416779697Snon * Msg process completed, reset msgin pointer and assert ATN if desired. 416867468Snon */ 416979697Snonbadlun: 417079697Snon slp->sl_error |= FATALIO; 417179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 417279697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong"); 417379697Snon 417479697Snonout: 417579697Snon if (ti->ti_msginptr < ti->ti_msginlen) 417679697Snon return EJUSTRETURN; 417779697Snon 417879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 417979697Snon scsi_low_msg_log_write(&ti->ti_log_msgin, 418079697Snon &ti->ti_msgin[0], ti->ti_msginlen); 418179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 418279697Snon 418379697Snon MSGINPTR_CLR(ti); 418479697Snon return 0; 418579697Snon} 418679697Snon 418779697Snon/********************************************************** 418879697Snon * disconnect 418979697Snon **********************************************************/ 419079697Snonint 419179697Snonscsi_low_disconnected(slp, ti) 419279697Snon struct scsi_low_softc *slp; 419379697Snon struct targ_info *ti; 419479697Snon{ 419579697Snon struct slccb *cb = slp->sl_Qnexus; 419679697Snon 419779697Snon /* check phase completion */ 419879697Snon switch (slp->sl_msgphase) 419967468Snon { 420079697Snon case MSGPH_RESET: 420179697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 420279697Snon scsi_low_msginfunc_cc(slp); 420379697Snon scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0); 420479697Snon goto io_resume; 420567468Snon 420679697Snon case MSGPH_ABORT: 420779697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 420879697Snon scsi_low_msginfunc_cc(slp); 420979697Snon scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0); 421079697Snon goto io_resume; 421179697Snon 421279697Snon case MSGPH_TERM: 421379697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 421479697Snon scsi_low_msginfunc_cc(slp); 421579697Snon goto io_resume; 421679697Snon 421779697Snon case MSGPH_DISC: 421879697Snon if (cb != NULL) 421967468Snon { 422079697Snon struct lun_info *li; 422179697Snon 422279697Snon li = cb->li; 422379697Snon TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain); 422479697Snon cb->ccb_flags |= CCB_DISCQ; 422579697Snon cb->ccb_error |= slp->sl_error; 422679697Snon li->li_disc ++; 422779697Snon ti->ti_disc ++; 422879697Snon slp->sl_disc ++; 422979697Snon } 423079697Snon 423179697Snon#ifdef SCSI_LOW_STATICS 423279697Snon scsi_low_statics.nexus_disconnected ++; 423379697Snon#endif /* SCSI_LOW_STATICS */ 423479697Snon 423579697Snon#ifdef SCSI_LOW_DEBUG 423679697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0) 423779697Snon { 423879697Snon printf("## SCSI_LOW_DISCONNECTED ===============\n"); 423979697Snon scsi_low_print(slp, NULL); 424079697Snon } 424179697Snon#endif /* SCSI_LOW_DEBUG */ 424279697Snon break; 424379697Snon 424479697Snon case MSGPH_NULL: 424579697Snon slp->sl_error |= FATALIO; 424679697Snon if (ti->ti_phase == PH_SELSTART) 424779697Snon slp->sl_error |= SELTIMEOUTIO; 424879697Snon else 424979697Snon slp->sl_error |= UBFERR; 425079697Snon /* fall through */ 425179697Snon 425279697Snon case MSGPH_LCTERM: 425379697Snon case MSGPH_CMDC: 425479697Snonio_resume: 425579697Snon if (cb == NULL) 425679697Snon break; 425779697Snon 425879697Snon#ifdef SCSI_LOW_DEBUG 425979697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 426079697Snon { 426179697Snon if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP && 426279697Snon (cb->ccb_msgoutflag != 0 || 426379697Snon (ti->ti_msgflags & SCSI_LOW_MSG_NOOP))) 426479697Snon { 426579697Snon scsi_low_info(slp, ti, "ATTEN CHECK FAILED"); 426679697Snon } 426779697Snon } 426879697Snon#endif /* SCSI_LOW_DEBUG */ 426979697Snon 427079697Snon cb->ccb_error |= slp->sl_error; 427179697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 427279697Snon { 427379697Snon cb->ccb_flags |= CCB_STARTQ; 427479697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 427579697Snon } 427679697Snon break; 427779697Snon } 427879697Snon 427979697Snon scsi_low_bus_release(slp, ti); 428079697Snon scsi_low_start(slp); 428179697Snon return 1; 428279697Snon} 428379697Snon 428479697Snon/********************************************************** 428579697Snon * TAG operations 428679697Snon **********************************************************/ 4287104094Sphkstatic int 428879697Snonscsi_low_alloc_qtag(cb) 428979697Snon struct slccb *cb; 429079697Snon{ 429179697Snon struct lun_info *li = cb->li; 429279697Snon scsi_low_tag_t etag; 429379697Snon 429479697Snon if (cb->ccb_otag != SCSI_LOW_UNKTAG) 429579697Snon return 0; 429679697Snon 429779697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 429879697Snon etag = ffs(li->li_qtagbits); 429979697Snon if (etag == 0) 430079697Snon return ENOSPC; 430179697Snon 430279697Snon li->li_qtagbits &= ~(1 << (etag - 1)); 430379697Snon cb->ccb_otag = etag; 430479697Snon return 0; 430579697Snon 430679697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 430779697Snon for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++) 430879697Snon if (li->li_qtagarray[li->li_qd] == 0) 430979697Snon goto found; 431079697Snon 431179697Snon for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++) 431279697Snon if (li->li_qtagarray[li->li_qd] == 0) 431379697Snon goto found; 431479697Snon 431579697Snon return ENOSPC; 431679697Snon 431779697Snonfound: 431879697Snon li->li_qtagarray[li->li_qd] ++; 431979697Snon cb->ccb_otag = (li->li_qd ++); 432079697Snon return 0; 432179697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 432279697Snon} 432379697Snon 4324104094Sphkstatic int 432579697Snonscsi_low_dealloc_qtag(cb) 432679697Snon struct slccb *cb; 432779697Snon{ 432879697Snon struct lun_info *li = cb->li; 432979697Snon scsi_low_tag_t etag; 433079697Snon 433179697Snon if (cb->ccb_otag == SCSI_LOW_UNKTAG) 433279697Snon return 0; 433379697Snon 433479697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 433579697Snon etag = cb->ccb_otag - 1; 433667468Snon#ifdef SCSI_LOW_DIAGNOSTIC 433779697Snon if (etag >= sizeof(li->li_qtagbits) * NBBY) 433879697Snon panic("scsi_low_dealloc_tag: illegal tag"); 433967468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 434079697Snon li->li_qtagbits |= (1 << etag); 434179697Snon 434279697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 434379697Snon etag = cb->ccb_otag; 434479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 434579697Snon if (etag >= SCSI_LOW_MAXNEXUS) 434679697Snon panic("scsi_low_dealloc_tag: illegal tag"); 434779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 434879697Snon li->li_qtagarray[etag] --; 434979697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 435079697Snon 435179697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 435279697Snon return 0; 435379697Snon} 435479697Snon 4355104094Sphkstatic struct slccb * 435679697Snonscsi_low_revoke_ccb(slp, cb, fdone) 435779697Snon struct scsi_low_softc *slp; 435879697Snon struct slccb *cb; 435979697Snon int fdone; 436079697Snon{ 436179697Snon struct targ_info *ti = cb->ti; 436279697Snon struct lun_info *li = cb->li; 436379697Snon 436479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 436579697Snon if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) == 436679697Snon (CCB_STARTQ | CCB_DISCQ)) 436779697Snon { 4368106890Simp panic("%s: ccb in both queue", slp->sl_xname); 436967468Snon } 437079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 437167468Snon 437279697Snon if ((cb->ccb_flags & CCB_STARTQ) != 0) 437379697Snon { 437479697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 437579697Snon } 437679697Snon 437779697Snon if ((cb->ccb_flags & CCB_DISCQ) != 0) 437879697Snon { 437979697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 438079697Snon li->li_disc --; 438179697Snon ti->ti_disc --; 438279697Snon slp->sl_disc --; 438379697Snon } 438479697Snon 438579697Snon cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ | 438679697Snon CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL); 438779697Snon 438879697Snon if (fdone != 0 && 438979697Snon (cb->ccb_rcnt ++ >= slp->sl_max_retry || 439079697Snon (cb->ccb_flags & CCB_NORETRY) != 0)) 439179697Snon { 439279697Snon cb->ccb_error |= FATALIO; 439379697Snon cb->ccb_flags &= ~CCB_AUTOSENSE; 439479697Snon if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE) 4395106890Simp panic("%s: done ccb retried", slp->sl_xname); 439679697Snon return NULL; 439779697Snon } 439879697Snon else 439979697Snon { 440079697Snon cb->ccb_error |= PENDINGIO; 440179697Snon scsi_low_deactivate_qtag(cb); 440279697Snon scsi_low_ccb_message_retry(cb); 440379697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 440479697Snon return cb; 440579697Snon } 440667468Snon} 440767468Snon 4408104094Sphkstatic void 440979697Snonscsi_low_reset_nexus_lun(slp, li, fdone) 441079697Snon struct scsi_low_softc *slp; 441179697Snon struct lun_info *li; 441279697Snon int fdone; 441379697Snon{ 441479697Snon struct slccb *cb, *ncb, *ecb; 441579697Snon 441679697Snon if (li == NULL) 441779697Snon return; 441879697Snon 441979697Snon ecb = NULL; 442079697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb) 442179697Snon { 442279697Snon ncb = TAILQ_NEXT(cb, ccb_chain); 442379697Snon cb = scsi_low_revoke_ccb(slp, cb, fdone); 442479697Snon if (cb != NULL) 442579697Snon { 442679697Snon /* 442779697Snon * presumely keep ordering of io 442879697Snon */ 442979697Snon cb->ccb_flags |= CCB_STARTQ; 443079697Snon if (ecb == NULL) 443179697Snon { 443279697Snon TAILQ_INSERT_HEAD(&slp->sl_start,\ 443379697Snon cb, ccb_chain); 443479697Snon } 443579697Snon else 443679697Snon { 443779697Snon TAILQ_INSERT_AFTER(&slp->sl_start,\ 443879697Snon ecb, cb, ccb_chain); 443979697Snon } 444079697Snon ecb = cb; 444179697Snon } 444279697Snon } 444379697Snon} 444479697Snon 444567468Snon/************************************************************** 444667468Snon * Qurik setup 444767468Snon **************************************************************/ 444867468Snonstatic void 444979697Snonscsi_low_calcf_lun(li) 445067468Snon struct lun_info *li; 445167468Snon{ 445279697Snon struct targ_info *ti = li->li_ti; 445367468Snon struct scsi_low_softc *slp = ti->ti_sc; 445479697Snon u_int cfgflags, diskflags; 445567468Snon 445679697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID) 445779697Snon cfgflags = li->li_cfgflags; 445879697Snon else 445979697Snon cfgflags = 0; 446079697Snon 446179697Snon diskflags = li->li_diskflags & li->li_quirks; 446279697Snon 446379697Snon /* disconnect */ 446467468Snon li->li_flags &= ~SCSI_LOW_DISC; 446567468Snon if ((slp->sl_cfgflags & CFG_NODISC) == 0 && 446679697Snon (diskflags & SCSI_LOW_DISK_DISC) != 0 && 446779697Snon (cfgflags & SCSI_LOW_DISC) != 0) 446867468Snon li->li_flags |= SCSI_LOW_DISC; 446967468Snon 447079697Snon /* parity */ 447167468Snon li->li_flags |= SCSI_LOW_NOPARITY; 447267468Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && 447379697Snon (diskflags & SCSI_LOW_DISK_PARITY) != 0 && 447479697Snon (cfgflags & SCSI_LOW_NOPARITY) == 0) 447567468Snon li->li_flags &= ~SCSI_LOW_NOPARITY; 447667468Snon 447779697Snon /* qtag */ 447879697Snon if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 && 447979697Snon (cfgflags & SCSI_LOW_QTAG) != 0 && 448079697Snon (diskflags & SCSI_LOW_DISK_QTAG) != 0) 448179697Snon { 448279697Snon li->li_flags |= SCSI_LOW_QTAG; 448379697Snon li->li_maxnexus = SCSI_LOW_MAXNEXUS; 448479697Snon li->li_maxnqio = li->li_maxnexus; 448579697Snon } 448679697Snon else 448779697Snon { 448879697Snon li->li_flags &= ~SCSI_LOW_QTAG; 448979697Snon li->li_maxnexus = 0; 449079697Snon li->li_maxnqio = li->li_maxnexus; 449179697Snon } 449279697Snon 449379697Snon /* cmd link */ 449479697Snon li->li_flags &= ~SCSI_LOW_LINK; 449579697Snon if ((cfgflags & SCSI_LOW_LINK) != 0 && 449679697Snon (diskflags & SCSI_LOW_DISK_LINK) != 0) 449779697Snon li->li_flags |= SCSI_LOW_LINK; 449879697Snon 449979697Snon /* compatible flags */ 450067468Snon li->li_flags &= ~SCSI_LOW_SYNC; 450179697Snon if (ti->ti_maxsynch.offset > 0) 450279697Snon li->li_flags |= SCSI_LOW_SYNC; 450379697Snon 450479697Snon#ifdef SCSI_LOW_DEBUG 450579697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 450667468Snon { 450779697Snon scsi_low_calcf_show(li); 450867468Snon } 450979697Snon#endif /* SCSI_LOW_DEBUG */ 451079697Snon} 451179697Snon 451279697Snonstatic void 451379697Snonscsi_low_calcf_target(ti) 451479697Snon struct targ_info *ti; 451579697Snon{ 451679697Snon struct scsi_low_softc *slp = ti->ti_sc; 451779697Snon u_int offset, period, diskflags; 451879697Snon 451979697Snon diskflags = ti->ti_diskflags & ti->ti_quirks; 452079697Snon 452179697Snon /* synch */ 452279697Snon if ((slp->sl_cfgflags & CFG_ASYNC) == 0 && 452379697Snon (diskflags & SCSI_LOW_DISK_SYNC) != 0) 452479697Snon { 452579697Snon offset = ti->ti_maxsynch.offset; 452679697Snon period = ti->ti_maxsynch.period; 452779697Snon if (offset == 0 || period == 0) 452879697Snon offset = period = 0; 452979697Snon } 453067468Snon else 453179697Snon { 453279697Snon offset = period = 0; 453379697Snon } 453467468Snon 453579697Snon ti->ti_maxsynch.offset = offset; 453679697Snon ti->ti_maxsynch.period = period; 453779697Snon 453879697Snon /* wide */ 453979697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 && 454079697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 454179697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_16; 454279697Snon 454379697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 && 454479697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 454579697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 454679697Snon 454779697Snon if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID) 454867468Snon { 454979697Snon if (ti->ti_maxsynch.offset != ti->ti_osynch.offset || 455079697Snon ti->ti_maxsynch.period != ti->ti_osynch.period) 455179697Snon ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH; 455279697Snon if (ti->ti_width != ti->ti_owidth) 455379697Snon ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH); 455479697Snon 455579697Snon ti->ti_osynch = ti->ti_maxsynch; 455679697Snon ti->ti_owidth = ti->ti_width; 455767468Snon } 455867468Snon 455979697Snon#ifdef SCSI_LOW_DEBUG 456079697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 456179697Snon { 456279697Snon printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n", 456379697Snon slp->sl_xname, ti->ti_id, 456479697Snon ti->ti_maxsynch.period * 4, 456579697Snon ti->ti_maxsynch.offset, 456679697Snon ti->ti_width); 456779697Snon } 456879697Snon#endif /* SCSI_LOW_DEBUG */ 456967468Snon} 457067468Snon 457179697Snonstatic void 457279697Snonscsi_low_calcf_show(li) 457379697Snon struct lun_info *li; 457479697Snon{ 457579697Snon struct targ_info *ti = li->li_ti; 457679697Snon struct scsi_low_softc *slp = ti->ti_sc; 457779697Snon 457879697Snon printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n", 457979697Snon slp->sl_xname, ti->ti_id, li->li_lun, 458079697Snon ti->ti_maxsynch.period * 4, 458179697Snon ti->ti_maxsynch.offset, 458279697Snon ti->ti_width, 458379697Snon li->li_flags, SCSI_LOW_BITS); 458479697Snon} 458579697Snon 458679697Snon#ifdef SCSI_LOW_START_UP_CHECK 458779697Snon/************************************************************** 458879697Snon * scsi world start up 458979697Snon **************************************************************/ 459092770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *); 459179697Snon 459267468Snonstatic int 459379697Snonscsi_low_start_up(slp) 459479697Snon struct scsi_low_softc *slp; 459567468Snon{ 459667468Snon struct targ_info *ti; 459767468Snon struct lun_info *li; 459879697Snon struct slccb *cb; 459979697Snon int target, lun; 460067468Snon 460179697Snon printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname); 460267468Snon 460379697Snon for (target = 0; target < slp->sl_ntargs; target ++) 460479697Snon { 460579697Snon if (target == slp->sl_hostid) 460679697Snon { 460779697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 460879697Snon { 460979697Snon printf("%s: scsi_low: target %d (host card)\n", 461079697Snon slp->sl_xname, target); 461179697Snon } 461279697Snon continue; 461379697Snon } 461467468Snon 461579697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 461679697Snon { 461779697Snon printf("%s: scsi_low: target %d lun ", 461879697Snon slp->sl_xname, target); 461979697Snon } 462067468Snon 462179697Snon ti = slp->sl_ti[target]; 462279697Snon for (lun = 0; lun < slp->sl_nluns; lun ++) 462379697Snon { 462479697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 462579697Snon break; 462679697Snon 462779697Snon cb->osdep = NULL; 462879697Snon cb->bp = NULL; 462979697Snon 463079697Snon li = scsi_low_alloc_li(ti, lun, 1); 463179697Snon 463279697Snon scsi_low_enqueue(slp, ti, li, cb, 463379697Snon CCB_AUTOSENSE | CCB_POLLED, 0); 463479697Snon 463579697Snon scsi_low_poll(slp, cb); 463679697Snon 463779697Snon if (li->li_state != SCSI_LOW_LUN_OK) 463879697Snon break; 463979697Snon 464079697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 464179697Snon { 464279697Snon printf("%d ", lun); 464379697Snon } 464479697Snon } 464579697Snon 464679697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 464779697Snon { 464879697Snon printf("\n"); 464979697Snon } 465079697Snon } 465167468Snon return 0; 465267468Snon} 465367468Snon 465479697Snonstatic int 465579697Snonscsi_low_poll(slp, cb) 465679697Snon struct scsi_low_softc *slp; 465779697Snon struct slccb *cb; 465879697Snon{ 465979697Snon int tcount; 466079697Snon 466179697Snon tcount = 0; 466279697Snon while (slp->sl_nio > 0) 466379697Snon { 466479697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ); 466579697Snon 466679697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 466779697Snon if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 466879697Snon continue; 466979697Snon 467079697Snon tcount = 0; 467179697Snon scsi_low_timeout_check(slp); 467279697Snon } 467379697Snon 467479697Snon return 0; 467579697Snon} 467679697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 467779697Snon 467867468Snon/********************************************************** 467967468Snon * DEBUG SECTION 468067468Snon **********************************************************/ 468179697Snon#ifdef SCSI_LOW_DEBUG 468267468Snonstatic void 468379697Snonscsi_low_test_abort(slp, ti, li) 468479697Snon struct scsi_low_softc *slp; 468579697Snon struct targ_info *ti; 468679697Snon struct lun_info *li; 468779697Snon{ 468879697Snon struct slccb *acb; 468979697Snon 469079697Snon if (li->li_disc > 1) 469179697Snon { 469279697Snon acb = TAILQ_FIRST(&li->li_discq); 469379697Snon if (scsi_low_abort_ccb(slp, acb) == 0) 469479697Snon { 469579697Snon printf("%s: aborting ccb(0x%lx) start\n", 469679697Snon slp->sl_xname, (u_long) acb); 469779697Snon } 469879697Snon } 469979697Snon} 470079697Snon 470179697Snonstatic void 470279697Snonscsi_low_test_atten(slp, ti, msg) 470379697Snon struct scsi_low_softc *slp; 470479697Snon struct targ_info *ti; 470579697Snon u_int msg; 470679697Snon{ 470779697Snon 470879697Snon if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK) 470979697Snon scsi_low_assert_msg(slp, ti, msg, 0); 471079697Snon else 471179697Snon printf("%s: atten check OK\n", slp->sl_xname); 471279697Snon} 471379697Snon 471479697Snonstatic void 471579697Snonscsi_low_test_cmdlnk(slp, cb) 471679697Snon struct scsi_low_softc *slp; 471779697Snon struct slccb *cb; 471879697Snon{ 471979697Snon#define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ) 472079697Snon 472179697Snon if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0) 472279697Snon return; 472379697Snon 472479697Snon memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd, 472579697Snon slp->sl_scp.scp_cmdlen); 472679697Snon cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1; 472779697Snon slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd; 472879697Snon} 472979697Snon#endif /* SCSI_LOW_DEBUG */ 473079697Snon 473179697Snon/* static */ void 473267468Snonscsi_low_info(slp, ti, s) 473367468Snon struct scsi_low_softc *slp; 473467468Snon struct targ_info *ti; 473567468Snon u_char *s; 473667468Snon{ 473767468Snon 473879697Snon if (slp == NULL) 473979697Snon slp = LIST_FIRST(&sl_tab); 474079697Snon if (s == NULL) 474179697Snon s = "no message"; 474279697Snon 474379697Snon printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s); 474467468Snon if (ti == NULL) 474567468Snon { 474679697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 474779697Snon ti = TAILQ_NEXT(ti, ti_chain)) 474879697Snon { 474967468Snon scsi_low_print(slp, ti); 475079697Snon } 475167468Snon } 475267468Snon else 475379697Snon { 475467468Snon scsi_low_print(slp, ti); 475579697Snon } 475667468Snon} 475767468Snon 475867468Snonstatic u_char *phase[] = 475967468Snon{ 476067468Snon "FREE", "ARBSTART", "SELSTART", "SELECTED", 476167468Snon "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" 476267468Snon}; 476367468Snon 476467468Snonvoid 476567468Snonscsi_low_print(slp, ti) 476667468Snon struct scsi_low_softc *slp; 476767468Snon struct targ_info *ti; 476867468Snon{ 476979697Snon struct lun_info *li; 477079697Snon struct slccb *cb; 477179697Snon struct sc_p *sp; 477267468Snon 477379697Snon if (ti == NULL || ti == slp->sl_Tnexus) 477479697Snon { 477579697Snon ti = slp->sl_Tnexus; 477679697Snon li = slp->sl_Lnexus; 477779697Snon cb = slp->sl_Qnexus; 477879697Snon } 477979697Snon else 478079697Snon { 478179697Snon li = LIST_FIRST(&ti->ti_litab); 478279697Snon cb = TAILQ_FIRST(&li->li_discq); 478379697Snon } 478479697Snon sp = &slp->sl_scp; 478567468Snon 478679697Snon printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n", 478779697Snon slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb, 478879697Snon slp->sl_nio); 478967468Snon 479067468Snon /* target stat */ 479167468Snon if (ti != NULL) 479267468Snon { 479379697Snon u_int flags = 0, maxnqio = 0, nqio = 0; 479467468Snon int lun = -1; 479567468Snon 479667468Snon if (li != NULL) 479767468Snon { 479867468Snon lun = li->li_lun; 479967468Snon flags = li->li_flags; 480079697Snon maxnqio = li->li_maxnqio; 480179697Snon nqio = li->li_nqio; 480267468Snon } 480367468Snon 480479697Snon printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n", 480579697Snon slp->sl_xname, 480667468Snon ti->ti_id, lun, phase[(int) ti->ti_ophase], 480779697Snon phase[(int) ti->ti_phase], ti->ti_disc, 480879697Snon nqio, maxnqio); 480967468Snon 481079697Snon if (cb != NULL) 481179697Snon { 481279697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n", 481379697Snon (u_int) cb->ccb_scp.scp_cmd[0], 481479697Snon cb->ccb_scp.scp_cmdlen, 481579697Snon cb->ccb_datalen, 481679697Snon cb->ccb_scp.scp_datalen, 481779697Snon (u_int) cb->ccb_sscp.scp_status, 481879697Snon cb->ccb_error, SCSI_LOW_ERRORBITS); 481979697Snon } 482067468Snon 482179697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n", 482279697Snon (u_int) (ti->ti_msginptr), 482379697Snon (u_int) (ti->ti_msgin[0]), 482479697Snon (u_int) (ti->ti_msgin[1]), 482579697Snon (u_int) (ti->ti_msgin[2]), 482679697Snon (u_int) (ti->ti_msgin[3]), 482779697Snon (u_int) (ti->ti_msgin[4]), 482879697Snon slp->sl_atten); 482979697Snon 483067468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", 483179697Snon (u_int) ti->ti_msgflags, 483279697Snon (u_int) (ti->ti_msgoutstr[0]), 483379697Snon (u_int) (ti->ti_msgoutstr[1]), 483479697Snon (u_int) (ti->ti_msgoutstr[2]), 483579697Snon (u_int) (ti->ti_msgoutstr[3]), 483679697Snon (u_int) (ti->ti_msgoutstr[4]), 483779697Snon ti->ti_msgoutlen, 483879697Snon flags, SCSI_LOW_BITS); 483967468Snon 484079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 484179697Snon scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2); 484279697Snon scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2); 484379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 484467468Snon 484567468Snon } 484679697Snon 484779697Snon printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n", 484879697Snon (u_long) sp->scp_data, 484979697Snon sp->scp_datalen, 485079697Snon (u_int) sp->scp_status, 485179697Snon slp->sl_error, SCSI_LOW_ERRORBITS); 485267468Snon} 4853