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: stable/10/sys/cam/scsi/scsi_low.c 315813 2017-03-23 06:41:13Z mav $"); 6116162Sobrien 767468Snon#define SCSI_LOW_STATICS 879697Snon#define SCSI_LOW_DEBUG 979697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE 1079697Snon#define SCSI_LOW_START_UP_CHECK 1179697Snon 1279697Snon/* #define SCSI_LOW_INFO_DETAIL */ 13116162Sobrien 1479697Snon/* #define SCSI_LOW_QCLEAR_AFTER_CA */ 1579697Snon/* #define SCSI_LOW_FLAGS_QUIRKS_OK */ 1679697Snon 1779697Snon#define SCSI_LOW_FLAGS_QUIRKS_OK 1879697Snon 19139743Simp/*- 2067468Snon * [NetBSD for NEC PC-98 series] 2179697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2267468Snon * NetBSD/pc98 porting staff. All rights reserved. 2379697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2467468Snon * Naofumi HONDA. All rights reserved. 2579697Snon * 2679697Snon * [Ported for FreeBSD CAM] 2779697Snon * Copyright (c) 2000, 2001 2879697Snon * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. 2979697Snon * All rights reserved. 3067468Snon * 3167468Snon * Redistribution and use in source and binary forms, with or without 3267468Snon * modification, are permitted provided that the following conditions 3367468Snon * are met: 3467468Snon * 1. Redistributions of source code must retain the above copyright 3567468Snon * notice, this list of conditions and the following disclaimer. 3667468Snon * 2. Redistributions in binary form must reproduce the above copyright 3767468Snon * notice, this list of conditions and the following disclaimer in the 3867468Snon * documentation and/or other materials provided with the distribution. 3967468Snon * 3. The name of the author may not be used to endorse or promote products 4067468Snon * derived from this software without specific prior written permission. 4167468Snon * 4267468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4367468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 4467468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4567468Snon * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 4667468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 4767468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 4867468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4967468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 5067468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 5167468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5267468Snon * POSSIBILITY OF SUCH DAMAGE. 5367468Snon */ 5467468Snon 5567468Snon/* <On the nexus establishment> 5667468Snon * When our host is reselected, 5767468Snon * nexus establish processes are little complicated. 5867468Snon * Normal steps are followings: 5979697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus) 6079697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus) 6179697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus) 6267468Snon */ 6367468Snon#include "opt_ddb.h" 6467468Snon 6567468Snon#include <sys/param.h> 6667468Snon#include <sys/systm.h> 6767468Snon#include <sys/kernel.h> 6867468Snon#include <sys/bio.h> 6967468Snon#include <sys/buf.h> 7067468Snon#include <sys/queue.h> 7167468Snon#include <sys/malloc.h> 7267468Snon#include <sys/errno.h> 7367468Snon 7467468Snon#include <cam/cam.h> 7567468Snon#include <cam/cam_ccb.h> 7667468Snon#include <cam/cam_sim.h> 7767468Snon#include <cam/cam_debug.h> 7867468Snon#include <cam/cam_periph.h> 79147723Savatar#include <cam/cam_xpt_periph.h> 8067468Snon 8167468Snon#include <cam/scsi/scsi_all.h> 8273025Snon#include <cam/scsi/scsi_message.h> 8367468Snon 8467468Snon#include <cam/scsi/scsi_low.h> 8567468Snon 8667468Snon#include <sys/cons.h> 8767468Snon 8879697Snon/************************************************************** 8979697Snon * Constants 9079697Snon **************************************************************/ 9179697Snon#define SCSI_LOW_POLL_HZ 1000 9267468Snon 9379697Snon/* functions return values */ 9479697Snon#define SCSI_LOW_START_NO_QTAG 0 9579697Snon#define SCSI_LOW_START_QTAG 1 9679697Snon 9767468Snon#define SCSI_LOW_DONE_COMPLETE 0 9867468Snon#define SCSI_LOW_DONE_RETRY 1 9967468Snon 10079697Snon/* internal disk flags */ 10179697Snon#define SCSI_LOW_DISK_DISC 0x00000001 10279697Snon#define SCSI_LOW_DISK_QTAG 0x00000002 10379697Snon#define SCSI_LOW_DISK_LINK 0x00000004 10479697Snon#define SCSI_LOW_DISK_PARITY 0x00000008 10579697Snon#define SCSI_LOW_DISK_SYNC 0x00010000 10679697Snon#define SCSI_LOW_DISK_WIDE_16 0x00020000 10779697Snon#define SCSI_LOW_DISK_WIDE_32 0x00040000 10879697Snon#define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32) 10979697Snon#define SCSI_LOW_DISK_LFLAGS 0x0000ffff 11079697Snon#define SCSI_LOW_DISK_TFLAGS 0xffff0000 11179697Snon 112227293Sedstatic MALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers"); 113147723Savatar 11479697Snon/************************************************************** 11579697Snon * Declarations 11679697Snon **************************************************************/ 11792770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *); 11892770Salfredstatic void scsi_low_engage(void *); 11992770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t); 12092770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *); 12192770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *); 12292770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *); 12392770Salfredstatic void scsi_low_twiddle_wait(void); 12492770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int); 12592770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int); 12692770Salfredstatic void scsi_low_calcf_lun(struct lun_info *); 12792770Salfredstatic void scsi_low_calcf_target(struct targ_info *); 12892770Salfredstatic void scsi_low_calcf_show(struct lun_info *); 12992770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int); 13092770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int); 13192770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int); 13292770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int); 13392770Salfredstatic void scsi_low_start(struct scsi_low_softc *); 13492770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *); 13567468Snon 13692770Salfredstatic int scsi_low_alloc_qtag(struct slccb *); 13792770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *); 13892770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int); 13992770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int); 14092770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *); 14192770Salfredstatic void scsi_low_timeout(void *); 14292770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *); 14379697Snon#ifdef SCSI_LOW_START_UP_CHECK 14492770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *); 14579697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 14692770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *); 14792770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int); 14879697Snon 14979697Snonint scsi_low_version_major = 2; 15079697Snonint scsi_low_version_minor = 17; 15179697Snon 15279697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab); 15379697Snon 15479697Snon/************************************************************** 15579697Snon * Debug, Run test and Statics 15679697Snon **************************************************************/ 15779697Snon#ifdef SCSI_LOW_INFO_DETAIL 15879697Snon#define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s)) 15979697Snon#else /* !SCSI_LOW_INFO_DETAIL */ 160240325Sjhb#define SCSI_LOW_INFO(slp, ti, s) device_printf((slp)->sl_dev, "%s\n", (s)) 16179697Snon#endif /* !SCSI_LOW_INFO_DETAIL */ 16279697Snon 16367468Snon#ifdef SCSI_LOW_STATICS 16489113Smsmithstatic struct scsi_low_statics { 16567468Snon int nexus_win; 16667468Snon int nexus_fail; 16767468Snon int nexus_disconnected; 16867468Snon int nexus_reselected; 16967468Snon int nexus_conflict; 17067468Snon} scsi_low_statics; 17167468Snon#endif /* SCSI_LOW_STATICS */ 17279697Snon 17379697Snon#ifdef SCSI_LOW_DEBUG 17479697Snon#define SCSI_LOW_DEBUG_DONE 0x00001 17579697Snon#define SCSI_LOW_DEBUG_DISC 0x00002 17679697Snon#define SCSI_LOW_DEBUG_SENSE 0x00004 17779697Snon#define SCSI_LOW_DEBUG_CALCF 0x00008 17879697Snon#define SCSI_LOW_DEBUG_ACTION 0x10000 17979697Snonint scsi_low_debug = 0; 18079697Snon 18179697Snon#define SCSI_LOW_MAX_ATTEN_CHECK 32 18279697Snon#define SCSI_LOW_ATTEN_CHECK 0x0001 18379697Snon#define SCSI_LOW_CMDLNK_CHECK 0x0002 18479697Snon#define SCSI_LOW_ABORT_CHECK 0x0004 18579697Snon#define SCSI_LOW_NEXUS_CHECK 0x0008 18679697Snonint scsi_low_test = 0; 18779697Snonint scsi_low_test_id = 0; 18879697Snon 18992770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *); 19092770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *); 19192770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int); 19279697Snon#define SCSI_LOW_DEBUG_TEST_GO(fl, id) \ 19379697Snon ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 19479697Snon#define SCSI_LOW_DEBUG_GO(fl, id) \ 19579697Snon ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 19679697Snon#endif /* SCSI_LOW_DEBUG */ 19779697Snon 19867468Snon/************************************************************** 19979697Snon * CCB 20079697Snon **************************************************************/ 20179697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) 20279697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain) 20379697Snon 20479697Snon/************************************************************** 20579697Snon * Inline functions 20679697Snon **************************************************************/ 20779697Snon#define SCSI_LOW_INLINE static __inline 20892770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *); 20992770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *); 21092770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int); 21192770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *); 21292770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *); 21392770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *); 21492770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *); 21579697Snon 21679697SnonSCSI_LOW_INLINE void 21779697Snonscsi_low_activate_qtag(cb) 21879697Snon struct slccb *cb; 21979697Snon{ 22079697Snon struct lun_info *li = cb->li; 22179697Snon 22279697Snon if (cb->ccb_tag != SCSI_LOW_UNKTAG) 22379697Snon return; 22479697Snon 22579697Snon li->li_nqio ++; 22679697Snon cb->ccb_tag = cb->ccb_otag; 22779697Snon} 22879697Snon 22979697SnonSCSI_LOW_INLINE void 23079697Snonscsi_low_deactivate_qtag(cb) 23179697Snon struct slccb *cb; 23279697Snon{ 23379697Snon struct lun_info *li = cb->li; 23479697Snon 23579697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 23679697Snon return; 23779697Snon 23879697Snon li->li_nqio --; 23979697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 24079697Snon} 24179697Snon 24279697SnonSCSI_LOW_INLINE void 24379697Snonscsi_low_ccb_message_exec(slp, cb) 24479697Snon struct scsi_low_softc *slp; 24579697Snon struct slccb *cb; 24679697Snon{ 24779697Snon 24879697Snon scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0); 24979697Snon cb->ccb_msgoutflag = 0; 25079697Snon} 25179697Snon 25279697SnonSCSI_LOW_INLINE void 25379697Snonscsi_low_ccb_message_assert(cb, msg) 25479697Snon struct slccb *cb; 25579697Snon u_int msg; 25679697Snon{ 25779697Snon 25879697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg; 25979697Snon} 26079697Snon 26179697SnonSCSI_LOW_INLINE void 26279697Snonscsi_low_ccb_message_retry(cb) 26379697Snon struct slccb *cb; 26479697Snon{ 26579697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag; 26679697Snon} 26779697Snon 26879697SnonSCSI_LOW_INLINE void 26979697Snonscsi_low_ccb_message_clear(cb) 27079697Snon struct slccb *cb; 27179697Snon{ 27279697Snon cb->ccb_msgoutflag = 0; 27379697Snon} 27479697Snon 27579697SnonSCSI_LOW_INLINE void 27679697Snonscsi_low_init_msgsys(slp, ti) 27779697Snon struct scsi_low_softc *slp; 27879697Snon struct targ_info *ti; 27979697Snon{ 28079697Snon 28179697Snon ti->ti_msginptr = 0; 28279697Snon ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; 28379697Snon SCSI_LOW_DEASSERT_ATN(slp); 28479697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 28579697Snon} 28679697Snon 28779697Snon/*============================================================= 28879697Snon * START OF OS switch (All OS depend fucntions should be here) 28979697Snon =============================================================*/ 29079697Snon/* common os depend utitlities */ 29179697Snon#define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001 29279697Snon#define SCSI_LOW_CMD_ORDERED_QTAG 0x0002 29379697Snon#define SCSI_LOW_CMD_ABORT_WARNING 0x0004 29479697Snon 29579697Snonstatic u_int8_t scsi_low_cmd_flags[256] = { 29679697Snon/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 29779697Snon/*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 29879697Snon/*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 29979697Snon/*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5, 30079697Snon/*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 30179697Snon}; 30279697Snon 30379697Snonstruct scsi_low_error_code { 30479697Snon int error_bits; 30579697Snon int error_code; 30679697Snon}; 30779697Snon 30892770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *); 30992770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *); 31079697Snon 31179697Snonstatic struct slccb * 31279697Snonscsi_low_find_ccb(slp, target, lun, osdep) 31379697Snon struct scsi_low_softc *slp; 31479697Snon u_int target, lun; 31579697Snon void *osdep; 31679697Snon{ 31779697Snon struct targ_info *ti; 31879697Snon struct lun_info *li; 31979697Snon struct slccb *cb; 32079697Snon 32179697Snon ti = slp->sl_ti[target]; 32279697Snon li = scsi_low_alloc_li(ti, lun, 0); 32379697Snon if (li == NULL) 32479697Snon return NULL; 32579697Snon 32679697Snon if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep) 32779697Snon return cb; 32879697Snon 329288693Smav TAILQ_FOREACH(cb, &slp->sl_start, ccb_chain) 33079697Snon { 33179697Snon if (cb->osdep == osdep) 33279697Snon return cb; 33379697Snon } 33479697Snon 335288693Smav TAILQ_FOREACH(cb, &li->li_discq, ccb_chain) 33679697Snon { 33779697Snon if (cb->osdep == osdep) 33879697Snon return cb; 33979697Snon } 34079697Snon return NULL; 34179697Snon} 34279697Snon 34379697Snonstatic int 34479697Snonscsi_low_translate_error_code(cb, tp) 34579697Snon struct slccb *cb; 34679697Snon struct scsi_low_error_code *tp; 34779697Snon{ 34879697Snon 34979697Snon if (cb->ccb_error == 0) 35079697Snon return tp->error_code; 35179697Snon 35279697Snon for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++) 35379697Snon ; 35479697Snon return tp->error_code; 35579697Snon} 35679697Snon 35779697Snon/************************************************************** 35879697Snon * SCSI INTERFACE (CAM) 35979697Snon **************************************************************/ 360147723Savatar#define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) 361147723Savatar#define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) 36279697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb() 36379697Snon 36492770Salfredstatic void scsi_low_poll_cam(struct cam_sim *); 36592770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *); 36679697Snon 36792770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *); 36892770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *); 36992770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *); 37092770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *); 37192770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *); 37292770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int); 37379697Snon 37479697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = { 37579697Snon scsi_low_attach_cam, 37679697Snon scsi_low_world_start_cam, 37779697Snon scsi_low_dettach_cam, 37879697Snon scsi_low_ccb_setup_cam, 37979697Snon scsi_low_done_cam, 38079697Snon scsi_low_timeout_cam 38179697Snon}; 38279697Snon 38379697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = { 38479697Snon {0, CAM_REQ_CMP}, 38579697Snon {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR}, 38679697Snon {SENSEERR, CAM_AUTOSENSE_FAIL}, 38779697Snon {UACAERR, CAM_SCSI_STATUS_ERROR}, 38879697Snon {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR}, 38979697Snon {SELTIMEOUTIO, CAM_SEL_TIMEOUT}, 39079697Snon {TIMEOUTIO, CAM_CMD_TIMEOUT}, 39179697Snon {PDMAERR, CAM_DATA_RUN_ERR}, 39279697Snon {PARITYERR, CAM_UNCOR_PARITY}, 39379697Snon {UBFERR, CAM_UNEXP_BUSFREE}, 39479697Snon {ABORTIO, CAM_REQ_ABORTED}, 39579697Snon {-1, CAM_UNREC_HBA_ERROR} 39679697Snon}; 39779697Snon 39879697Snon#define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim))) 39979697Snon 40079697Snon/* XXX: 40179697Snon * Please check a polling hz, currently we assume scsi_low_poll() is 40279697Snon * called each 1 ms. 40379697Snon */ 40479697Snon#define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */ 40579697Snon 40679697Snonstatic void 40779697Snonscsi_low_poll_cam(sim) 40879697Snon struct cam_sim *sim; 40979697Snon{ 41079697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 41179697Snon 41279697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 41379697Snon 41479697Snon if (slp->sl_si.si_poll_count ++ >= 41579697Snon SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 41679697Snon { 41779697Snon slp->sl_si.si_poll_count = 0; 41879697Snon scsi_low_timeout_check(slp); 41979697Snon } 42079697Snon} 42179697Snon 42279697Snonvoid 42379697Snonscsi_low_scsi_action_cam(sim, ccb) 42479697Snon struct cam_sim *sim; 42579697Snon union ccb *ccb; 42679697Snon{ 42779697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 42879697Snon struct targ_info *ti; 42979697Snon struct lun_info *li; 43079697Snon struct slccb *cb; 43179697Snon u_int lun, flags, msg, target; 43279697Snon int s, rv; 43379697Snon 43479697Snon target = (u_int) (ccb->ccb_h.target_id); 43579697Snon lun = (u_int) ccb->ccb_h.target_lun; 43679697Snon 43779697Snon#ifdef SCSI_LOW_DEBUG 43879697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0) 43979697Snon { 440240325Sjhb device_printf(slp->sl_dev, 441240325Sjhb "cam_action: func code 0x%x target: %d, lun: %d\n", 442240325Sjhb ccb->ccb_h.func_code, target, lun); 44379697Snon } 44479697Snon#endif /* SCSI_LOW_DEBUG */ 44579697Snon 44679697Snon switch (ccb->ccb_h.func_code) { 44779697Snon case XPT_SCSI_IO: /* Execute the requested I/O operation */ 44879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 44979697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 45079697Snon { 451240325Sjhb device_printf(slp->sl_dev, "invalid target/lun\n"); 45279697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 45379697Snon xpt_done(ccb); 45479697Snon return; 45579697Snon } 45679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 45779697Snon 45879697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { 45979697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 46079697Snon xpt_done(ccb); 46179697Snon return; 46279697Snon } 46379697Snon 46479697Snon ti = slp->sl_ti[target]; 46579697Snon cb->osdep = ccb; 46679697Snon cb->bp = NULL; 46779697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 46879697Snon flags = CCB_AUTOSENSE | CCB_SCSIIO; 46979697Snon else 47079697Snon flags = CCB_SCSIIO; 47179697Snon 472240172Sjhb s = splcam(); 47379697Snon li = scsi_low_alloc_li(ti, lun, 1); 47479697Snon 47579697Snon if (ti->ti_setup_msg != 0) 47679697Snon { 47779697Snon scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE); 47879697Snon } 47979697Snon 48079697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 48179697Snon 48279697Snon#ifdef SCSI_LOW_DEBUG 48379697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0) 48479697Snon { 48579697Snon scsi_low_test_abort(slp, ti, li); 48679697Snon } 48779697Snon#endif /* SCSI_LOW_DEBUG */ 48879697Snon splx(s); 48979697Snon break; 49079697Snon 49179697Snon case XPT_EN_LUN: /* Enable LUN as a target */ 49279697Snon case XPT_TARGET_IO: /* Execute target I/O request */ 49379697Snon case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 49479697Snon case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 49579697Snon /* XXX Implement */ 49679697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 49779697Snon xpt_done(ccb); 49879697Snon break; 49979697Snon 50079697Snon case XPT_ABORT: /* Abort the specified CCB */ 50179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 50279697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 50379697Snon { 504240325Sjhb device_printf(slp->sl_dev, "invalid target/lun\n"); 50579697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 50679697Snon xpt_done(ccb); 50779697Snon return; 50879697Snon } 50979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 51079697Snon 511240172Sjhb s = splcam(); 51279697Snon cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb); 51379697Snon rv = scsi_low_abort_ccb(slp, cb); 51479697Snon splx(s); 51579697Snon 51679697Snon if (rv == 0) 51779697Snon ccb->ccb_h.status = CAM_REQ_CMP; 51879697Snon else 51979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 52079697Snon xpt_done(ccb); 52179697Snon break; 52279697Snon 52379697Snon case XPT_SET_TRAN_SETTINGS: { 524163816Smjacob struct ccb_trans_settings_scsi *scsi; 525163816Smjacob struct ccb_trans_settings_spi *spi; 52679697Snon struct ccb_trans_settings *cts; 52779697Snon u_int val; 52879697Snon 52979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 53079697Snon if (target == CAM_TARGET_WILDCARD) 53179697Snon { 532240325Sjhb device_printf(slp->sl_dev, "invalid target\n"); 53379697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 53479697Snon xpt_done(ccb); 53579697Snon return; 53679697Snon } 53779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 53879697Snon cts = &ccb->cts; 53979697Snon ti = slp->sl_ti[target]; 54079697Snon if (lun == CAM_LUN_WILDCARD) 54179697Snon lun = 0; 54279697Snon 543240172Sjhb s = splcam(); 544163816Smjacob scsi = &cts->proto_specific.scsi; 545163816Smjacob spi = &cts->xport_specific.spi; 546163816Smjacob if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH | 547163816Smjacob CTS_SPI_VALID_SYNC_RATE | 548163816Smjacob CTS_SPI_VALID_SYNC_OFFSET)) != 0) 549163816Smjacob { 550163816Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 551163816Smjacob val = spi->bus_width; 552163816Smjacob if (val < ti->ti_width) 553163816Smjacob ti->ti_width = val; 554163816Smjacob } 555163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_RATE) { 556163816Smjacob val = spi->sync_period; 557163816Smjacob if (val == 0 || val > ti->ti_maxsynch.period) 558163816Smjacob ti->ti_maxsynch.period = val; 559163816Smjacob } 560163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 561163816Smjacob val = spi->sync_offset; 562163816Smjacob if (val < ti->ti_maxsynch.offset) 563163816Smjacob ti->ti_maxsynch.offset = val; 564163816Smjacob } 565163816Smjacob ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 566163816Smjacob scsi_low_calcf_target(ti); 567163816Smjacob } 568163816Smjacob 569163816Smjacob if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 || 570163816Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 571163816Smjacob 572163816Smjacob li = scsi_low_alloc_li(ti, lun, 1); 573163816Smjacob if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) { 574163816Smjacob li->li_quirks |= SCSI_LOW_DISK_DISC; 575163816Smjacob } else { 576163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_DISC; 577163816Smjacob } 578163816Smjacob 579163816Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 580163816Smjacob li->li_quirks |= SCSI_LOW_DISK_QTAG; 581163816Smjacob } else { 582163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_QTAG; 583163816Smjacob } 584163816Smjacob li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 585163816Smjacob scsi_low_calcf_target(ti); 586163816Smjacob scsi_low_calcf_lun(li); 587163816Smjacob if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) 588163816Smjacob scsi_low_calcf_show(li); 589163816Smjacob } 59079697Snon splx(s); 59179697Snon 59279697Snon ccb->ccb_h.status = CAM_REQ_CMP; 59379697Snon xpt_done(ccb); 59479697Snon break; 59579697Snon } 59679697Snon 59779697Snon case XPT_GET_TRAN_SETTINGS: { 59879697Snon struct ccb_trans_settings *cts; 59979697Snon u_int diskflags; 60079697Snon 60179697Snon cts = &ccb->cts; 60279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 60379697Snon if (target == CAM_TARGET_WILDCARD) 60479697Snon { 605240325Sjhb device_printf(slp->sl_dev, "invalid target\n"); 60679697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 60779697Snon xpt_done(ccb); 60879697Snon return; 60979697Snon } 61079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 61179697Snon ti = slp->sl_ti[target]; 61279697Snon if (lun == CAM_LUN_WILDCARD) 61379697Snon lun = 0; 61479697Snon 615240172Sjhb s = splcam(); 61679697Snon li = scsi_low_alloc_li(ti, lun, 1); 61779697Snon if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) { 61879697Snon struct ccb_trans_settings_scsi *scsi = 61979697Snon &cts->proto_specific.scsi; 62079697Snon struct ccb_trans_settings_spi *spi = 62179697Snon &cts->xport_specific.spi; 62279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 62379697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 62479697Snon { 62579697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 626240325Sjhb device_printf(slp->sl_dev, 627240325Sjhb "invalid GET_TRANS_CURRENT_SETTINGS call\n"); 62879697Snon goto settings_out; 62979697Snon } 63079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 63179697Snon cts->protocol = PROTO_SCSI; 63279697Snon cts->protocol_version = SCSI_REV_2; 63379697Snon cts->transport = XPORT_SPI; 63479697Snon cts->transport_version = 2; 63579697Snon 63679697Snon scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 63779697Snon spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 63879697Snon 63979697Snon diskflags = li->li_diskflags & li->li_cfgflags; 64079697Snon if (diskflags & SCSI_LOW_DISK_DISC) 64179697Snon spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 64279697Snon if (diskflags & SCSI_LOW_DISK_QTAG) 64379697Snon scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 64479697Snon 64579697Snon spi->sync_period = ti->ti_maxsynch.period; 64679697Snon spi->valid |= CTS_SPI_VALID_SYNC_RATE; 64779697Snon spi->sync_offset = ti->ti_maxsynch.offset; 64879697Snon spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 64979697Snon 65079697Snon spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 65179697Snon spi->bus_width = ti->ti_width; 65279697Snon 65379697Snon if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 65479697Snon scsi->valid = CTS_SCSI_VALID_TQ; 65579697Snon spi->valid |= CTS_SPI_VALID_DISC; 65679697Snon } else 65779697Snon scsi->valid = 0; 65879697Snon } else 65979697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 66079697Snonsettings_out: 66179697Snon splx(s); 66279697Snon xpt_done(ccb); 66379697Snon break; 66479697Snon } 66579697Snon 66679697Snon case XPT_CALC_GEOMETRY: { /* not yet HN2 */ 667116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 66879697Snon xpt_done(ccb); 66979697Snon break; 67079697Snon } 67179697Snon 67279697Snon case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 673240172Sjhb s = splcam(); 67479697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 67579697Snon splx(s); 67679697Snon ccb->ccb_h.status = CAM_REQ_CMP; 67779697Snon xpt_done(ccb); 67879697Snon break; 67979697Snon 68079697Snon case XPT_TERM_IO: /* Terminate the I/O process */ 68179697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 68279697Snon xpt_done(ccb); 68379697Snon break; 68479697Snon 68579697Snon case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 68679697Snon#ifdef SCSI_LOW_DIAGNOSTIC 68779697Snon if (target == CAM_TARGET_WILDCARD) 68879697Snon { 689240325Sjhb device_printf(slp->sl_dev, "invalid target\n"); 69079697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 69179697Snon xpt_done(ccb); 69279697Snon return; 69379697Snon } 69479697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 69579697Snon 69679697Snon msg = SCSI_LOW_MSG_RESET; 69779697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) 69879697Snon { 69979697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 70079697Snon xpt_done(ccb); 70179697Snon return; 70279697Snon } 70379697Snon 70479697Snon ti = slp->sl_ti[target]; 70579697Snon if (lun == CAM_LUN_WILDCARD) 70679697Snon lun = 0; 70779697Snon cb->osdep = ccb; 70879697Snon cb->bp = NULL; 70979697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 71079697Snon flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT; 71179697Snon else 71279697Snon flags = CCB_NORETRY | CCB_URGENT; 71379697Snon 714240172Sjhb s = splcam(); 71579697Snon li = scsi_low_alloc_li(ti, lun, 1); 71679697Snon scsi_low_enqueue(slp, ti, li, cb, flags, msg); 71779697Snon splx(s); 71879697Snon break; 71979697Snon 72079697Snon case XPT_PATH_INQ: { /* Path routing inquiry */ 72179697Snon struct ccb_pathinq *cpi = &ccb->cpi; 72279697Snon 72379697Snon cpi->version_num = scsi_low_version_major; 72479697Snon cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB; 72579697Snon ti = slp->sl_ti[slp->sl_hostid]; /* host id */ 72679697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 72779697Snon cpi->hba_inquiry |= PI_WIDE_16; 72879697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 72979697Snon cpi->hba_inquiry |= PI_WIDE_32; 73079697Snon if (ti->ti_maxsynch.offset > 0) 73179697Snon cpi->hba_inquiry |= PI_SDTR_ABLE; 73279697Snon cpi->target_sprt = 0; 73379697Snon cpi->hba_misc = 0; 73479697Snon cpi->hba_eng_cnt = 0; 73579697Snon cpi->max_target = slp->sl_ntargs - 1; 73679697Snon cpi->max_lun = slp->sl_nluns - 1; 73779697Snon cpi->initiator_id = slp->sl_hostid; 73879697Snon cpi->bus_id = cam_sim_bus(sim); 73979697Snon cpi->base_transfer_speed = 3300; 74079697Snon cpi->transport = XPORT_SPI; 74179697Snon cpi->transport_version = 2; 74279697Snon cpi->protocol = PROTO_SCSI; 74379697Snon cpi->protocol_version = SCSI_REV_2; 744315813Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 745315813Smav strlcpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); 746315813Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 74779697Snon cpi->unit_number = cam_sim_unit(sim); 74879697Snon cpi->ccb_h.status = CAM_REQ_CMP; 74979697Snon xpt_done(ccb); 75079697Snon break; 75179697Snon } 75279697Snon 75379697Snon default: 75479697Snon printf("scsi_low: non support func_code = %d ", 75579697Snon ccb->ccb_h.func_code); 75679697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 75779697Snon xpt_done(ccb); 75879697Snon break; 75979697Snon } 76079697Snon} 76179697Snon 76279697Snonstatic int 76379697Snonscsi_low_attach_cam(slp) 76479697Snon struct scsi_low_softc *slp; 76579697Snon{ 76679697Snon struct cam_devq *devq; 76779697Snon int tagged_openings; 76879697Snon 76979697Snon devq = cam_simq_alloc(SCSI_LOW_NCCB); 77079697Snon if (devq == NULL) 77179697Snon return (ENOMEM); 77279697Snon 77379697Snon /* 77479697Snon * ask the adapter what subunits are present 77579697Snon */ 77679697Snon tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS); 77779697Snon slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, 77879697Snon scsi_low_poll_cam, 779240172Sjhb device_get_name(slp->sl_dev), slp, 780240172Sjhb device_get_unit(slp->sl_dev), &Giant, 78179697Snon slp->sl_openings, tagged_openings, devq); 78279697Snon 78379697Snon if (slp->sl_si.sim == NULL) { 78479697Snon cam_simq_free(devq); 78579697Snon return ENODEV; 78679697Snon } 78779697Snon 788170872Sscottl if (xpt_bus_register(slp->sl_si.sim, NULL, 0) != CAM_SUCCESS) { 789147723Savatar free(slp->sl_si.sim, M_SCSILOW); 79079697Snon return ENODEV; 79179697Snon } 79279697Snon 79379697Snon if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL, 79479697Snon cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD, 79579697Snon CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 79679697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 79779697Snon cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE); 79879697Snon return ENODEV; 79979697Snon } 80079697Snon 80179697Snon slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */ 80279697Snon return 0; 80379697Snon} 80479697Snon 80579697Snonstatic int 80679697Snonscsi_low_world_start_cam(slp) 80779697Snon struct scsi_low_softc *slp; 80879697Snon{ 80979697Snon 81079697Snon return 0; 81179697Snon} 81279697Snon 81379697Snonstatic int 81479697Snonscsi_low_dettach_cam(slp) 81579697Snon struct scsi_low_softc *slp; 81679697Snon{ 81779697Snon 81879697Snon xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL); 81979697Snon xpt_free_path(slp->sl_si.path); 82079697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 82179697Snon cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE); 82279697Snon return 0; 82379697Snon} 82479697Snon 82579697Snonstatic int 82679697Snonscsi_low_ccb_setup_cam(slp, cb) 82779697Snon struct scsi_low_softc *slp; 82879697Snon struct slccb *cb; 82979697Snon{ 83079697Snon union ccb *ccb = (union ccb *) cb->osdep; 83179697Snon 83279697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 83379697Snon { 83479697Snon cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; 83579697Snon cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; 83679697Snon cb->ccb_scp.scp_data = ccb->csio.data_ptr; 83779697Snon cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; 83879697Snon if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 83979697Snon cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; 84079697Snon else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ 84179697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 84279697Snon cb->ccb_tcmax = ccb->ccb_h.timeout / 1000; 84379697Snon } 84479697Snon else 84579697Snon { 84679697Snon scsi_low_unit_ready_cmd(cb); 84779697Snon } 84879697Snon return SCSI_LOW_START_QTAG; 84979697Snon} 85079697Snon 85179697Snonstatic int 85279697Snonscsi_low_done_cam(slp, cb) 85379697Snon struct scsi_low_softc *slp; 85479697Snon struct slccb *cb; 85579697Snon{ 85679697Snon union ccb *ccb; 85779697Snon 85879697Snon ccb = (union ccb *) cb->osdep; 85979697Snon if (cb->ccb_error == 0) 86079697Snon { 86179697Snon ccb->ccb_h.status = CAM_REQ_CMP; 86279697Snon ccb->csio.resid = 0; 86379697Snon } 86479697Snon else 86579697Snon { 86679697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 86779697Snon cb->ccb_error |= ABORTIO; 86879697Snon 86979697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 87079697Snon (cb->ccb_error & ABORTIO) == 0) 87179697Snon return EJUSTRETURN; 87279697Snon 87379697Snon if ((cb->ccb_error & SENSEIO) != 0) 87479697Snon { 87579697Snon memcpy(&ccb->csio.sense_data, 87679697Snon &cb->ccb_sense, 87779697Snon sizeof(ccb->csio.sense_data)); 87879697Snon } 87979697Snon 88079697Snon ccb->ccb_h.status = scsi_low_translate_error_code(cb, 88179697Snon &scsi_low_error_code_cam[0]); 88279697Snon 88379697Snon#ifdef SCSI_LOW_DIAGNOSTIC 88479697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 88579697Snon cb->ccb_scp.scp_cmdlen > 0 && 88679697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 88779697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 88879697Snon { 889240325Sjhb device_printf(slp->sl_dev, 890240325Sjhb "WARNING: scsi_low IO abort\n"); 89179697Snon scsi_low_print(slp, NULL); 89279697Snon } 89379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 89479697Snon } 89579697Snon 89679697Snon if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0) 89779697Snon ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 89879697Snon 89979697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 90079697Snon ccb->csio.scsi_status = 0; /* XXX */ 90179697Snon else 90279697Snon ccb->csio.scsi_status = cb->ccb_scp.scp_status; 90379697Snon 90479697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 90579697Snon xpt_done(ccb); 90679697Snon return 0; 90779697Snon} 90879697Snon 90979697Snonstatic void 91079697Snonscsi_low_timeout_cam(slp, ch, action) 91179697Snon struct scsi_low_softc *slp; 91279697Snon int ch; 91379697Snon int action; 91479697Snon{ 91579697Snon 91679697Snon switch (ch) 91779697Snon { 91879697Snon case SCSI_LOW_TIMEOUT_CH_IO: 91979697Snon switch (action) 92079697Snon { 92179697Snon case SCSI_LOW_TIMEOUT_START: 92279697Snon slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp, 92379697Snon hz / SCSI_LOW_TIMEOUT_HZ); 92479697Snon break; 92579697Snon case SCSI_LOW_TIMEOUT_STOP: 92679697Snon untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch); 92779697Snon break; 92879697Snon } 92979697Snon break; 93079697Snon 93179697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 93279697Snon switch (action) 93379697Snon { 93479697Snon case SCSI_LOW_TIMEOUT_START: 93579697Snon slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1); 93679697Snon break; 93779697Snon case SCSI_LOW_TIMEOUT_STOP: 93879697Snon untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch); 93979697Snon break; 94079697Snon } 94179697Snon break; 94279697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 94379697Snon break; 94479697Snon } 94579697Snon} 94679697Snon 94779697Snon/*============================================================= 94879697Snon * END OF OS switch (All OS depend fucntions should be above) 94979697Snon =============================================================*/ 95079697Snon 95179697Snon/************************************************************** 95279697Snon * scsi low deactivate and activate 95379697Snon **************************************************************/ 95479697Snonint 95579697Snonscsi_low_is_busy(slp) 95679697Snon struct scsi_low_softc *slp; 95779697Snon{ 95879697Snon 95979697Snon if (slp->sl_nio > 0) 96079697Snon return EBUSY; 96179697Snon return 0; 96279697Snon} 96379697Snon 96479697Snonint 96579697Snonscsi_low_deactivate(slp) 96679697Snon struct scsi_low_softc *slp; 96779697Snon{ 96879697Snon int s; 96979697Snon 970240172Sjhb s = splcam(); 97179697Snon slp->sl_flags |= HW_INACTIVE; 97279697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 97379697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP); 97479697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 97579697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 97679697Snon splx(s); 97779697Snon return 0; 97879697Snon} 97979697Snon 98079697Snonint 98179697Snonscsi_low_activate(slp) 98279697Snon struct scsi_low_softc *slp; 98379697Snon{ 98479697Snon int error, s; 98579697Snon 986240172Sjhb s = splcam(); 98779697Snon slp->sl_flags &= ~HW_INACTIVE; 98879697Snon if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0) 98979697Snon { 99079697Snon slp->sl_flags |= HW_INACTIVE; 99179697Snon splx(s); 99279697Snon return error; 99379697Snon } 99479697Snon 99579697Snon slp->sl_timeout_count = 0; 99679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 99779697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 99879697Snon splx(s); 99979697Snon return 0; 100079697Snon} 100179697Snon 100279697Snon/************************************************************** 100379697Snon * scsi low log 100479697Snon **************************************************************/ 100579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 100692770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *); 100792770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int); 100892770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int); 100979697Snon 101079697Snonstatic void 101179697Snonscsi_low_msg_log_init(slmlp) 101279697Snon struct scsi_low_msg_log *slmlp; 101379697Snon{ 101479697Snon 101579697Snon slmlp->slml_ptr = 0; 101679697Snon} 101779697Snon 101879697Snonstatic void 101979697Snonscsi_low_msg_log_write(slmlp, datap, len) 102079697Snon struct scsi_low_msg_log *slmlp; 102179697Snon u_int8_t *datap; 102279697Snon int len; 102379697Snon{ 102479697Snon int ptr, ind; 102579697Snon 102679697Snon if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN) 102779697Snon return; 102879697Snon 102979697Snon ptr = slmlp->slml_ptr ++; 103079697Snon for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++) 103179697Snon slmlp->slml_msg[ptr].msg[ind] = datap[ind]; 103279697Snon for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++) 103379697Snon slmlp->slml_msg[ptr].msg[ind] = 0; 103479697Snon} 103579697Snon 103679697Snonstatic void 103779697Snonscsi_low_msg_log_show(slmlp, s, len) 103879697Snon struct scsi_low_msg_log *slmlp; 103979697Snon char *s; 104079697Snon int len; 104179697Snon{ 104279697Snon int ptr, ind; 104379697Snon 104479697Snon printf("%s: (%d) ", s, slmlp->slml_ptr); 104579697Snon for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++) 104679697Snon { 104779697Snon for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]); 104879697Snon ind ++) 104979697Snon { 105079697Snon printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]); 105179697Snon } 105279697Snon printf(">"); 105379697Snon } 105479697Snon printf("\n"); 105579697Snon} 105679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 105779697Snon 105879697Snon/************************************************************** 105967468Snon * power control 106067468Snon **************************************************************/ 106167468Snonstatic void 106267468Snonscsi_low_engage(arg) 106367468Snon void *arg; 106467468Snon{ 106567468Snon struct scsi_low_softc *slp = arg; 1066240172Sjhb int s = splcam(); 106767468Snon 106867468Snon switch (slp->sl_rstep) 106967468Snon { 107067468Snon case 0: 107167468Snon slp->sl_rstep ++; 107267468Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 107379697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 107479697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START); 107567468Snon break; 107667468Snon 107767468Snon case 1: 107867468Snon slp->sl_rstep ++; 107967468Snon slp->sl_flags &= ~HW_RESUME; 108067468Snon scsi_low_start(slp); 108167468Snon break; 108267468Snon 108367468Snon case 2: 108467468Snon break; 108567468Snon } 108667468Snon splx(s); 108767468Snon} 108867468Snon 108967468Snonstatic int 109067468Snonscsi_low_init(slp, flags) 109167468Snon struct scsi_low_softc *slp; 109267468Snon u_int flags; 109367468Snon{ 109479697Snon int rv = 0; 109567468Snon 109679697Snon slp->sl_flags |= HW_INITIALIZING; 109779697Snon 109879697Snon /* clear power control timeout */ 109967468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 110067468Snon { 110179697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 110279697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 110367468Snon slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); 110467468Snon slp->sl_active = 1; 110567468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 110667468Snon } 110767468Snon 110867468Snon /* reset current nexus */ 110967468Snon scsi_low_reset_nexus(slp, flags); 111067468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 111179697Snon { 111279697Snon rv = EBUSY; 111379697Snon goto out; 111479697Snon } 111567468Snon 111679697Snon if (flags != SCSI_LOW_RESTART_SOFT) 111779697Snon { 111879697Snon rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags)); 111979697Snon } 112067468Snon 112179697Snonout: 112279697Snon slp->sl_flags &= ~HW_INITIALIZING; 112379697Snon return rv; 112467468Snon} 112567468Snon 112667468Snon/************************************************************** 112767468Snon * allocate lun_info 112867468Snon **************************************************************/ 112967468Snonstatic struct lun_info * 113067468Snonscsi_low_alloc_li(ti, lun, alloc) 113167468Snon struct targ_info *ti; 113267468Snon int lun; 113367468Snon int alloc; 113467468Snon{ 113579697Snon struct scsi_low_softc *slp = ti->ti_sc; 113667468Snon struct lun_info *li; 113767468Snon 113867468Snon li = LIST_FIRST(&ti->ti_litab); 113967468Snon if (li != NULL) 114067468Snon { 114167468Snon if (li->li_lun == lun) 114267468Snon return li; 114367468Snon 114467468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 114567468Snon { 114667468Snon if (li->li_lun == lun) 114767468Snon { 114867468Snon LIST_REMOVE(li, lun_chain); 114967468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 115067468Snon return li; 115167468Snon } 115267468Snon } 115367468Snon } 115467468Snon 115567468Snon if (alloc == 0) 115667468Snon return li; 115767468Snon 115879697Snon li = SCSI_LOW_MALLOC(ti->ti_lunsize); 115967468Snon if (li == NULL) 1160106890Simp panic("no lun info mem"); 116167468Snon 1162240172Sjhb bzero(li, ti->ti_lunsize); 116367468Snon li->li_lun = lun; 116467468Snon li->li_ti = ti; 116567468Snon 116679697Snon li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC | 116779697Snon SCSI_LOW_QTAG; 116879697Snon li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 116979697Snon li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID; 117079697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 117179697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 117279697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 117379697Snon 117479697Snon li->li_qtagbits = (u_int) -1; 117579697Snon 117679697Snon TAILQ_INIT(&li->li_discq); 117767468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 117867468Snon 117979697Snon /* host specific structure initialization per lun */ 118079697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 118179697Snon (*slp->sl_funcs->scsi_low_lun_init) 118279697Snon (slp, ti, li, SCSI_LOW_INFO_ALLOC); 118379697Snon scsi_low_calcf_lun(li); 118467468Snon return li; 118567468Snon} 118667468Snon 118767468Snon/************************************************************** 118867468Snon * allocate targ_info 118967468Snon **************************************************************/ 119067468Snonstatic struct targ_info * 119179697Snonscsi_low_alloc_ti(slp, targ) 119267468Snon struct scsi_low_softc *slp; 119379697Snon int targ; 119467468Snon{ 119567468Snon struct targ_info *ti; 119667468Snon 119771999Sphk if (TAILQ_FIRST(&slp->sl_titab) == NULL) 119867468Snon TAILQ_INIT(&slp->sl_titab); 119967468Snon 120079697Snon ti = SCSI_LOW_MALLOC(slp->sl_targsize); 120167468Snon if (ti == NULL) 1202240325Sjhb panic("%s short of memory", device_get_nameunit(slp->sl_dev)); 120367468Snon 1204240172Sjhb bzero(ti, slp->sl_targsize); 120567468Snon ti->ti_id = targ; 120667468Snon ti->ti_sc = slp; 120767468Snon 120867468Snon slp->sl_ti[targ] = ti; 120967468Snon TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); 121067468Snon LIST_INIT(&ti->ti_litab); 121167468Snon 121279697Snon ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 121379697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 121479697Snon ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID; 121579697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 121679697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 121779697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 121873025Snon 121979697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 122079697Snon { 122179697Snon (*slp->sl_funcs->scsi_low_targ_init) 122279697Snon (slp, ti, SCSI_LOW_INFO_ALLOC); 122379697Snon } 122479697Snon scsi_low_calcf_target(ti); 122567468Snon return ti; 122667468Snon} 122767468Snon 122867468Snonstatic void 122967468Snonscsi_low_free_ti(slp) 123067468Snon struct scsi_low_softc *slp; 123167468Snon{ 123267468Snon struct targ_info *ti, *tib; 123367468Snon struct lun_info *li, *nli; 123467468Snon 123571999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) 123667468Snon { 123767468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) 123867468Snon { 123979697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 124079697Snon { 124179697Snon (*slp->sl_funcs->scsi_low_lun_init) 124279697Snon (slp, ti, li, SCSI_LOW_INFO_DEALLOC); 124379697Snon } 124467468Snon nli = LIST_NEXT(li, lun_chain); 124579697Snon SCSI_LOW_FREE(li); 124667468Snon } 124779697Snon 124879697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 124979697Snon { 125079697Snon (*slp->sl_funcs->scsi_low_targ_init) 125179697Snon (slp, ti, SCSI_LOW_INFO_DEALLOC); 125279697Snon } 125379697Snon tib = TAILQ_NEXT(ti, ti_chain); 125479697Snon SCSI_LOW_FREE(ti); 125567468Snon } 125667468Snon} 125767468Snon 125867468Snon/************************************************************** 125967468Snon * timeout 126067468Snon **************************************************************/ 126167468Snonvoid 126279697Snonscsi_low_bus_idle(slp) 126379697Snon struct scsi_low_softc *slp; 126479697Snon{ 126579697Snon 126679697Snon slp->sl_retry_sel = 0; 126779697Snon if (slp->sl_Tnexus == NULL) 126879697Snon scsi_low_start(slp); 126979697Snon} 127079697Snon 127179697Snonstatic void 127267468Snonscsi_low_timeout(arg) 127367468Snon void *arg; 127467468Snon{ 127567468Snon struct scsi_low_softc *slp = arg; 127679697Snon int s; 127779697Snon 1278240172Sjhb s = splcam(); 127979697Snon (void) scsi_low_timeout_check(slp); 128079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 128179697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 128279697Snon splx(s); 128379697Snon} 128479697Snon 128579697Snonstatic int 128679697Snonscsi_low_timeout_check(slp) 128779697Snon struct scsi_low_softc *slp; 128879697Snon{ 128967468Snon struct targ_info *ti; 129079697Snon struct lun_info *li; 129167468Snon struct slccb *cb = NULL; /* XXX */ 129267468Snon 129379697Snon /* selection restart */ 129479697Snon if (slp->sl_retry_sel != 0) 129567468Snon { 129679697Snon slp->sl_retry_sel = 0; 129779697Snon if (slp->sl_Tnexus != NULL) 129879697Snon goto step1; 129967468Snon 130079697Snon cb = TAILQ_FIRST(&slp->sl_start); 130179697Snon if (cb == NULL) 130279697Snon goto step1; 130379697Snon 130479697Snon if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY) 130567468Snon { 130679697Snon cb->ccb_flags |= CCB_NORETRY; 130779697Snon cb->ccb_error |= SELTIMEOUTIO; 130879697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 1309240325Sjhb panic("%s: ccb not finished", 1310240325Sjhb device_get_nameunit(slp->sl_dev)); 131167468Snon } 131279697Snon 131379697Snon if (slp->sl_Tnexus == NULL) 131479697Snon scsi_low_start(slp); 131567468Snon } 131679697Snon 131779697Snon /* call hardware timeout */ 131879697Snonstep1: 131979697Snon if (slp->sl_funcs->scsi_low_timeout != NULL) 132067468Snon { 132179697Snon (*slp->sl_funcs->scsi_low_timeout) (slp); 132279697Snon } 132379697Snon 132479697Snon if (slp->sl_timeout_count ++ < 132579697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ) 132679697Snon return 0; 132779697Snon 132879697Snon slp->sl_timeout_count = 0; 132979697Snon if (slp->sl_nio > 0) 133079697Snon { 133179697Snon if ((cb = slp->sl_Qnexus) != NULL) 133267468Snon { 133367468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 133467468Snon if (cb->ccb_tc < 0) 133567468Snon goto bus_reset; 133667468Snon } 133779697Snon else if (slp->sl_disc == 0) 133867468Snon { 133979697Snon if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL) 134079697Snon return 0; 134167468Snon 134279697Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 134379697Snon if (cb->ccb_tc < 0) 134479697Snon goto bus_reset; 134579697Snon } 134679697Snon else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 134779697Snon ti = TAILQ_NEXT(ti, ti_chain)) 134879697Snon { 134979697Snon if (ti->ti_disc == 0) 135079697Snon continue; 135167468Snon 135279697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 135379697Snon li = LIST_NEXT(li, lun_chain)) 135467468Snon { 135579697Snon for (cb = TAILQ_FIRST(&li->li_discq); 135679697Snon cb != NULL; 135779697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 135879697Snon { 135979697Snon cb->ccb_tc -= 136079697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 136179697Snon if (cb->ccb_tc < 0) 136279697Snon goto bus_reset; 136379697Snon } 136467468Snon } 136567468Snon } 136679697Snon 136767468Snon } 136879697Snon else if ((slp->sl_flags & HW_POWERCTRL) != 0) 136979697Snon { 137079697Snon if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) 137179697Snon return 0; 137267468Snon 137379697Snon if (slp->sl_active != 0) 137479697Snon { 137579697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 137679697Snon slp->sl_active = 0; 137779697Snon return 0; 137879697Snon } 137967468Snon 138079697Snon slp->sl_powc --; 138179697Snon if (slp->sl_powc < 0) 138279697Snon { 138379697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 138479697Snon slp->sl_flags |= HW_POWDOWN; 138579697Snon (*slp->sl_funcs->scsi_low_power) 138679697Snon (slp, SCSI_LOW_POWDOWN); 138779697Snon } 138879697Snon } 138979697Snon return 0; 139067468Snon 139167468Snonbus_reset: 139267468Snon cb->ccb_error |= TIMEOUTIO; 1393240325Sjhb device_printf(slp->sl_dev, "slccb (0x%lx) timeout!\n", (u_long) cb); 139467468Snon scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); 139567468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 139667468Snon scsi_low_start(slp); 139779697Snon return ERESTART; 139867468Snon} 139967468Snon 140067468Snon 140179697Snonstatic int 140279697Snonscsi_low_abort_ccb(slp, cb) 140379697Snon struct scsi_low_softc *slp; 140479697Snon struct slccb *cb; 140579697Snon{ 140679697Snon struct targ_info *ti; 140779697Snon struct lun_info *li; 140879697Snon u_int msg; 140967468Snon 141079697Snon if (cb == NULL) 141179697Snon return EINVAL; 141279697Snon if ((cb->ccb_omsgoutflag & 141379697Snon (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0) 141479697Snon return EBUSY; 141567468Snon 141679697Snon ti = cb->ti; 141779697Snon li = cb->li; 141879697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 141979697Snon msg = SCSI_LOW_MSG_ABORT; 142079697Snon else 142179697Snon msg = SCSI_LOW_MSG_ABORT_QTAG; 142267468Snon 142379697Snon cb->ccb_error |= ABORTIO; 142479697Snon cb->ccb_flags |= CCB_NORETRY; 142579697Snon scsi_low_ccb_message_assert(cb, msg); 142667468Snon 142779697Snon if (cb == slp->sl_Qnexus) 142879697Snon { 142979697Snon scsi_low_assert_msg(slp, ti, msg, 1); 143079697Snon } 143179697Snon else if ((cb->ccb_flags & CCB_DISCQ) != 0) 143279697Snon { 143379697Snon if (scsi_low_revoke_ccb(slp, cb, 0) == NULL) 1434240325Sjhb panic("%s: revoked ccb done", 1435240325Sjhb device_get_nameunit(slp->sl_dev)); 143667468Snon 143779697Snon cb->ccb_flags |= CCB_STARTQ; 143879697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 143967468Snon 144079697Snon if (slp->sl_Tnexus == NULL) 144179697Snon scsi_low_start(slp); 144279697Snon } 144379697Snon else 144479697Snon { 144579697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 1446240325Sjhb panic("%s: revoked ccb retried", 1447240325Sjhb device_get_nameunit(slp->sl_dev)); 144879697Snon } 144979697Snon return 0; 145067468Snon} 145167468Snon 145279697Snon/************************************************************** 145379697Snon * Generic SCSI INTERFACE 145479697Snon **************************************************************/ 145567468Snonint 145679697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize) 145767468Snon struct scsi_low_softc *slp; 145879697Snon int openings, ntargs, nluns, targsize, lunsize; 145967468Snon{ 146067468Snon struct targ_info *ti; 146167468Snon struct lun_info *li; 146279697Snon int s, i, nccb, rv; 146367468Snon 146479697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam; 146579697Snon 146679697Snon if (slp->sl_osdep_fp == NULL) 1467106890Simp panic("scsi_low: interface not spcified"); 146879697Snon 146967468Snon if (ntargs > SCSI_LOW_NTARGETS) 147067468Snon { 147167468Snon printf("scsi_low: %d targets are too large\n", ntargs); 147267468Snon printf("change kernel options SCSI_LOW_NTARGETS"); 147379697Snon return EINVAL; 147467468Snon } 147567468Snon 147679697Snon if (openings <= 0) 147779697Snon slp->sl_openings = (SCSI_LOW_NCCB / ntargs); 147879697Snon else 147979697Snon slp->sl_openings = openings; 148079697Snon slp->sl_ntargs = ntargs; 148179697Snon slp->sl_nluns = nluns; 148279697Snon slp->sl_max_retry = SCSI_LOW_MAX_RETRY; 148367468Snon 148479697Snon if (lunsize < sizeof(struct lun_info)) 148579697Snon lunsize = sizeof(struct lun_info); 148679697Snon 148779697Snon if (targsize < sizeof(struct targ_info)) 148879697Snon targsize = sizeof(struct targ_info); 148979697Snon 149079697Snon slp->sl_targsize = targsize; 149167468Snon for (i = 0; i < ntargs; i ++) 149267468Snon { 149379697Snon ti = scsi_low_alloc_ti(slp, i); 149479697Snon ti->ti_lunsize = lunsize; 149567468Snon li = scsi_low_alloc_li(ti, 0, 1); 149667468Snon } 149767468Snon 149867468Snon /* initialize queue */ 149979697Snon nccb = openings * ntargs; 150067468Snon if (nccb >= SCSI_LOW_NCCB || nccb <= 0) 150167468Snon nccb = SCSI_LOW_NCCB; 150267468Snon scsi_low_init_ccbque(nccb); 150367468Snon TAILQ_INIT(&slp->sl_start); 150467468Snon 150579697Snon /* call os depend attach */ 1506240172Sjhb s = splcam(); 150779697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp); 150879697Snon if (rv != 0) 150979697Snon { 151079697Snon splx(s); 1511240325Sjhb device_printf(slp->sl_dev, 1512240325Sjhb "scsi_low_attach: osdep attach failed\n"); 151379697Snon return EINVAL; 151479697Snon } 151567468Snon 151679697Snon /* check hardware */ 1517240172Sjhb DELAY(1000); /* wait for 1ms */ 151879697Snon if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) 151979697Snon { 152079697Snon splx(s); 1521240325Sjhb device_printf(slp->sl_dev, 1522240325Sjhb "scsi_low_attach: initialization failed\n"); 152379697Snon return EINVAL; 152479697Snon } 152567468Snon 152667468Snon /* start watch dog */ 152779697Snon slp->sl_timeout_count = 0; 152879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 152979697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 153079697Snon LIST_INSERT_HEAD(&sl_tab, slp, sl_chain); 153167468Snon 153279697Snon /* fake call */ 153379697Snon scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL)); 153467468Snon 153579697Snon#ifdef SCSI_LOW_START_UP_CHECK 153679697Snon /* probing devices */ 153779697Snon scsi_low_start_up(slp); 153879697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 153967468Snon 154079697Snon /* call os depend attach done*/ 154179697Snon (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp); 154279697Snon splx(s); 154379697Snon return 0; 154467468Snon} 154567468Snon 154667468Snonint 154767468Snonscsi_low_dettach(slp) 154867468Snon struct scsi_low_softc *slp; 154967468Snon{ 155079697Snon int s, rv; 155167468Snon 1552240172Sjhb s = splcam(); 155379697Snon if (scsi_low_is_busy(slp) != 0) 155479697Snon { 155579697Snon splx(s); 155667468Snon return EBUSY; 155779697Snon } 155867468Snon 155979697Snon scsi_low_deactivate(slp); 156067468Snon 156179697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp); 156279697Snon if (rv != 0) 156379697Snon { 156479697Snon splx(s); 156579697Snon return EBUSY; 156679697Snon } 156767468Snon 156867468Snon scsi_low_free_ti(slp); 156979697Snon LIST_REMOVE(slp, sl_chain); 157079697Snon splx(s); 157167468Snon return 0; 157267468Snon} 157367468Snon 157479697Snon/************************************************************** 157579697Snon * Generic enqueue 157679697Snon **************************************************************/ 157779697Snonstatic int 157879697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg) 157979697Snon struct scsi_low_softc *slp; 158067468Snon struct targ_info *ti; 158167468Snon struct lun_info *li; 158267468Snon struct slccb *cb; 158379697Snon u_int flags, msg; 158479697Snon{ 158567468Snon 158679697Snon cb->ti = ti; 158779697Snon cb->li = li; 158867468Snon 158979697Snon scsi_low_ccb_message_assert(cb, msg); 159067468Snon 159179697Snon cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG; 159279697Snon scsi_low_alloc_qtag(cb); 159367468Snon 159479697Snon cb->ccb_flags = flags | CCB_STARTQ; 159579697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 159679697Snon cb->ccb_error |= PENDINGIO; 159779697Snon 159879697Snon if ((flags & CCB_URGENT) != 0) 159979697Snon { 160079697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 160179697Snon } 160279697Snon else 160379697Snon { 160467468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 160579697Snon } 160667468Snon 160779697Snon slp->sl_nio ++; 160867468Snon 160979697Snon if (slp->sl_Tnexus == NULL) 161079697Snon scsi_low_start(slp); 161179697Snon return 0; 161279697Snon} 161367468Snon 161479697Snonstatic int 161579697Snonscsi_low_message_enqueue(slp, ti, li, flags) 161679697Snon struct scsi_low_softc *slp; 161779697Snon struct targ_info *ti; 161879697Snon struct lun_info *li; 161979697Snon u_int flags; 162079697Snon{ 162179697Snon struct slccb *cb; 162279697Snon u_int tmsgflags; 162367468Snon 162479697Snon tmsgflags = ti->ti_setup_msg; 162579697Snon ti->ti_setup_msg = 0; 162667468Snon 162779697Snon flags |= CCB_NORETRY; 162879697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 162979697Snon return ENOMEM; 163067468Snon 163179697Snon cb->osdep = NULL; 163279697Snon cb->bp = NULL; 163379697Snon scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags); 163479697Snon return 0; 163579697Snon} 163667468Snon 163779697Snon/************************************************************** 163879697Snon * Generic Start & Done 163979697Snon **************************************************************/ 164079697Snon#define SLSC_MODE_SENSE_SHORT 0x1a 164179697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0}; 164279697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0, 164379697Snon sizeof(struct scsi_low_mode_sense_data), 0}; 164479697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0, 164579697Snon sizeof(struct scsi_low_inq_data), 0}; 164679697Snonstatic u_int8_t unit_ready_cmd[6]; 164792770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 164892770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 164992770Salfredstatic int scsi_low_resume(struct scsi_low_softc *); 165079697Snon 165179697Snonstatic void 165279697Snonscsi_low_unit_ready_cmd(cb) 165379697Snon struct slccb *cb; 165479697Snon{ 165579697Snon 165679697Snon cb->ccb_scp.scp_cmd = unit_ready_cmd; 165779697Snon cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); 165879697Snon cb->ccb_scp.scp_datalen = 0; 165979697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 166079697Snon cb->ccb_tcmax = 15; 166167468Snon} 166279697Snon 166367468Snonstatic int 166479697Snonscsi_low_sense_abort_start(slp, ti, li, cb) 166579697Snon struct scsi_low_softc *slp; 166667468Snon struct targ_info *ti; 166779697Snon struct lun_info *li; 166867468Snon struct slccb *cb; 166979697Snon{ 167067468Snon 167179697Snon cb->ccb_scp.scp_cmdlen = 6; 1672240172Sjhb bzero(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen); 167379697Snon cb->ccb_scsi_cmd[0] = REQUEST_SENSE; 167479697Snon cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense); 167579697Snon cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd; 167679697Snon cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; 167779697Snon cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); 167879697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 167979697Snon cb->ccb_tcmax = 15; 168079697Snon scsi_low_ccb_message_clear(cb); 168179697Snon if ((cb->ccb_flags & CCB_CLEARQ) != 0) 168267468Snon { 168379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 168467468Snon } 168579697Snon else 168679697Snon { 1687240172Sjhb bzero(&cb->ccb_sense, sizeof(cb->ccb_sense)); 168879697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 168979697Snon scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0); 169079697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 169179697Snon } 169267468Snon 169379697Snon return SCSI_LOW_START_NO_QTAG; 169479697Snon} 169567468Snon 169679697Snonstatic int 169779697Snonscsi_low_setup_start(slp, ti, li, cb) 169879697Snon struct scsi_low_softc *slp; 169979697Snon struct targ_info *ti; 170079697Snon struct lun_info *li; 170179697Snon struct slccb *cb; 170279697Snon{ 170367468Snon 170479697Snon switch(li->li_state) 170579697Snon { 170679697Snon case SCSI_LOW_LUN_SLEEP: 170779697Snon scsi_low_unit_ready_cmd(cb); 170879697Snon break; 170967468Snon 171079697Snon case SCSI_LOW_LUN_START: 171179697Snon cb->ccb_scp.scp_cmd = ss_cmd; 171279697Snon cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); 171379697Snon cb->ccb_scp.scp_datalen = 0; 171479697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 171579697Snon cb->ccb_tcmax = 30; 171679697Snon break; 171767468Snon 171879697Snon case SCSI_LOW_LUN_INQ: 171979697Snon cb->ccb_scp.scp_cmd = inq_cmd; 172079697Snon cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd); 172179697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq; 172279697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_inq); 172379697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 172479697Snon cb->ccb_tcmax = 15; 172579697Snon break; 172667468Snon 172779697Snon case SCSI_LOW_LUN_MODEQ: 172879697Snon cb->ccb_scp.scp_cmd = sms_cmd; 172979697Snon cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd); 173079697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms; 173179697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_sms); 173279697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 173379697Snon cb->ccb_tcmax = 15; 173479697Snon return SCSI_LOW_START_QTAG; 173567468Snon 173679697Snon default: 1737240325Sjhb panic("%s: no setup phase", device_get_nameunit(slp->sl_dev)); 173867468Snon } 173967468Snon 174079697Snon return SCSI_LOW_START_NO_QTAG; 174167468Snon} 174267468Snon 174379697Snonstatic int 174479697Snonscsi_low_resume(slp) 174579697Snon struct scsi_low_softc *slp; 174667468Snon{ 174767468Snon 174879697Snon if (slp->sl_flags & HW_RESUME) 174979697Snon return EJUSTRETURN; 175079697Snon slp->sl_flags &= ~HW_POWDOWN; 175179697Snon if (slp->sl_funcs->scsi_low_power != NULL) 175279697Snon { 175379697Snon slp->sl_flags |= HW_RESUME; 175479697Snon slp->sl_rstep = 0; 175579697Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 175679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 175779697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, 175879697Snon SCSI_LOW_TIMEOUT_START); 175979697Snon return EJUSTRETURN; 176079697Snon } 176179697Snon return 0; 176267468Snon} 176367468Snon 176467468Snonstatic void 176567468Snonscsi_low_start(slp) 176667468Snon struct scsi_low_softc *slp; 176767468Snon{ 176867468Snon struct targ_info *ti; 176967468Snon struct lun_info *li; 177067468Snon struct slccb *cb; 177167468Snon int rv; 177267468Snon 177379697Snon /* check hardware exists or under initializations ? */ 177479697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 177567468Snon return; 177667468Snon 177767468Snon /* check hardware power up ? */ 177867468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 177967468Snon { 178067468Snon slp->sl_active ++; 178167468Snon if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) 178267468Snon { 178379697Snon if (scsi_low_resume(slp) == EJUSTRETURN) 178467468Snon return; 178567468Snon } 178667468Snon } 178767468Snon 178867468Snon /* setup nexus */ 178967468Snon#ifdef SCSI_LOW_DIAGNOSTIC 179079697Snon if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus) 179167468Snon { 179267468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 1793240325Sjhb panic("%s: inconsistent", device_get_nameunit(slp->sl_dev)); 179467468Snon } 179567468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 179667468Snon 179779697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 179879697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 179967468Snon { 180067468Snon li = cb->li; 180179697Snon 180279697Snon if (li->li_disc == 0) 180379697Snon { 180467468Snon goto scsi_low_cmd_start; 180579697Snon } 180679697Snon else if (li->li_nqio > 0) 180779697Snon { 180879697Snon if (li->li_nqio < li->li_maxnqio || 180979697Snon (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 181079697Snon goto scsi_low_cmd_start; 181179697Snon } 181267468Snon } 181367468Snon return; 181467468Snon 181567468Snonscsi_low_cmd_start: 181679697Snon cb->ccb_flags &= ~CCB_STARTQ; 181779697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 181879697Snon ti = cb->ti; 181967468Snon 182067468Snon /* clear all error flag bits (for restart) */ 182167468Snon cb->ccb_error = 0; 182279697Snon cb->ccb_datalen = -1; 182379697Snon cb->ccb_scp.scp_status = ST_UNKNOWN; 182467468Snon 182567468Snon /* setup nexus pointer */ 182679697Snon slp->sl_Qnexus = cb; 182779697Snon slp->sl_Lnexus = li; 182879697Snon slp->sl_Tnexus = ti; 182967468Snon 183067468Snon /* initialize msgsys */ 183167468Snon scsi_low_init_msgsys(slp, ti); 183267468Snon 183379697Snon /* exec cmd */ 183479697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 183567468Snon { 183679697Snon /* CA state or forced abort */ 183779697Snon rv = scsi_low_sense_abort_start(slp, ti, li, cb); 183867468Snon } 183979697Snon else if (li->li_state >= SCSI_LOW_LUN_OK) 184067468Snon { 184179697Snon cb->ccb_flags &= ~CCB_INTERNAL; 184279697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb); 184379697Snon if (cb->ccb_msgoutflag != 0) 184479697Snon { 184579697Snon scsi_low_ccb_message_exec(slp, cb); 184679697Snon } 184767468Snon } 184879697Snon else 184967468Snon { 185079697Snon cb->ccb_flags |= CCB_INTERNAL; 185179697Snon rv = scsi_low_setup_start(slp, ti, li, cb); 185279697Snon } 185367468Snon 185479697Snon /* allocate qtag */ 185579697Snon#define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC) 185667468Snon 185779697Snon if (rv == SCSI_LOW_START_QTAG && 185879697Snon (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK && 185979697Snon li->li_maxnqio > 0) 186079697Snon { 186179697Snon u_int qmsg; 186267468Snon 186379697Snon scsi_low_activate_qtag(cb); 186479697Snon if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 186579697Snon SCSI_LOW_CMD_ORDERED_QTAG) != 0) 186679697Snon qmsg = SCSI_LOW_MSG_ORDERED_QTAG; 186779697Snon else if ((cb->ccb_flags & CCB_URGENT) != 0) 186879697Snon qmsg = SCSI_LOW_MSG_HEAD_QTAG; 186979697Snon else 187079697Snon qmsg = SCSI_LOW_MSG_SIMPLE_QTAG; 187179697Snon scsi_low_assert_msg(slp, ti, qmsg, 0); 187267468Snon } 187367468Snon 187467468Snon /* timeout */ 187567468Snon if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 187667468Snon cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 187767468Snon cb->ccb_tc = cb->ccb_tcmax; 187867468Snon 187967468Snon /* setup saved scsi data pointer */ 188067468Snon cb->ccb_sscp = cb->ccb_scp; 188167468Snon 188267468Snon /* setup current scsi pointer */ 188367468Snon slp->sl_scp = cb->ccb_sscp; 188467468Snon slp->sl_error = cb->ccb_error; 188567468Snon 188679697Snon /* assert always an identify msg */ 188779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); 188879697Snon 188979697Snon /* debug section */ 189079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 189179697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 189279697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 189379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 189479697Snon 189567468Snon /* selection start */ 189679697Snon slp->sl_selid = cb; 189767468Snon rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); 189867468Snon if (rv == SCSI_LOW_START_OK) 189967468Snon { 190067468Snon#ifdef SCSI_LOW_STATICS 190167468Snon scsi_low_statics.nexus_win ++; 190267468Snon#endif /* SCSI_LOW_STATICS */ 190367468Snon return; 190467468Snon } 190567468Snon 190679697Snon scsi_low_arbit_fail(slp, cb); 190767468Snon#ifdef SCSI_LOW_STATICS 190867468Snon scsi_low_statics.nexus_fail ++; 190967468Snon#endif /* SCSI_LOW_STATICS */ 191067468Snon} 191167468Snon 191267468Snonvoid 191379697Snonscsi_low_arbit_fail(slp, cb) 191467468Snon struct scsi_low_softc *slp; 191579697Snon struct slccb *cb; 191679697Snon{ 191779697Snon struct targ_info *ti = cb->ti; 191879697Snon 191979697Snon scsi_low_deactivate_qtag(cb); 192079697Snon scsi_low_ccb_message_retry(cb); 192179697Snon cb->ccb_flags |= CCB_STARTQ; 192279697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 192379697Snon 192479697Snon scsi_low_bus_release(slp, ti); 192579697Snon 192679697Snon cb->ccb_selrcnt ++; 192779697Snon if (slp->sl_disc == 0) 192879697Snon { 192979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 1930240325Sjhb device_printf(slp->sl_dev, "try selection again\n"); 193179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 193279697Snon slp->sl_retry_sel = 1; 193379697Snon } 193479697Snon} 193579697Snon 193679697Snonstatic void 193779697Snonscsi_low_bus_release(slp, ti) 193879697Snon struct scsi_low_softc *slp; 193967468Snon struct targ_info *ti; 194067468Snon{ 194167468Snon 194279697Snon if (ti->ti_disc > 0) 194379697Snon { 194479697Snon SCSI_LOW_SETUP_PHASE(ti, PH_DISC); 194579697Snon } 194679697Snon else 194779697Snon { 194879697Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 194979697Snon } 195079697Snon 195167468Snon /* clear all nexus pointer */ 195279697Snon slp->sl_Qnexus = NULL; 195379697Snon slp->sl_Lnexus = NULL; 195479697Snon slp->sl_Tnexus = NULL; 195567468Snon 195667468Snon /* clear selection assert */ 195767468Snon slp->sl_selid = NULL; 195867468Snon 195967468Snon /* clear nexus data */ 196067468Snon slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; 196179697Snon 196279697Snon /* clear phase change counter */ 196379697Snon slp->sl_ph_count = 0; 196467468Snon} 196567468Snon 196667468Snonstatic int 196779697Snonscsi_low_setup_done(slp, cb) 196867468Snon struct scsi_low_softc *slp; 196967468Snon struct slccb *cb; 197067468Snon{ 197167468Snon struct targ_info *ti; 197267468Snon struct lun_info *li; 197367468Snon 197467468Snon ti = cb->ti; 197567468Snon li = cb->li; 197679697Snon 197779697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 197867468Snon { 197979697Snon cb->ccb_error |= ABORTIO; 198079697Snon return SCSI_LOW_DONE_COMPLETE; 198179697Snon } 198279697Snon 198379697Snon /* XXX: special huck for selection timeout */ 198479697Snon if (li->li_state == SCSI_LOW_LUN_SLEEP && 198579697Snon (cb->ccb_error & SELTIMEOUTIO) != 0) 198679697Snon { 198779697Snon cb->ccb_error |= ABORTIO; 198879697Snon return SCSI_LOW_DONE_COMPLETE; 198979697Snon } 199079697Snon 199179697Snon switch(li->li_state) 199279697Snon { 199379697Snon case SCSI_LOW_LUN_INQ: 199479697Snon if (cb->ccb_error != 0) 199567468Snon { 199679697Snon li->li_diskflags &= 199779697Snon ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG); 199879697Snon if (li->li_lun > 0) 199979697Snon goto resume; 200079697Snon ti->ti_diskflags &= 200179697Snon ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE); 200267468Snon } 200379697Snon else if ((li->li_inq.sd_version & 7) >= 2 || 200479697Snon (li->li_inq.sd_len >= 4)) 200567468Snon { 200679697Snon if ((li->li_inq.sd_support & 0x2) == 0) 200779697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 200879697Snon if ((li->li_inq.sd_support & 0x8) == 0) 200979697Snon li->li_diskflags &= ~SCSI_LOW_DISK_LINK; 201079697Snon if (li->li_lun > 0) 201179697Snon goto resume; 201279697Snon if ((li->li_inq.sd_support & 0x10) == 0) 201379697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC; 201479697Snon if ((li->li_inq.sd_support & 0x20) == 0) 201579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16; 201679697Snon if ((li->li_inq.sd_support & 0x40) == 0) 201779697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32; 201879697Snon } 201979697Snon else 202079697Snon { 202179697Snon li->li_diskflags &= 202279697Snon ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK); 202379697Snon if (li->li_lun > 0) 202479697Snon goto resume; 202579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE; 202679697Snon } 202779697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID; 202879697Snonresume: 202979697Snon scsi_low_calcf_target(ti); 203079697Snon scsi_low_calcf_lun(li); 203179697Snon break; 203279697Snon 203379697Snon case SCSI_LOW_LUN_MODEQ: 203479697Snon if (cb->ccb_error != 0) 203579697Snon { 203679697Snon if (cb->ccb_error & SENSEIO) 203767468Snon { 203879697Snon#ifdef SCSI_LOW_DEBUG 203979697Snon if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) 204079697Snon { 2041225950Sken int error_code, sense_key, asc, ascq; 2042225950Sken 2043225950Sken scsi_extract_sense(&cb->ccb_sense, 2044225950Sken &error_code, 2045225950Sken &sense_key, 2046225950Sken &asc, 2047225950Sken &ascq); 2048225950Sken printf("SENSE: [%x][%x][%x][%x]\n", 2049225950Sken error_code, sense_key, asc, 2050225950Sken ascq); 205179697Snon } 205279697Snon#endif /* SCSI_LOW_DEBUG */ 205367468Snon } 205479697Snon else 205579697Snon { 205679697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 205779697Snon } 205879697Snon } 205979697Snon else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a) 206079697Snon { 206179697Snon if (li->li_sms.sms_cmp.cmp_qc & 0x02) 206279697Snon li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR; 206379697Snon else 206479697Snon li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR; 206579697Snon if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0) 206679697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 206779697Snon } 206879697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID; 206979697Snon scsi_low_calcf_lun(li); 207079697Snon break; 207167468Snon 207279697Snon default: 207379697Snon break; 207479697Snon } 207579697Snon 207679697Snon li->li_state ++; 207779697Snon if (li->li_state == SCSI_LOW_LUN_OK) 207879697Snon { 207979697Snon scsi_low_calcf_target(ti); 208079697Snon scsi_low_calcf_lun(li); 208179697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID && 208279697Snon (slp->sl_show_result & SHOW_CALCF_RES) != 0) 208379697Snon { 208479697Snon scsi_low_calcf_show(li); 208579697Snon } 208679697Snon } 208779697Snon 208879697Snon cb->ccb_rcnt --; 208979697Snon return SCSI_LOW_DONE_RETRY; 209079697Snon} 209179697Snon 209279697Snonstatic int 209379697Snonscsi_low_done(slp, cb) 209479697Snon struct scsi_low_softc *slp; 209579697Snon struct slccb *cb; 209679697Snon{ 209779697Snon int rv; 209879697Snon 209979697Snon if (cb->ccb_error == 0) 210079697Snon { 210179697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 210279697Snon { 210379697Snon#ifdef SCSI_LOW_QCLEAR_AFTER_CA 210479697Snon /* XXX: 210579697Snon * SCSI-2 draft suggests 210679697Snon * page 0x0a QErr bit determins if 210779697Snon * the target aborts or continues 210879697Snon * the queueing io's after CA state resolved. 210979697Snon * However many targets seem not to support 211079697Snon * the page 0x0a. Thus we should manually clear the 211179697Snon * queuing io's after CA state. 211279697Snon */ 211379697Snon if ((cb->ccb_flags & CCB_CLEARQ) == 0) 211467468Snon { 211579697Snon cb->ccb_rcnt --; 211679697Snon cb->ccb_flags |= CCB_CLEARQ; 211779697Snon goto retry; 211879697Snon } 211979697Snon#endif /* SCSI_LOW_QCLEAR_AFTER_CA */ 212079697Snon 212179697Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 212279697Snon cb->ccb_error |= (SENSEIO | ABORTIO); 212379697Snon cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ); 212479697Snon } 212579697Snon else switch (cb->ccb_sscp.scp_status) 212679697Snon { 212779697Snon case ST_GOOD: 212879697Snon case ST_MET: 212979697Snon case ST_INTERGOOD: 213079697Snon case ST_INTERMET: 213179697Snon if (cb->ccb_datalen == 0 || 213279697Snon cb->ccb_scp.scp_datalen == 0) 213367468Snon break; 213467468Snon 213579697Snon if (cb->ccb_scp.scp_cmdlen > 0 && 213679697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 213779697Snon SCSI_LOW_CMD_RESIDUAL_CHK) == 0) 213879697Snon break; 213979697Snon 214067468Snon cb->ccb_error |= PDMAERR; 214167468Snon break; 214267468Snon 214379697Snon case ST_BUSY: 214479697Snon case ST_QUEFULL: 214579697Snon cb->ccb_error |= (BUSYERR | STATERR); 214679697Snon break; 214779697Snon 214879697Snon case ST_CONFLICT: 214979697Snon cb->ccb_error |= (STATERR | ABORTIO); 215079697Snon break; 215179697Snon 215267468Snon case ST_CHKCOND: 215379697Snon case ST_CMDTERM: 215479697Snon if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL)) 215579697Snon { 215679697Snon cb->ccb_rcnt --; 215773025Snon cb->ccb_flags |= CCB_SENSE; 215873025Snon goto retry; 215973025Snon } 216079697Snon cb->ccb_error |= (UACAERR | STATERR | ABORTIO); 216173025Snon break; 216267468Snon 216379697Snon case ST_UNKNOWN: 216467468Snon default: 216567468Snon cb->ccb_error |= FATALIO; 216667468Snon break; 216767468Snon } 216867468Snon } 216967468Snon else 217067468Snon { 217179697Snon if (cb->ccb_flags & CCB_SENSE) 217267468Snon { 217379697Snon cb->ccb_error |= (SENSEERR | ABORTIO); 217467468Snon } 217579697Snon cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE); 217679697Snon } 217767468Snon 217879697Snon /* internal ccb */ 217979697Snon if ((cb->ccb_flags & CCB_INTERNAL) != 0) 218079697Snon { 218179697Snon if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY) 218279697Snon goto retry; 218367468Snon } 218467468Snon 218579697Snon /* check a ccb msgout flag */ 218679697Snon if (cb->ccb_omsgoutflag != 0) 218767468Snon { 218879697Snon#define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \ 218979697Snon SCSI_LOW_MSG_ABORT_QTAG | \ 219079697Snon SCSI_LOW_MSG_CLEAR_QTAG | \ 219179697Snon SCSI_LOW_MSG_TERMIO) 219279697Snon 219379697Snon if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0) 219467468Snon { 219579697Snon cb->ccb_error |= ABORTIO; 219667468Snon } 219767468Snon } 219867468Snon 219979697Snon /* call OS depend done */ 220079697Snon if (cb->osdep != NULL) 220167468Snon { 220279697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb); 220379697Snon if (rv == EJUSTRETURN) 220479697Snon goto retry; 220567468Snon } 220679697Snon else if (cb->ccb_error != 0) 220767468Snon { 220879697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 220979697Snon cb->ccb_error |= ABORTIO; 221079697Snon 221179697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 221279697Snon (cb->ccb_error & ABORTIO) == 0) 221367468Snon goto retry; 221467468Snon } 221579697Snon 221679697Snon /* free our target */ 221779697Snon#ifdef SCSI_LOW_DEBUG 221879697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 221967468Snon { 222079697Snon printf(">> SCSI_LOW_DONE_COMPLETE ===============\n"); 222179697Snon scsi_low_print(slp, NULL); 222267468Snon } 222379697Snon#endif /* SCSI_LOW_DEBUG */ 222467468Snon 222579697Snon scsi_low_deactivate_qtag(cb); 222679697Snon scsi_low_dealloc_qtag(cb); 222767468Snon scsi_low_free_ccb(cb); 222879697Snon slp->sl_nio --; 222967468Snon return SCSI_LOW_DONE_COMPLETE; 223067468Snon 223167468Snonretry: 223279697Snon#ifdef SCSI_LOW_DEBUG 223379697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 223467468Snon { 223579697Snon printf("** SCSI_LOW_DONE_RETRY ===============\n"); 223679697Snon scsi_low_print(slp, NULL); 223767468Snon } 223879697Snon#endif /* SCSI_LOW_DEBUG */ 223979697Snon 224079697Snon cb->ccb_rcnt ++; 224179697Snon scsi_low_deactivate_qtag(cb); 224279697Snon scsi_low_ccb_message_retry(cb); 224367468Snon return SCSI_LOW_DONE_RETRY; 224467468Snon} 224567468Snon 224667468Snon/************************************************************** 224767468Snon * Reset 224867468Snon **************************************************************/ 224967468Snonstatic void 225079697Snonscsi_low_reset_nexus_target(slp, ti, fdone) 225179697Snon struct scsi_low_softc *slp; 225279697Snon struct targ_info *ti; 225379697Snon int fdone; 225467468Snon{ 225579697Snon struct lun_info *li; 225667468Snon 225779697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 225879697Snon li = LIST_NEXT(li, lun_chain)) 225979697Snon { 226079697Snon scsi_low_reset_nexus_lun(slp, li, fdone); 226179697Snon li->li_state = SCSI_LOW_LUN_SLEEP; 226279697Snon li->li_maxnqio = 0; 226379697Snon } 226479697Snon 226579697Snon ti->ti_disc = 0; 226679697Snon ti->ti_setup_msg = 0; 226779697Snon ti->ti_setup_msg_done = 0; 226879697Snon 226979697Snon ti->ti_osynch.offset = ti->ti_osynch.period = 0; 227079697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 227179697Snon 227279697Snon ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 227379697Snon ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID; 227479697Snon 227579697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 227679697Snon { 227779697Snon ((*slp->sl_funcs->scsi_low_targ_init) 227879697Snon (slp, ti, SCSI_LOW_INFO_REVOKE)); 227979697Snon } 228079697Snon scsi_low_calcf_target(ti); 228179697Snon 228279697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 228379697Snon li = LIST_NEXT(li, lun_chain)) 228479697Snon { 228579697Snon li->li_flags = 0; 228679697Snon 228779697Snon li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 228879697Snon li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID; 228979697Snon 229079697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 229179697Snon { 229279697Snon ((*slp->sl_funcs->scsi_low_lun_init) 229379697Snon (slp, ti, li, SCSI_LOW_INFO_REVOKE)); 229479697Snon } 229579697Snon scsi_low_calcf_lun(li); 229679697Snon } 229767468Snon} 229867468Snon 229967468Snonstatic void 230067468Snonscsi_low_reset_nexus(slp, fdone) 230167468Snon struct scsi_low_softc *slp; 230267468Snon int fdone; 230367468Snon{ 230467468Snon struct targ_info *ti; 230579697Snon struct slccb *cb, *topcb; 230667468Snon 230779697Snon if ((cb = slp->sl_Qnexus) != NULL) 230867468Snon { 230979697Snon topcb = scsi_low_revoke_ccb(slp, cb, fdone); 231067468Snon } 231179697Snon else 231279697Snon { 231379697Snon topcb = NULL; 231479697Snon } 231567468Snon 231679697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 231779697Snon ti = TAILQ_NEXT(ti, ti_chain)) 231867468Snon { 231979697Snon scsi_low_reset_nexus_target(slp, ti, fdone); 232079697Snon scsi_low_bus_release(slp, ti); 232167468Snon scsi_low_init_msgsys(slp, ti); 232267468Snon } 232367468Snon 232479697Snon if (topcb != NULL) 232579697Snon { 232679697Snon topcb->ccb_flags |= CCB_STARTQ; 232779697Snon TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain); 232879697Snon } 232979697Snon 233079697Snon slp->sl_disc = 0; 233179697Snon slp->sl_retry_sel = 0; 233267468Snon slp->sl_flags &= ~HW_PDMASTART; 233367468Snon} 233467468Snon 233567468Snon/* misc */ 233667468Snonstatic int tw_pos; 233767468Snonstatic char tw_chars[] = "|/-\\"; 233879697Snon#define TWIDDLEWAIT 10000 233967468Snon 234067468Snonstatic void 234167468Snonscsi_low_twiddle_wait(void) 234267468Snon{ 234367468Snon 234467468Snon cnputc('\b'); 234567468Snon cnputc(tw_chars[tw_pos++]); 234667468Snon tw_pos %= (sizeof(tw_chars) - 1); 2347240172Sjhb DELAY(TWIDDLEWAIT); 234867468Snon} 234967468Snon 235067468Snonvoid 235167468Snonscsi_low_bus_reset(slp) 235267468Snon struct scsi_low_softc *slp; 235367468Snon{ 235467468Snon int i; 235567468Snon 235667468Snon (*slp->sl_funcs->scsi_low_bus_reset) (slp); 235767468Snon 2358240325Sjhb device_printf(slp->sl_dev, "try to reset scsi bus "); 235967468Snon for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) 236067468Snon scsi_low_twiddle_wait(); 236167468Snon cnputc('\b'); 236267468Snon printf("\n"); 236367468Snon} 236467468Snon 236567468Snonint 236667468Snonscsi_low_restart(slp, flags, s) 236767468Snon struct scsi_low_softc *slp; 236867468Snon int flags; 236967468Snon u_char *s; 237067468Snon{ 237167468Snon int error; 237267468Snon 237367468Snon if (s != NULL) 2374240325Sjhb device_printf(slp->sl_dev, "scsi bus restart. reason: %s\n", s); 237567468Snon 237667468Snon if ((error = scsi_low_init(slp, flags)) != 0) 237767468Snon return error; 237867468Snon 237967468Snon scsi_low_start(slp); 238067468Snon return 0; 238167468Snon} 238267468Snon 238367468Snon/************************************************************** 238467468Snon * disconnect and reselect 238567468Snon **************************************************************/ 238667468Snon#define MSGCMD_LUN(msg) (msg & 0x07) 238767468Snon 238867468Snonstatic struct slccb * 238967468Snonscsi_low_establish_ccb(ti, li, tag) 239067468Snon struct targ_info *ti; 239167468Snon struct lun_info *li; 239267468Snon scsi_low_tag_t tag; 239367468Snon{ 239467468Snon struct scsi_low_softc *slp = ti->ti_sc; 239567468Snon struct slccb *cb; 239667468Snon 239779697Snon if (li == NULL) 239879697Snon return NULL; 239979697Snon 240079697Snon cb = TAILQ_FIRST(&li->li_discq); 240171999Sphk for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) 240279697Snon if (cb->ccb_tag == tag) 240367468Snon goto found; 240467468Snon return cb; 240567468Snon 240667468Snon /* 240767468Snon * establish our ccb nexus 240867468Snon */ 240967468Snonfound: 241079697Snon#ifdef SCSI_LOW_DEBUG 241179697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 241279697Snon { 2413240325Sjhb device_printf(slp->sl_dev, "nexus(0x%lx) abort check start\n", 2414240325Sjhb (u_long) cb); 241579697Snon cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT); 241679697Snon scsi_low_revoke_ccb(slp, cb, 1); 241779697Snon return NULL; 241879697Snon } 241967468Snon 242079697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0) 242179697Snon { 242279697Snon if (cb->ccb_omsgoutflag == 0) 242379697Snon scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP); 242479697Snon } 242579697Snon#endif /* SCSI_LOW_DEBUG */ 242679697Snon 242779697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 242879697Snon cb->ccb_flags &= ~CCB_DISCQ; 242979697Snon slp->sl_Qnexus = cb; 243079697Snon 243167468Snon slp->sl_scp = cb->ccb_sscp; 243267468Snon slp->sl_error |= cb->ccb_error; 243367468Snon 243467468Snon slp->sl_disc --; 243579697Snon ti->ti_disc --; 243667468Snon li->li_disc --; 243767468Snon 243867468Snon /* inform "ccb nexus established" to the host driver */ 243979697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 244079697Snon 244179697Snon /* check msg */ 244279697Snon if (cb->ccb_msgoutflag != 0) 244379697Snon { 244479697Snon scsi_low_ccb_message_exec(slp, cb); 244579697Snon } 244679697Snon 244767468Snon return cb; 244867468Snon} 244967468Snon 245067468Snonstruct targ_info * 245167468Snonscsi_low_reselected(slp, targ) 245267468Snon struct scsi_low_softc *slp; 245367468Snon u_int targ; 245467468Snon{ 245567468Snon struct targ_info *ti; 245679697Snon struct slccb *cb; 245767468Snon u_char *s; 245867468Snon 245967468Snon /* 246067468Snon * Check select vs reselected collision. 246167468Snon */ 246267468Snon 246379697Snon if ((cb = slp->sl_selid) != NULL) 246467468Snon { 246579697Snon scsi_low_arbit_fail(slp, cb); 246667468Snon#ifdef SCSI_LOW_STATICS 246767468Snon scsi_low_statics.nexus_conflict ++; 246867468Snon#endif /* SCSI_LOW_STATICS */ 246967468Snon } 247079697Snon 247179697Snon /* 247279697Snon * Check if no current active nexus. 247379697Snon */ 247479697Snon if (slp->sl_Tnexus != NULL) 247567468Snon { 247667468Snon s = "host busy"; 247767468Snon goto world_restart; 247867468Snon } 247967468Snon 248067468Snon /* 248167468Snon * Check a valid target id asserted ? 248267468Snon */ 248367468Snon if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) 248467468Snon { 248567468Snon s = "scsi id illegal"; 248667468Snon goto world_restart; 248767468Snon } 248867468Snon 248967468Snon /* 249067468Snon * Check the target scsi status. 249167468Snon */ 249267468Snon ti = slp->sl_ti[targ]; 249379697Snon if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL) 249467468Snon { 249567468Snon s = "phase mismatch"; 249667468Snon goto world_restart; 249767468Snon } 249867468Snon 249967468Snon /* 250079697Snon * Setup init msgsys 250167468Snon */ 250267468Snon slp->sl_error = 0; 250367468Snon scsi_low_init_msgsys(slp, ti); 250467468Snon 250567468Snon /* 250667468Snon * Establish our target nexus 250767468Snon */ 250867468Snon SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); 250979697Snon slp->sl_Tnexus = ti; 251067468Snon#ifdef SCSI_LOW_STATICS 251167468Snon scsi_low_statics.nexus_reselected ++; 251267468Snon#endif /* SCSI_LOW_STATICS */ 251367468Snon return ti; 251467468Snon 251567468Snonworld_restart: 2516240325Sjhb device_printf(slp->sl_dev, "reselect(%x:unknown) %s\n", targ, s); 251767468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 251867468Snon "reselect: scsi world confused"); 251967468Snon return NULL; 252067468Snon} 252167468Snon 252267468Snon/************************************************************** 252367468Snon * cmd out pointer setup 252467468Snon **************************************************************/ 252567468Snonint 252667468Snonscsi_low_cmd(slp, ti) 252767468Snon struct scsi_low_softc *slp; 252867468Snon struct targ_info *ti; 252967468Snon{ 253079697Snon struct slccb *cb = slp->sl_Qnexus; 253167468Snon 253279697Snon slp->sl_ph_count ++; 253367468Snon if (cb == NULL) 253467468Snon { 253567468Snon /* 253679697Snon * no ccb, abort! 253767468Snon */ 253867468Snon slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 253967468Snon slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); 254067468Snon slp->sl_scp.scp_datalen = 0; 254167468Snon slp->sl_scp.scp_direction = SCSI_LOW_READ; 254279697Snon slp->sl_error |= FATALIO; 254379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 254479697Snon SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found"); 254579697Snon return EINVAL; 254667468Snon } 254779697Snon else 254867468Snon { 254979697Snon#ifdef SCSI_LOW_DEBUG 255079697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id)) 255179697Snon { 255279697Snon scsi_low_test_cmdlnk(slp, cb); 255379697Snon } 255479697Snon#endif /* SCSI_LOW_DEBUG */ 255567468Snon } 255667468Snon return 0; 255767468Snon} 255867468Snon 255967468Snon/************************************************************** 256067468Snon * data out pointer setup 256167468Snon **************************************************************/ 256267468Snonint 256367468Snonscsi_low_data(slp, ti, bp, direction) 256467468Snon struct scsi_low_softc *slp; 256567468Snon struct targ_info *ti; 256667468Snon struct buf **bp; 256767468Snon int direction; 256867468Snon{ 256979697Snon struct slccb *cb = slp->sl_Qnexus; 257067468Snon 257179697Snon if (cb != NULL && direction == cb->ccb_sscp.scp_direction) 257267468Snon { 257379697Snon *bp = cb->bp; 257479697Snon return 0; 257567468Snon } 257667468Snon 257779697Snon slp->sl_error |= (FATALIO | PDMAERR); 257879697Snon slp->sl_scp.scp_datalen = 0; 257979697Snon slp->sl_scp.scp_direction = direction; 258079697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 258179697Snon if (ti->ti_ophase != ti->ti_phase) 258267468Snon { 258379697Snon char *s; 258479697Snon 258579697Snon if (cb == NULL) 258679697Snon s = "DATA PHASE: ccb nexus not found"; 258779697Snon else 258879697Snon s = "DATA PHASE: xfer direction mismatch"; 258979697Snon SCSI_LOW_INFO(slp, ti, s); 259067468Snon } 259167468Snon 259279697Snon *bp = NULL; 259379697Snon return EINVAL; 259467468Snon} 259567468Snon 259667468Snon/************************************************************** 259767468Snon * MSG_SYS 259867468Snon **************************************************************/ 259967468Snon#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} 260067468Snon#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) 260167468Snon#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) 260279697Snon#define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3]) 260367468Snon#define MSGIN_DATA_LAST 0x30 260467468Snon 260592770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int); 260692770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int); 260792770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int); 260892770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int); 260967468Snon 261092770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *); 261192770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *); 261292770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *); 261392770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *); 261492770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *); 261592770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *); 261692770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *); 261767468Snon 261867468Snonstruct scsi_low_msgout_data { 261967468Snon u_int md_flags; 262067468Snon u_int8_t md_msg; 262192770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 262292770Salfred int (*md_errfunc)(struct scsi_low_softc *, u_int); 262379697Snon#define MSG_RELEASE_ATN 0x0001 262479697Snon u_int md_condition; 262567468Snon}; 262667468Snon 262767468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = { 262879697Snon/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN}, 262979697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN}, 263079697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN}, 263179697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN}, 263279697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0}, 263379697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 263479697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN}, 263579697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 263679697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 263779697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 263879697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN}, 263979697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 264079697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN}, 264179697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN}, 264279697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN}, 264379697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0}, 264467468Snon}; 264567468Snon 264692770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *); 264792770Salfredstatic int scsi_low_synch(struct scsi_low_softc *); 264892770Salfredstatic int scsi_low_wide(struct scsi_low_softc *); 264992770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *); 265092770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *); 265192770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *); 265292770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *); 265392770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *); 265492770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *); 265592770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *); 265692770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *); 265792770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *); 265892770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *); 265992770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *); 266067468Snon 266167468Snonstruct scsi_low_msgin_data { 266267468Snon u_int md_len; 266392770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 266467468Snon}; 266567468Snon 266667468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = { 266767468Snon/* 0 */ {1, scsi_low_msginfunc_cc}, 266867468Snon/* 1 */ {2, scsi_low_msginfunc_ext}, 266967468Snon/* 2 */ {1, scsi_low_msginfunc_sdp}, 267079697Snon/* 3 */ {1, scsi_low_msginfunc_rp}, 267167468Snon/* 4 */ {1, scsi_low_msginfunc_disc}, 267267468Snon/* 5 */ {1, scsi_low_msginfunc_rejop}, 267367468Snon/* 6 */ {1, scsi_low_msginfunc_rejop}, 267467468Snon/* 7 */ {1, scsi_low_msginfunc_msg_reject}, 267567468Snon/* 8 */ {1, scsi_low_msginfunc_noop}, 267667468Snon/* 9 */ {1, scsi_low_msginfunc_parity}, 267779697Snon/* a */ {1, scsi_low_msginfunc_lcc}, 267879697Snon/* b */ {1, scsi_low_msginfunc_lcc}, 267967468Snon/* c */ {1, scsi_low_msginfunc_rejop}, 268067468Snon/* d */ {2, scsi_low_msginfunc_rejop}, 268167468Snon/* e */ {1, scsi_low_msginfunc_rejop}, 268267468Snon/* f */ {1, scsi_low_msginfunc_rejop}, 268367468Snon/* 0x10 */ {1, scsi_low_msginfunc_rejop}, 268467468Snon/* 0x11 */ {1, scsi_low_msginfunc_rejop}, 268567468Snon/* 0x12 */ {1, scsi_low_msginfunc_rejop}, 268667468Snon/* 0x13 */ {1, scsi_low_msginfunc_rejop}, 268767468Snon/* 0x14 */ {1, scsi_low_msginfunc_rejop}, 268867468Snon/* 0x15 */ {1, scsi_low_msginfunc_rejop}, 268967468Snon/* 0x16 */ {1, scsi_low_msginfunc_rejop}, 269067468Snon/* 0x17 */ {1, scsi_low_msginfunc_rejop}, 269167468Snon/* 0x18 */ {1, scsi_low_msginfunc_rejop}, 269267468Snon/* 0x19 */ {1, scsi_low_msginfunc_rejop}, 269367468Snon/* 0x1a */ {1, scsi_low_msginfunc_rejop}, 269467468Snon/* 0x1b */ {1, scsi_low_msginfunc_rejop}, 269567468Snon/* 0x1c */ {1, scsi_low_msginfunc_rejop}, 269667468Snon/* 0x1d */ {1, scsi_low_msginfunc_rejop}, 269767468Snon/* 0x1e */ {1, scsi_low_msginfunc_rejop}, 269867468Snon/* 0x1f */ {1, scsi_low_msginfunc_rejop}, 269979697Snon/* 0x20 */ {2, scsi_low_msginfunc_simple_qtag}, 270067468Snon/* 0x21 */ {2, scsi_low_msginfunc_rejop}, 270167468Snon/* 0x22 */ {2, scsi_low_msginfunc_rejop}, 270279697Snon/* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue}, 270367468Snon/* 0x24 */ {2, scsi_low_msginfunc_rejop}, 270467468Snon/* 0x25 */ {2, scsi_low_msginfunc_rejop}, 270567468Snon/* 0x26 */ {2, scsi_low_msginfunc_rejop}, 270667468Snon/* 0x27 */ {2, scsi_low_msginfunc_rejop}, 270767468Snon/* 0x28 */ {2, scsi_low_msginfunc_rejop}, 270867468Snon/* 0x29 */ {2, scsi_low_msginfunc_rejop}, 270967468Snon/* 0x2a */ {2, scsi_low_msginfunc_rejop}, 271067468Snon/* 0x2b */ {2, scsi_low_msginfunc_rejop}, 271167468Snon/* 0x2c */ {2, scsi_low_msginfunc_rejop}, 271267468Snon/* 0x2d */ {2, scsi_low_msginfunc_rejop}, 271367468Snon/* 0x2e */ {2, scsi_low_msginfunc_rejop}, 271467468Snon/* 0x2f */ {2, scsi_low_msginfunc_rejop}, 271567468Snon/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ 271667468Snon}; 271767468Snon 271867468Snon/************************************************************** 271967468Snon * msgout 272067468Snon **************************************************************/ 272167468Snonstatic int 272279697Snonscsi_low_msgfunc_synch(slp) 272379697Snon struct scsi_low_softc *slp; 272467468Snon{ 272579697Snon struct targ_info *ti = slp->sl_Tnexus; 272667468Snon int ptr = ti->ti_msgoutlen; 272767468Snon 272867468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; 272967468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; 273073025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period; 273173025Snon ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset; 273267468Snon return MSG_EXTEND_SYNCHLEN + 2; 273367468Snon} 273467468Snon 273567468Snonstatic int 273679697Snonscsi_low_msgfunc_wide(slp) 273779697Snon struct scsi_low_softc *slp; 273867468Snon{ 273979697Snon struct targ_info *ti = slp->sl_Tnexus; 274067468Snon int ptr = ti->ti_msgoutlen; 274167468Snon 274267468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; 274367468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; 274473025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_width; 274567468Snon return MSG_EXTEND_WIDELEN + 2; 274667468Snon} 274767468Snon 274867468Snonstatic int 274979697Snonscsi_low_msgfunc_identify(slp) 275079697Snon struct scsi_low_softc *slp; 275167468Snon{ 275279697Snon struct targ_info *ti = slp->sl_Tnexus; 275379697Snon struct lun_info *li = slp->sl_Lnexus; 275479697Snon struct slccb *cb = slp->sl_Qnexus; 275579697Snon int ptr = ti->ti_msgoutlen; 275679697Snon u_int8_t msg; 275767468Snon 275879697Snon msg = MSG_IDENTIFY; 275979697Snon if (cb == NULL) 276067468Snon { 276179697Snon slp->sl_error |= FATALIO; 276279697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 276379697Snon SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown"); 276467468Snon } 276567468Snon else 276667468Snon { 276779697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 276879697Snon msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun); 276979697Snon else 277079697Snon msg |= li->li_lun; 277179697Snon 277279697Snon if (ti->ti_phase == PH_MSGOUT) 277379697Snon { 277479697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 277579697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 277679697Snon { 277779697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 277879697Snon } 277979697Snon } 278067468Snon } 278179697Snon ti->ti_msgoutstr[ptr + 0] = msg; 278267468Snon return 1; 278367468Snon} 278467468Snon 278567468Snonstatic int 278679697Snonscsi_low_msgfunc_abort(slp) 278779697Snon struct scsi_low_softc *slp; 278867468Snon{ 278967468Snon 279079697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT); 279179697Snon return 1; 279279697Snon} 279379697Snon 279479697Snonstatic int 279579697Snonscsi_low_msgfunc_qabort(slp) 279679697Snon struct scsi_low_softc *slp; 279779697Snon{ 279879697Snon 279979697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM); 280079697Snon return 1; 280179697Snon} 280279697Snon 280379697Snonstatic int 280479697Snonscsi_low_msgfunc_reset(slp) 280579697Snon struct scsi_low_softc *slp; 280679697Snon{ 280779697Snon 280879697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET); 280979697Snon return 1; 281079697Snon} 281179697Snon 281279697Snonstatic int 281379697Snonscsi_low_msgfunc_qtag(slp) 281479697Snon struct scsi_low_softc *slp; 281579697Snon{ 281679697Snon struct targ_info *ti = slp->sl_Tnexus; 281779697Snon struct slccb *cb = slp->sl_Qnexus; 281879697Snon int ptr = ti->ti_msgoutlen; 281979697Snon 282079697Snon if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG) 282167468Snon { 282267468Snon ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; 282367468Snon return 1; 282467468Snon } 282567468Snon else 282667468Snon { 282779697Snon ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag; 282879697Snon if (ti->ti_phase == PH_MSGOUT) 282979697Snon { 283079697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 283179697Snon } 283267468Snon } 283379697Snon return 2; 283467468Snon} 283567468Snon 283667468Snon/* 283767468Snon * The following functions are called when targets give unexpected 283867468Snon * responces in msgin (after msgout). 283967468Snon */ 284067468Snonstatic int 284179697Snonscsi_low_errfunc_identify(slp, msgflags) 284279697Snon struct scsi_low_softc *slp; 284367468Snon u_int msgflags; 284467468Snon{ 284567468Snon 284679697Snon if (slp->sl_Lnexus != NULL) 284779697Snon { 284879697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC; 284979697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 285079697Snon } 285167468Snon return 0; 285267468Snon} 285367468Snon 285467468Snonstatic int 285579697Snonscsi_low_errfunc_synch(slp, msgflags) 285679697Snon struct scsi_low_softc *slp; 285767468Snon u_int msgflags; 285867468Snon{ 285979697Snon struct targ_info *ti = slp->sl_Tnexus; 286067468Snon 286167468Snon MSGIN_PERIOD(ti) = 0; 286267468Snon MSGIN_OFFSET(ti) = 0; 286379697Snon scsi_low_synch(slp); 286467468Snon return 0; 286567468Snon} 286667468Snon 286767468Snonstatic int 286879697Snonscsi_low_errfunc_wide(slp, msgflags) 286979697Snon struct scsi_low_softc *slp; 287067468Snon u_int msgflags; 287167468Snon{ 287279697Snon struct targ_info *ti = slp->sl_Tnexus; 287379697Snon 287479697Snon MSGIN_WIDTHP(ti) = 0; 287579697Snon scsi_low_wide(slp); 287667468Snon return 0; 287767468Snon} 287867468Snon 287979697Snonstatic int 288079697Snonscsi_low_errfunc_qtag(slp, msgflags) 288179697Snon struct scsi_low_softc *slp; 288279697Snon u_int msgflags; 288379697Snon{ 288479697Snon 288579697Snon if ((msgflags & SCSI_LOW_MSG_REJECT) != 0) 288679697Snon { 288779697Snon if (slp->sl_Qnexus != NULL) 288879697Snon { 288979697Snon scsi_low_deactivate_qtag(slp->sl_Qnexus); 289079697Snon } 289179697Snon if (slp->sl_Lnexus != NULL) 289279697Snon { 289379697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG; 289479697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 289579697Snon } 2896240325Sjhb device_printf(slp->sl_dev, "scsi_low: qtag msg rejected\n"); 289779697Snon } 289879697Snon return 0; 289979697Snon} 290079697Snon 290179697Snon 290267468Snonint 290379697Snonscsi_low_msgout(slp, ti, fl) 290467468Snon struct scsi_low_softc *slp; 290567468Snon struct targ_info *ti; 290679697Snon u_int fl; 290767468Snon{ 290867468Snon struct scsi_low_msgout_data *mdp; 290967468Snon int len = 0; 291067468Snon 291179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 291279697Snon if (ti != slp->sl_Tnexus) 291379697Snon { 291479697Snon scsi_low_print(slp, NULL); 291579697Snon panic("scsi_low_msgout: Target nexus inconsistent"); 291679697Snon } 291779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 291879697Snon 291979697Snon slp->sl_ph_count ++; 292079697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 292179697Snon { 2922240325Sjhb device_printf(slp->sl_dev, "too many phase changes\n"); 292379697Snon slp->sl_error |= FATALIO; 292479697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 292579697Snon } 292679697Snon 292767468Snon /* STEP I. 292867468Snon * Scsi phase changes. 292967468Snon * Previously msgs asserted are accepted by our target or 293067468Snon * processed by scsi_low_msgin. 293167468Snon * Thus clear all saved informations. 293267468Snon */ 293379697Snon if ((fl & SCSI_LOW_MSGOUT_INIT) != 0) 293467468Snon { 293567468Snon ti->ti_omsgflags = 0; 293667468Snon ti->ti_emsgflags = 0; 293767468Snon } 293879697Snon else if (slp->sl_atten == 0) 293979697Snon { 294067468Snon /* STEP II. 294167468Snon * We did not assert attention, however still our target required 294267468Snon * msgs. Resend previous msgs. 294367468Snon */ 294467468Snon ti->ti_msgflags |= ti->ti_omsgflags; 294579697Snon ti->ti_omsgflags = 0; 294667468Snon#ifdef SCSI_LOW_DIAGNOSTIC 2947240325Sjhb device_printf(slp->sl_dev, "scsi_low_msgout: retry msgout\n"); 294867468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 294967468Snon } 295067468Snon 295167468Snon /* STEP III. 295279697Snon * We have no msgs. send MSG_NOOP (OK?) 295367468Snon */ 295479697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 295567468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); 295667468Snon 295767468Snon /* STEP IV. 295867468Snon * Process all msgs 295967468Snon */ 296067468Snon ti->ti_msgoutlen = 0; 296179697Snon slp->sl_clear_atten = 0; 296267468Snon mdp = &scsi_low_msgout_data[0]; 296367468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 296467468Snon { 296567468Snon if ((ti->ti_msgflags & mdp->md_flags) != 0) 296667468Snon { 296767468Snon ti->ti_omsgflags |= mdp->md_flags; 296867468Snon ti->ti_msgflags &= ~mdp->md_flags; 296967468Snon ti->ti_emsgflags = mdp->md_flags; 297067468Snon 297167468Snon ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; 297267468Snon if (mdp->md_msgfunc != NULL) 297379697Snon len = (*mdp->md_msgfunc) (slp); 297467468Snon else 297567468Snon len = 1; 297667468Snon 297779697Snon#ifdef SCSI_LOW_DIAGNOSTIC 297879697Snon scsi_low_msg_log_write(&ti->ti_log_msgout, 297979697Snon &ti->ti_msgoutstr[ti->ti_msgoutlen], len); 298079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 298179697Snon 298267468Snon ti->ti_msgoutlen += len; 298379697Snon if ((mdp->md_condition & MSG_RELEASE_ATN) != 0) 298479697Snon { 298579697Snon slp->sl_clear_atten = 1; 298679697Snon break; 298779697Snon } 298879697Snon 298979697Snon if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 || 299067468Snon ti->ti_msgflags == 0) 299167468Snon break; 299279697Snon 299367468Snon if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) 299467468Snon break; 299567468Snon } 299667468Snon } 299767468Snon 299879697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 299979697Snon slp->sl_clear_atten = 1; 300067468Snon 300167468Snon return ti->ti_msgoutlen; 300267468Snon} 300367468Snon 300467468Snon/************************************************************** 300567468Snon * msgin 300667468Snon **************************************************************/ 300767468Snonstatic int 300879697Snonscsi_low_msginfunc_noop(slp) 300979697Snon struct scsi_low_softc *slp; 301067468Snon{ 301167468Snon 301267468Snon return 0; 301367468Snon} 301467468Snon 301567468Snonstatic int 301679697Snonscsi_low_msginfunc_rejop(slp) 301779697Snon struct scsi_low_softc *slp; 301867468Snon{ 301979697Snon struct targ_info *ti = slp->sl_Tnexus; 302067468Snon u_int8_t msg = ti->ti_msgin[0]; 302167468Snon 3022240325Sjhb device_printf(slp->sl_dev, "MSGIN: msg 0x%x rejected\n", (u_int) msg); 302367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 302467468Snon return 0; 302567468Snon} 302667468Snon 302767468Snonstatic int 302879697Snonscsi_low_msginfunc_cc(slp) 302979697Snon struct scsi_low_softc *slp; 303067468Snon{ 303179697Snon struct lun_info *li; 303267468Snon 303367468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 303479697Snon 303579697Snon /* validate status */ 303679697Snon if (slp->sl_Qnexus == NULL) 303779697Snon return ENOENT; 303879697Snon 303979697Snon slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status; 304079697Snon li = slp->sl_Lnexus; 304179697Snon switch (slp->sl_scp.scp_status) 304279697Snon { 304379697Snon case ST_GOOD: 304479697Snon li->li_maxnqio = li->li_maxnexus; 304579697Snon break; 304679697Snon 304779697Snon case ST_CHKCOND: 304879697Snon li->li_maxnqio = 0; 304979697Snon if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR) 305079697Snon scsi_low_reset_nexus_lun(slp, li, 0); 305179697Snon break; 305279697Snon 305379697Snon case ST_BUSY: 305479697Snon li->li_maxnqio = 0; 305579697Snon break; 305679697Snon 305779697Snon case ST_QUEFULL: 305879697Snon if (li->li_maxnexus >= li->li_nqio) 305979697Snon li->li_maxnexus = li->li_nqio - 1; 306079697Snon li->li_maxnqio = li->li_maxnexus; 306179697Snon break; 306279697Snon 306379697Snon case ST_INTERGOOD: 306479697Snon case ST_INTERMET: 306579697Snon slp->sl_error |= MSGERR; 306679697Snon break; 306779697Snon 306879697Snon default: 306979697Snon break; 307079697Snon } 307167468Snon return 0; 307267468Snon} 307367468Snon 307467468Snonstatic int 307579697Snonscsi_low_msginfunc_lcc(slp) 307679697Snon struct scsi_low_softc *slp; 307779697Snon{ 307867468Snon struct targ_info *ti; 307979697Snon struct lun_info *li; 308079697Snon struct slccb *ncb, *cb; 308179697Snon 308279697Snon ti = slp->sl_Tnexus; 308379697Snon li = slp->sl_Lnexus; 308479697Snon if ((cb = slp->sl_Qnexus) == NULL) 308579697Snon goto bad; 308679697Snon 308779697Snon cb->ccb_sscp.scp_status = slp->sl_scp.scp_status; 308879697Snon switch (slp->sl_scp.scp_status) 308979697Snon { 309079697Snon case ST_INTERGOOD: 309179697Snon case ST_INTERMET: 309279697Snon li->li_maxnqio = li->li_maxnexus; 309379697Snon break; 309479697Snon 309579697Snon default: 309679697Snon slp->sl_error |= MSGERR; 309779697Snon break; 309879697Snon } 309979697Snon 310079697Snon if ((li->li_flags & SCSI_LOW_LINK) == 0) 310179697Snon goto bad; 310279697Snon 310379697Snon cb->ccb_error |= slp->sl_error; 310479697Snon if (cb->ccb_error != 0) 310579697Snon goto bad; 310679697Snon 310779697Snon for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL; 310879697Snon ncb = TAILQ_NEXT(ncb, ccb_chain)) 310979697Snon { 311079697Snon if (ncb->li == li) 311179697Snon goto cmd_link_start; 311279697Snon } 311379697Snon 311479697Snon 311579697Snonbad: 311679697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM); 311779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 311879697Snon return EIO; 311979697Snon 312079697Snoncmd_link_start: 312179697Snon ncb->ccb_flags &= ~CCB_STARTQ; 312279697Snon TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain); 312379697Snon 312479697Snon scsi_low_dealloc_qtag(ncb); 312579697Snon ncb->ccb_tag = cb->ccb_tag; 312679697Snon ncb->ccb_otag = cb->ccb_otag; 312779697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 312879697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 312979697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 3130240325Sjhb panic("%s: linked ccb retried", 3131240325Sjhb device_get_nameunit(slp->sl_dev)); 313279697Snon 313379697Snon slp->sl_Qnexus = ncb; 313479697Snon slp->sl_ph_count = 0; 313579697Snon 313679697Snon ncb->ccb_error = 0; 313779697Snon ncb->ccb_datalen = -1; 313879697Snon ncb->ccb_scp.scp_status = ST_UNKNOWN; 313979697Snon ncb->ccb_flags &= ~CCB_INTERNAL; 314079697Snon 314179697Snon scsi_low_init_msgsys(slp, ti); 314279697Snon 314379697Snon (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb); 314479697Snon 314579697Snon if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 314679697Snon ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 314779697Snon ncb->ccb_tc = ncb->ccb_tcmax; 314879697Snon 314979697Snon /* setup saved scsi data pointer */ 315079697Snon ncb->ccb_sscp = ncb->ccb_scp; 315179697Snon slp->sl_scp = ncb->ccb_sscp; 315279697Snon slp->sl_error = ncb->ccb_error; 315379697Snon 315479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 315579697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 315679697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 315779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 315879697Snon return EJUSTRETURN; 315979697Snon} 316079697Snon 316179697Snonstatic int 316279697Snonscsi_low_msginfunc_disc(slp) 316379697Snon struct scsi_low_softc *slp; 316467468Snon{ 316567468Snon 316667468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); 316767468Snon return 0; 316867468Snon} 316967468Snon 317067468Snonstatic int 317179697Snonscsi_low_msginfunc_sdp(slp) 317279697Snon struct scsi_low_softc *slp; 317367468Snon{ 317479697Snon struct slccb *cb = slp->sl_Qnexus; 317567468Snon 317679697Snon if (cb != NULL) 317779697Snon { 317879697Snon cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen; 317979697Snon cb->ccb_sscp.scp_data = slp->sl_scp.scp_data; 318079697Snon } 318167468Snon else 318279697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 318367468Snon return 0; 318467468Snon} 318567468Snon 318667468Snonstatic int 318779697Snonscsi_low_msginfunc_rp(slp) 318879697Snon struct scsi_low_softc *slp; 318967468Snon{ 319067468Snon 319179697Snon if (slp->sl_Qnexus != NULL) 319279697Snon slp->sl_scp = slp->sl_Qnexus->ccb_sscp; 319367468Snon else 319479697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 319567468Snon return 0; 319667468Snon} 319767468Snon 319867468Snonstatic int 319979697Snonscsi_low_synch(slp) 320079697Snon struct scsi_low_softc *slp; 320167468Snon{ 320279697Snon struct targ_info *ti = slp->sl_Tnexus; 320379697Snon u_int period = 0, offset = 0, speed; 320467468Snon u_char *s; 320567468Snon int error; 320667468Snon 320779697Snon if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period && 320879697Snon MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) || 320979697Snon MSGIN_OFFSET(ti) == 0) 321067468Snon { 321167468Snon if ((offset = MSGIN_OFFSET(ti)) != 0) 321267468Snon period = MSGIN_PERIOD(ti); 321367468Snon s = offset ? "synchronous" : "async"; 321467468Snon } 321567468Snon else 321667468Snon { 321767468Snon /* XXX: 321867468Snon * Target seems to be brain damaged. 321967468Snon * Force async transfer. 322067468Snon */ 322173025Snon ti->ti_maxsynch.period = 0; 322273025Snon ti->ti_maxsynch.offset = 0; 3223240325Sjhb device_printf(slp->sl_dev, 3224240325Sjhb "target brain damaged. async transfer\n"); 322567468Snon return EINVAL; 322667468Snon } 322767468Snon 322873025Snon ti->ti_maxsynch.period = period; 322973025Snon ti->ti_maxsynch.offset = offset; 323067468Snon 323167468Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); 323267468Snon if (error != 0) 323367468Snon { 323467468Snon /* XXX: 323567468Snon * Current period and offset are not acceptable 323667468Snon * for our adapter. 323767468Snon * The adapter changes max synch and max offset. 323867468Snon */ 3239240325Sjhb device_printf(slp->sl_dev, 3240240325Sjhb "synch neg failed. retry synch msg neg ...\n"); 324167468Snon return error; 324267468Snon } 324367468Snon 324479697Snon ti->ti_osynch = ti->ti_maxsynch; 324579697Snon if (offset > 0) 324679697Snon { 324779697Snon ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH; 324879697Snon } 324979697Snon 325067468Snon /* inform data */ 325179697Snon if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0) 325267468Snon { 325379697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 325479697Snon struct slccb *cb = slp->sl_Qnexus; 325579697Snon 325679697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 325779697Snon return 0; 325879697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 325979697Snon 3260240325Sjhb device_printf(slp->sl_dev, 3261240325Sjhb "(%d:*): <%s> offset %d period %dns ", 3262240325Sjhb ti->ti_id, s, offset, period * 4); 326379697Snon 326479697Snon if (period != 0) 326579697Snon { 326679697Snon speed = 1000 * 10 / (period * 4); 326779697Snon printf("%d.%d M/s", speed / 10, speed % 10); 326879697Snon } 326979697Snon printf("\n"); 327067468Snon } 327179697Snon return 0; 327279697Snon} 327367468Snon 327479697Snonstatic int 327579697Snonscsi_low_wide(slp) 327679697Snon struct scsi_low_softc *slp; 327779697Snon{ 327879697Snon struct targ_info *ti = slp->sl_Tnexus; 327979697Snon int error; 328079697Snon 328179697Snon ti->ti_width = MSGIN_WIDTHP(ti); 328279697Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE); 328379697Snon if (error != 0) 328479697Snon { 328579697Snon /* XXX: 328679697Snon * Current width is not acceptable for our adapter. 328779697Snon * The adapter changes max width. 328879697Snon */ 3289240325Sjhb device_printf(slp->sl_dev, 3290240325Sjhb "wide neg failed. retry wide msg neg ...\n"); 329179697Snon return error; 329279697Snon } 329379697Snon 329479697Snon ti->ti_owidth = ti->ti_width; 329579697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 329679697Snon { 329779697Snon ti->ti_setup_msg_done |= 329879697Snon (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE); 329979697Snon } 330079697Snon 330179697Snon /* inform data */ 330279697Snon if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0) 330379697Snon { 330479697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 330579697Snon struct slccb *cb = slp->sl_Qnexus; 330679697Snon 330779697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 330879697Snon return 0; 330979697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 331079697Snon 3311240325Sjhb device_printf(slp->sl_dev, "(%d:*): transfer width %d bits\n", 3312240325Sjhb ti->ti_id, 1 << (3 + ti->ti_width)); 331379697Snon } 331467468Snon return 0; 331567468Snon} 331667468Snon 331767468Snonstatic int 331879697Snonscsi_low_msginfunc_simple_qtag(slp) 331979697Snon struct scsi_low_softc *slp; 332067468Snon{ 332179697Snon struct targ_info *ti = slp->sl_Tnexus; 332279697Snon scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1]; 332379697Snon 332479697Snon if (slp->sl_Qnexus != NULL) 332579697Snon { 332679697Snon if (slp->sl_Qnexus->ccb_tag != etag) 332779697Snon { 332879697Snon slp->sl_error |= FATALIO; 332979697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 333079697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch"); 333179697Snon } 333279697Snon } 333379697Snon else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL) 333479697Snon { 333579697Snon#ifdef SCSI_LOW_DEBUG 333679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id)) 333779697Snon return 0; 333879697Snon#endif /* SCSI_LOW_DEBUG */ 333979697Snon 334079697Snon slp->sl_error |= FATALIO; 334179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0); 334279697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found"); 334379697Snon } 334479697Snon return 0; 334579697Snon} 334679697Snon 334779697Snonstatic int 334879697Snonscsi_low_msginfunc_i_wide_residue(slp) 334979697Snon struct scsi_low_softc *slp; 335079697Snon{ 335179697Snon struct targ_info *ti = slp->sl_Tnexus; 335279697Snon struct slccb *cb = slp->sl_Qnexus; 335379697Snon int res = (int) ti->ti_msgin[1]; 335479697Snon 335579697Snon if (cb == NULL || res <= 0 || 335679697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) || 335779697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3)) 335879697Snon return EINVAL; 335979697Snon 336079697Snon if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen) 336179697Snon return EINVAL; 336279697Snon 336379697Snon slp->sl_scp.scp_datalen += res; 336479697Snon slp->sl_scp.scp_data -= res; 336579697Snon scsi_low_data_finish(slp); 336679697Snon return 0; 336779697Snon} 336879697Snon 336979697Snonstatic int 337079697Snonscsi_low_msginfunc_ext(slp) 337179697Snon struct scsi_low_softc *slp; 337279697Snon{ 337379697Snon struct slccb *cb = slp->sl_Qnexus; 337479697Snon struct lun_info *li = slp->sl_Lnexus; 337579697Snon struct targ_info *ti = slp->sl_Tnexus; 337667468Snon int count, retry; 337767468Snon u_int32_t *ptr; 337867468Snon 337967468Snon if (ti->ti_msginptr == 2) 338067468Snon { 338167468Snon ti->ti_msginlen = ti->ti_msgin[1] + 2; 338267468Snon return 0; 338367468Snon } 338467468Snon 338567468Snon switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) 338667468Snon { 338767468Snon case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): 338867468Snon if (cb == NULL) 338967468Snon break; 339067468Snon 339167468Snon ptr = (u_int32_t *)(&ti->ti_msgin[3]); 339267468Snon count = (int) htonl((long) (*ptr)); 339367468Snon if(slp->sl_scp.scp_datalen - count < 0 || 339467468Snon slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) 339567468Snon break; 339667468Snon 339767468Snon slp->sl_scp.scp_datalen -= count; 339867468Snon slp->sl_scp.scp_data += count; 339967468Snon return 0; 340067468Snon 340167468Snon case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): 340267468Snon if (li == NULL) 340367468Snon break; 340467468Snon 340579697Snon retry = scsi_low_synch(slp); 340667468Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) 340767468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 340879697Snon 340979697Snon#ifdef SCSI_LOW_DEBUG 341079697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 341179697Snon { 341279697Snon scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH); 341379697Snon } 341479697Snon#endif /* SCSI_LOW_DEBUG */ 341567468Snon return 0; 341667468Snon 341767468Snon case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): 341867468Snon if (li == NULL) 341967468Snon break; 342067468Snon 342179697Snon retry = scsi_low_wide(slp); 342279697Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0) 342379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 342479697Snon 342567468Snon return 0; 342667468Snon 342767468Snon default: 342867468Snon break; 342967468Snon } 343067468Snon 343167468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 343267468Snon return EINVAL; 343367468Snon} 343467468Snon 343567468Snonstatic int 343679697Snonscsi_low_msginfunc_parity(slp) 343779697Snon struct scsi_low_softc *slp; 343867468Snon{ 343979697Snon struct targ_info *ti = slp->sl_Tnexus; 344067468Snon 344179697Snon /* only I -> T, invalid! */ 344279697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 344367468Snon return 0; 344467468Snon} 344567468Snon 344667468Snonstatic int 344779697Snonscsi_low_msginfunc_msg_reject(slp) 344879697Snon struct scsi_low_softc *slp; 344967468Snon{ 345079697Snon struct targ_info *ti = slp->sl_Tnexus; 345167468Snon struct scsi_low_msgout_data *mdp; 345267468Snon u_int msgflags; 345367468Snon 345479697Snon if (ti->ti_emsgflags != 0) 345567468Snon { 3456240325Sjhb device_printf(slp->sl_dev, "msg flags [0x%x] rejected\n", 3457240325Sjhb ti->ti_emsgflags); 345867468Snon msgflags = SCSI_LOW_MSG_REJECT; 345967468Snon mdp = &scsi_low_msgout_data[0]; 346067468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 346167468Snon { 346267468Snon if ((ti->ti_emsgflags & mdp->md_flags) != 0) 346367468Snon { 346467468Snon ti->ti_emsgflags &= ~mdp->md_flags; 346567468Snon if (mdp->md_errfunc != NULL) 346679697Snon (*mdp->md_errfunc) (slp, msgflags); 346767468Snon break; 346867468Snon } 346967468Snon } 347079697Snon return 0; 347167468Snon } 347279697Snon else 347379697Snon { 347479697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found"); 347579697Snon slp->sl_error |= MSGERR; 347679697Snon } 347779697Snon return EINVAL; 347867468Snon} 347967468Snon 348079697Snonint 348167468Snonscsi_low_msgin(slp, ti, c) 348267468Snon struct scsi_low_softc *slp; 348367468Snon struct targ_info *ti; 348479697Snon u_int c; 348567468Snon{ 348667468Snon struct scsi_low_msgin_data *sdp; 348767468Snon struct lun_info *li; 348867468Snon u_int8_t msg; 348967468Snon 349079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 349179697Snon if (ti != slp->sl_Tnexus) 349279697Snon { 349379697Snon scsi_low_print(slp, NULL); 349479697Snon panic("scsi_low_msgin: Target nexus inconsistent"); 349579697Snon } 349679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 349779697Snon 349867468Snon /* 349967468Snon * Phase changes, clear the pointer. 350067468Snon */ 350167468Snon if (ti->ti_ophase != ti->ti_phase) 350267468Snon { 350367468Snon MSGINPTR_CLR(ti); 350479697Snon ti->ti_msgin_parity_error = 0; 350579697Snon 350679697Snon slp->sl_ph_count ++; 350779697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 350879697Snon { 3509240325Sjhb device_printf(slp->sl_dev, "too many phase changes\n"); 351079697Snon slp->sl_error |= FATALIO; 351179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 351279697Snon } 351367468Snon } 351467468Snon 351567468Snon /* 351667468Snon * Store a current messages byte into buffer and 351767468Snon * wait for the completion of the current msg. 351867468Snon */ 351979697Snon ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c; 352067468Snon if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) 352167468Snon { 352267468Snon ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; 352367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 352467468Snon } 352567468Snon 352667468Snon /* 352779697Snon * Check parity errors. 352879697Snon */ 352979697Snon if ((c & SCSI_LOW_DATA_PE) != 0) 353079697Snon { 353179697Snon ti->ti_msgin_parity_error ++; 353279697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); 353379697Snon goto out; 353479697Snon } 353579697Snon 353679697Snon if (ti->ti_msgin_parity_error != 0) 353779697Snon goto out; 353879697Snon 353979697Snon /* 354067468Snon * Calculate messages length. 354167468Snon */ 354267468Snon msg = ti->ti_msgin[0]; 354367468Snon if (msg < MSGIN_DATA_LAST) 354467468Snon sdp = &scsi_low_msgin_data[msg]; 354567468Snon else 354667468Snon sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; 354767468Snon 354867468Snon if (ti->ti_msginlen == 0) 354967468Snon { 355067468Snon ti->ti_msginlen = sdp->md_len; 355167468Snon } 355267468Snon 355367468Snon /* 355467468Snon * Check comletion. 355567468Snon */ 355667468Snon if (ti->ti_msginptr < ti->ti_msginlen) 355779697Snon return EJUSTRETURN; 355867468Snon 355967468Snon /* 356067468Snon * Do process. 356167468Snon */ 356267468Snon if ((msg & MSG_IDENTIFY) == 0) 356367468Snon { 356479697Snon if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN) 356579697Snon return EJUSTRETURN; 356667468Snon } 356767468Snon else 356867468Snon { 356979697Snon li = slp->sl_Lnexus; 357067468Snon if (li == NULL) 357167468Snon { 357279697Snon li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0); 357367468Snon if (li == NULL) 357467468Snon goto badlun; 357579697Snon slp->sl_Lnexus = li; 357679697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 357767468Snon } 357879697Snon else 357979697Snon { 358079697Snon if (MSGCMD_LUN(msg) != li->li_lun) 358179697Snon goto badlun; 358279697Snon } 358367468Snon 358479697Snon if (slp->sl_Qnexus == NULL && li->li_nqio == 0) 358567468Snon { 358667468Snon if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) 358779697Snon { 358879697Snon#ifdef SCSI_LOW_DEBUG 358979697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 359079697Snon { 359179697Snon goto out; 359279697Snon } 359379697Snon#endif /* SCSI_LOW_DEBUG */ 359467468Snon goto badlun; 359579697Snon } 359667468Snon } 359767468Snon } 359879697Snon goto out; 359967468Snon 360067468Snon /* 360179697Snon * Msg process completed, reset msgin pointer and assert ATN if desired. 360267468Snon */ 360379697Snonbadlun: 360479697Snon slp->sl_error |= FATALIO; 360579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 360679697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong"); 360779697Snon 360879697Snonout: 360979697Snon if (ti->ti_msginptr < ti->ti_msginlen) 361079697Snon return EJUSTRETURN; 361179697Snon 361279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 361379697Snon scsi_low_msg_log_write(&ti->ti_log_msgin, 361479697Snon &ti->ti_msgin[0], ti->ti_msginlen); 361579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 361679697Snon 361779697Snon MSGINPTR_CLR(ti); 361879697Snon return 0; 361979697Snon} 362079697Snon 362179697Snon/********************************************************** 362279697Snon * disconnect 362379697Snon **********************************************************/ 362479697Snonint 362579697Snonscsi_low_disconnected(slp, ti) 362679697Snon struct scsi_low_softc *slp; 362779697Snon struct targ_info *ti; 362879697Snon{ 362979697Snon struct slccb *cb = slp->sl_Qnexus; 363079697Snon 363179697Snon /* check phase completion */ 363279697Snon switch (slp->sl_msgphase) 363367468Snon { 363479697Snon case MSGPH_RESET: 363579697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 363679697Snon scsi_low_msginfunc_cc(slp); 363779697Snon scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0); 363879697Snon goto io_resume; 363967468Snon 364079697Snon case MSGPH_ABORT: 364179697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 364279697Snon scsi_low_msginfunc_cc(slp); 364379697Snon scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0); 364479697Snon goto io_resume; 364579697Snon 364679697Snon case MSGPH_TERM: 364779697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 364879697Snon scsi_low_msginfunc_cc(slp); 364979697Snon goto io_resume; 365079697Snon 365179697Snon case MSGPH_DISC: 365279697Snon if (cb != NULL) 365367468Snon { 365479697Snon struct lun_info *li; 365579697Snon 365679697Snon li = cb->li; 365779697Snon TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain); 365879697Snon cb->ccb_flags |= CCB_DISCQ; 365979697Snon cb->ccb_error |= slp->sl_error; 366079697Snon li->li_disc ++; 366179697Snon ti->ti_disc ++; 366279697Snon slp->sl_disc ++; 366379697Snon } 366479697Snon 366579697Snon#ifdef SCSI_LOW_STATICS 366679697Snon scsi_low_statics.nexus_disconnected ++; 366779697Snon#endif /* SCSI_LOW_STATICS */ 366879697Snon 366979697Snon#ifdef SCSI_LOW_DEBUG 367079697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0) 367179697Snon { 367279697Snon printf("## SCSI_LOW_DISCONNECTED ===============\n"); 367379697Snon scsi_low_print(slp, NULL); 367479697Snon } 367579697Snon#endif /* SCSI_LOW_DEBUG */ 367679697Snon break; 367779697Snon 367879697Snon case MSGPH_NULL: 367979697Snon slp->sl_error |= FATALIO; 368079697Snon if (ti->ti_phase == PH_SELSTART) 368179697Snon slp->sl_error |= SELTIMEOUTIO; 368279697Snon else 368379697Snon slp->sl_error |= UBFERR; 368479697Snon /* fall through */ 368579697Snon 368679697Snon case MSGPH_LCTERM: 368779697Snon case MSGPH_CMDC: 368879697Snonio_resume: 368979697Snon if (cb == NULL) 369079697Snon break; 369179697Snon 369279697Snon#ifdef SCSI_LOW_DEBUG 369379697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 369479697Snon { 369579697Snon if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP && 369679697Snon (cb->ccb_msgoutflag != 0 || 369779697Snon (ti->ti_msgflags & SCSI_LOW_MSG_NOOP))) 369879697Snon { 369979697Snon scsi_low_info(slp, ti, "ATTEN CHECK FAILED"); 370079697Snon } 370179697Snon } 370279697Snon#endif /* SCSI_LOW_DEBUG */ 370379697Snon 370479697Snon cb->ccb_error |= slp->sl_error; 370579697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 370679697Snon { 370779697Snon cb->ccb_flags |= CCB_STARTQ; 370879697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 370979697Snon } 371079697Snon break; 371179697Snon } 371279697Snon 371379697Snon scsi_low_bus_release(slp, ti); 371479697Snon scsi_low_start(slp); 371579697Snon return 1; 371679697Snon} 371779697Snon 371879697Snon/********************************************************** 371979697Snon * TAG operations 372079697Snon **********************************************************/ 3721104094Sphkstatic int 372279697Snonscsi_low_alloc_qtag(cb) 372379697Snon struct slccb *cb; 372479697Snon{ 372579697Snon struct lun_info *li = cb->li; 372679697Snon scsi_low_tag_t etag; 372779697Snon 372879697Snon if (cb->ccb_otag != SCSI_LOW_UNKTAG) 372979697Snon return 0; 373079697Snon 373179697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 373279697Snon etag = ffs(li->li_qtagbits); 373379697Snon if (etag == 0) 373479697Snon return ENOSPC; 373579697Snon 373679697Snon li->li_qtagbits &= ~(1 << (etag - 1)); 373779697Snon cb->ccb_otag = etag; 373879697Snon return 0; 373979697Snon 374079697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 374179697Snon for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++) 374279697Snon if (li->li_qtagarray[li->li_qd] == 0) 374379697Snon goto found; 374479697Snon 374579697Snon for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++) 374679697Snon if (li->li_qtagarray[li->li_qd] == 0) 374779697Snon goto found; 374879697Snon 374979697Snon return ENOSPC; 375079697Snon 375179697Snonfound: 375279697Snon li->li_qtagarray[li->li_qd] ++; 375379697Snon cb->ccb_otag = (li->li_qd ++); 375479697Snon return 0; 375579697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 375679697Snon} 375779697Snon 3758104094Sphkstatic int 375979697Snonscsi_low_dealloc_qtag(cb) 376079697Snon struct slccb *cb; 376179697Snon{ 376279697Snon struct lun_info *li = cb->li; 376379697Snon scsi_low_tag_t etag; 376479697Snon 376579697Snon if (cb->ccb_otag == SCSI_LOW_UNKTAG) 376679697Snon return 0; 376779697Snon 376879697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 376979697Snon etag = cb->ccb_otag - 1; 377067468Snon#ifdef SCSI_LOW_DIAGNOSTIC 377179697Snon if (etag >= sizeof(li->li_qtagbits) * NBBY) 377279697Snon panic("scsi_low_dealloc_tag: illegal tag"); 377367468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 377479697Snon li->li_qtagbits |= (1 << etag); 377579697Snon 377679697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 377779697Snon etag = cb->ccb_otag; 377879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 377979697Snon if (etag >= SCSI_LOW_MAXNEXUS) 378079697Snon panic("scsi_low_dealloc_tag: illegal tag"); 378179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 378279697Snon li->li_qtagarray[etag] --; 378379697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 378479697Snon 378579697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 378679697Snon return 0; 378779697Snon} 378879697Snon 3789104094Sphkstatic struct slccb * 379079697Snonscsi_low_revoke_ccb(slp, cb, fdone) 379179697Snon struct scsi_low_softc *slp; 379279697Snon struct slccb *cb; 379379697Snon int fdone; 379479697Snon{ 379579697Snon struct targ_info *ti = cb->ti; 379679697Snon struct lun_info *li = cb->li; 379779697Snon 379879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 379979697Snon if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) == 380079697Snon (CCB_STARTQ | CCB_DISCQ)) 380179697Snon { 3802240325Sjhb panic("%s: ccb in both queue", 3803240325Sjhb device_get_nameunit(slp->sl_dev)); 380467468Snon } 380579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 380667468Snon 380779697Snon if ((cb->ccb_flags & CCB_STARTQ) != 0) 380879697Snon { 380979697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 381079697Snon } 381179697Snon 381279697Snon if ((cb->ccb_flags & CCB_DISCQ) != 0) 381379697Snon { 381479697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 381579697Snon li->li_disc --; 381679697Snon ti->ti_disc --; 381779697Snon slp->sl_disc --; 381879697Snon } 381979697Snon 382079697Snon cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ | 382179697Snon CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL); 382279697Snon 382379697Snon if (fdone != 0 && 382479697Snon (cb->ccb_rcnt ++ >= slp->sl_max_retry || 382579697Snon (cb->ccb_flags & CCB_NORETRY) != 0)) 382679697Snon { 382779697Snon cb->ccb_error |= FATALIO; 382879697Snon cb->ccb_flags &= ~CCB_AUTOSENSE; 382979697Snon if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE) 3830240325Sjhb panic("%s: done ccb retried", 3831240325Sjhb device_get_nameunit(slp->sl_dev)); 383279697Snon return NULL; 383379697Snon } 383479697Snon else 383579697Snon { 383679697Snon cb->ccb_error |= PENDINGIO; 383779697Snon scsi_low_deactivate_qtag(cb); 383879697Snon scsi_low_ccb_message_retry(cb); 383979697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 384079697Snon return cb; 384179697Snon } 384267468Snon} 384367468Snon 3844104094Sphkstatic void 384579697Snonscsi_low_reset_nexus_lun(slp, li, fdone) 384679697Snon struct scsi_low_softc *slp; 384779697Snon struct lun_info *li; 384879697Snon int fdone; 384979697Snon{ 385079697Snon struct slccb *cb, *ncb, *ecb; 385179697Snon 385279697Snon if (li == NULL) 385379697Snon return; 385479697Snon 385579697Snon ecb = NULL; 385679697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb) 385779697Snon { 385879697Snon ncb = TAILQ_NEXT(cb, ccb_chain); 385979697Snon cb = scsi_low_revoke_ccb(slp, cb, fdone); 386079697Snon if (cb != NULL) 386179697Snon { 386279697Snon /* 386379697Snon * presumely keep ordering of io 386479697Snon */ 386579697Snon cb->ccb_flags |= CCB_STARTQ; 386679697Snon if (ecb == NULL) 386779697Snon { 386879697Snon TAILQ_INSERT_HEAD(&slp->sl_start,\ 386979697Snon cb, ccb_chain); 387079697Snon } 387179697Snon else 387279697Snon { 387379697Snon TAILQ_INSERT_AFTER(&slp->sl_start,\ 387479697Snon ecb, cb, ccb_chain); 387579697Snon } 387679697Snon ecb = cb; 387779697Snon } 387879697Snon } 387979697Snon} 388079697Snon 388167468Snon/************************************************************** 388267468Snon * Qurik setup 388367468Snon **************************************************************/ 388467468Snonstatic void 388579697Snonscsi_low_calcf_lun(li) 388667468Snon struct lun_info *li; 388767468Snon{ 388879697Snon struct targ_info *ti = li->li_ti; 388967468Snon struct scsi_low_softc *slp = ti->ti_sc; 389079697Snon u_int cfgflags, diskflags; 389167468Snon 389279697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID) 389379697Snon cfgflags = li->li_cfgflags; 389479697Snon else 389579697Snon cfgflags = 0; 389679697Snon 389779697Snon diskflags = li->li_diskflags & li->li_quirks; 389879697Snon 389979697Snon /* disconnect */ 390067468Snon li->li_flags &= ~SCSI_LOW_DISC; 390167468Snon if ((slp->sl_cfgflags & CFG_NODISC) == 0 && 390279697Snon (diskflags & SCSI_LOW_DISK_DISC) != 0 && 390379697Snon (cfgflags & SCSI_LOW_DISC) != 0) 390467468Snon li->li_flags |= SCSI_LOW_DISC; 390567468Snon 390679697Snon /* parity */ 390767468Snon li->li_flags |= SCSI_LOW_NOPARITY; 390867468Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && 390979697Snon (diskflags & SCSI_LOW_DISK_PARITY) != 0 && 391079697Snon (cfgflags & SCSI_LOW_NOPARITY) == 0) 391167468Snon li->li_flags &= ~SCSI_LOW_NOPARITY; 391267468Snon 391379697Snon /* qtag */ 391479697Snon if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 && 391579697Snon (cfgflags & SCSI_LOW_QTAG) != 0 && 391679697Snon (diskflags & SCSI_LOW_DISK_QTAG) != 0) 391779697Snon { 391879697Snon li->li_flags |= SCSI_LOW_QTAG; 391979697Snon li->li_maxnexus = SCSI_LOW_MAXNEXUS; 392079697Snon li->li_maxnqio = li->li_maxnexus; 392179697Snon } 392279697Snon else 392379697Snon { 392479697Snon li->li_flags &= ~SCSI_LOW_QTAG; 392579697Snon li->li_maxnexus = 0; 392679697Snon li->li_maxnqio = li->li_maxnexus; 392779697Snon } 392879697Snon 392979697Snon /* cmd link */ 393079697Snon li->li_flags &= ~SCSI_LOW_LINK; 393179697Snon if ((cfgflags & SCSI_LOW_LINK) != 0 && 393279697Snon (diskflags & SCSI_LOW_DISK_LINK) != 0) 393379697Snon li->li_flags |= SCSI_LOW_LINK; 393479697Snon 393579697Snon /* compatible flags */ 393667468Snon li->li_flags &= ~SCSI_LOW_SYNC; 393779697Snon if (ti->ti_maxsynch.offset > 0) 393879697Snon li->li_flags |= SCSI_LOW_SYNC; 393979697Snon 394079697Snon#ifdef SCSI_LOW_DEBUG 394179697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 394267468Snon { 394379697Snon scsi_low_calcf_show(li); 394467468Snon } 394579697Snon#endif /* SCSI_LOW_DEBUG */ 394679697Snon} 394779697Snon 394879697Snonstatic void 394979697Snonscsi_low_calcf_target(ti) 395079697Snon struct targ_info *ti; 395179697Snon{ 395279697Snon struct scsi_low_softc *slp = ti->ti_sc; 395379697Snon u_int offset, period, diskflags; 395479697Snon 395579697Snon diskflags = ti->ti_diskflags & ti->ti_quirks; 395679697Snon 395779697Snon /* synch */ 395879697Snon if ((slp->sl_cfgflags & CFG_ASYNC) == 0 && 395979697Snon (diskflags & SCSI_LOW_DISK_SYNC) != 0) 396079697Snon { 396179697Snon offset = ti->ti_maxsynch.offset; 396279697Snon period = ti->ti_maxsynch.period; 396379697Snon if (offset == 0 || period == 0) 396479697Snon offset = period = 0; 396579697Snon } 396667468Snon else 396779697Snon { 396879697Snon offset = period = 0; 396979697Snon } 397067468Snon 397179697Snon ti->ti_maxsynch.offset = offset; 397279697Snon ti->ti_maxsynch.period = period; 397379697Snon 397479697Snon /* wide */ 397579697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 && 397679697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 397779697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_16; 397879697Snon 397979697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 && 398079697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 398179697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 398279697Snon 398379697Snon if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID) 398467468Snon { 398579697Snon if (ti->ti_maxsynch.offset != ti->ti_osynch.offset || 398679697Snon ti->ti_maxsynch.period != ti->ti_osynch.period) 398779697Snon ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH; 398879697Snon if (ti->ti_width != ti->ti_owidth) 398979697Snon ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH); 399079697Snon 399179697Snon ti->ti_osynch = ti->ti_maxsynch; 399279697Snon ti->ti_owidth = ti->ti_width; 399367468Snon } 399467468Snon 399579697Snon#ifdef SCSI_LOW_DEBUG 399679697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 399779697Snon { 3998240325Sjhb device_printf(slp->sl_dev, 3999240325Sjhb "(%d:*): max period(%dns) offset(%d) width(%d)\n", 4000240325Sjhb ti->ti_id, 400179697Snon ti->ti_maxsynch.period * 4, 400279697Snon ti->ti_maxsynch.offset, 400379697Snon ti->ti_width); 400479697Snon } 400579697Snon#endif /* SCSI_LOW_DEBUG */ 400667468Snon} 400767468Snon 400879697Snonstatic void 400979697Snonscsi_low_calcf_show(li) 401079697Snon struct lun_info *li; 401179697Snon{ 401279697Snon struct targ_info *ti = li->li_ti; 401379697Snon struct scsi_low_softc *slp = ti->ti_sc; 401479697Snon 4015240325Sjhb device_printf(slp->sl_dev, 4016240325Sjhb "(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n", 4017240325Sjhb ti->ti_id, li->li_lun, 401879697Snon ti->ti_maxsynch.period * 4, 401979697Snon ti->ti_maxsynch.offset, 402079697Snon ti->ti_width, 402179697Snon li->li_flags, SCSI_LOW_BITS); 402279697Snon} 402379697Snon 402479697Snon#ifdef SCSI_LOW_START_UP_CHECK 402579697Snon/************************************************************** 402679697Snon * scsi world start up 402779697Snon **************************************************************/ 402892770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *); 402979697Snon 403067468Snonstatic int 403179697Snonscsi_low_start_up(slp) 403279697Snon struct scsi_low_softc *slp; 403367468Snon{ 403467468Snon struct targ_info *ti; 403567468Snon struct lun_info *li; 403679697Snon struct slccb *cb; 403779697Snon int target, lun; 403867468Snon 4039240325Sjhb device_printf(slp->sl_dev, "scsi_low: probing all devices ....\n"); 404067468Snon 404179697Snon for (target = 0; target < slp->sl_ntargs; target ++) 404279697Snon { 404379697Snon if (target == slp->sl_hostid) 404479697Snon { 404579697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 404679697Snon { 4047240325Sjhb device_printf(slp->sl_dev, 4048240325Sjhb "scsi_low: target %d (host card)\n", 4049240325Sjhb target); 405079697Snon } 405179697Snon continue; 405279697Snon } 405367468Snon 405479697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 405579697Snon { 4056240325Sjhb device_printf(slp->sl_dev, "scsi_low: target %d lun ", 4057240325Sjhb target); 405879697Snon } 405967468Snon 406079697Snon ti = slp->sl_ti[target]; 406179697Snon for (lun = 0; lun < slp->sl_nluns; lun ++) 406279697Snon { 406379697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 406479697Snon break; 406579697Snon 406679697Snon cb->osdep = NULL; 406779697Snon cb->bp = NULL; 406879697Snon 406979697Snon li = scsi_low_alloc_li(ti, lun, 1); 407079697Snon 407179697Snon scsi_low_enqueue(slp, ti, li, cb, 407279697Snon CCB_AUTOSENSE | CCB_POLLED, 0); 407379697Snon 407479697Snon scsi_low_poll(slp, cb); 407579697Snon 407679697Snon if (li->li_state != SCSI_LOW_LUN_OK) 407779697Snon break; 407879697Snon 407979697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 408079697Snon { 408179697Snon printf("%d ", lun); 408279697Snon } 408379697Snon } 408479697Snon 408579697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 408679697Snon { 408779697Snon printf("\n"); 408879697Snon } 408979697Snon } 409067468Snon return 0; 409167468Snon} 409267468Snon 409379697Snonstatic int 409479697Snonscsi_low_poll(slp, cb) 409579697Snon struct scsi_low_softc *slp; 409679697Snon struct slccb *cb; 409779697Snon{ 409879697Snon int tcount; 409979697Snon 410079697Snon tcount = 0; 410179697Snon while (slp->sl_nio > 0) 410279697Snon { 4103240172Sjhb DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ); 410479697Snon 410579697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 410679697Snon if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 410779697Snon continue; 410879697Snon 410979697Snon tcount = 0; 411079697Snon scsi_low_timeout_check(slp); 411179697Snon } 411279697Snon 411379697Snon return 0; 411479697Snon} 411579697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 411679697Snon 411767468Snon/********************************************************** 411867468Snon * DEBUG SECTION 411967468Snon **********************************************************/ 412079697Snon#ifdef SCSI_LOW_DEBUG 412167468Snonstatic void 412279697Snonscsi_low_test_abort(slp, ti, li) 412379697Snon struct scsi_low_softc *slp; 412479697Snon struct targ_info *ti; 412579697Snon struct lun_info *li; 412679697Snon{ 412779697Snon struct slccb *acb; 412879697Snon 412979697Snon if (li->li_disc > 1) 413079697Snon { 413179697Snon acb = TAILQ_FIRST(&li->li_discq); 413279697Snon if (scsi_low_abort_ccb(slp, acb) == 0) 413379697Snon { 4134240325Sjhb device_printf(slp->sl_dev, 4135240325Sjhb "aborting ccb(0x%lx) start\n", (u_long) acb); 413679697Snon } 413779697Snon } 413879697Snon} 413979697Snon 414079697Snonstatic void 414179697Snonscsi_low_test_atten(slp, ti, msg) 414279697Snon struct scsi_low_softc *slp; 414379697Snon struct targ_info *ti; 414479697Snon u_int msg; 414579697Snon{ 414679697Snon 414779697Snon if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK) 414879697Snon scsi_low_assert_msg(slp, ti, msg, 0); 414979697Snon else 4150240325Sjhb device_printf(slp->sl_dev, "atten check OK\n"); 415179697Snon} 415279697Snon 415379697Snonstatic void 415479697Snonscsi_low_test_cmdlnk(slp, cb) 415579697Snon struct scsi_low_softc *slp; 415679697Snon struct slccb *cb; 415779697Snon{ 415879697Snon#define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ) 415979697Snon 416079697Snon if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0) 416179697Snon return; 416279697Snon 416379697Snon memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd, 416479697Snon slp->sl_scp.scp_cmdlen); 416579697Snon cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1; 416679697Snon slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd; 416779697Snon} 416879697Snon#endif /* SCSI_LOW_DEBUG */ 416979697Snon 417079697Snon/* static */ void 417167468Snonscsi_low_info(slp, ti, s) 417267468Snon struct scsi_low_softc *slp; 417367468Snon struct targ_info *ti; 417467468Snon u_char *s; 417567468Snon{ 417667468Snon 417779697Snon if (slp == NULL) 417879697Snon slp = LIST_FIRST(&sl_tab); 417979697Snon if (s == NULL) 418079697Snon s = "no message"; 418179697Snon 418279697Snon printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s); 418367468Snon if (ti == NULL) 418467468Snon { 4185288693Smav TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain) 418679697Snon { 418767468Snon scsi_low_print(slp, ti); 418879697Snon } 418967468Snon } 419067468Snon else 419179697Snon { 419267468Snon scsi_low_print(slp, ti); 419379697Snon } 419467468Snon} 419567468Snon 419667468Snonstatic u_char *phase[] = 419767468Snon{ 419867468Snon "FREE", "ARBSTART", "SELSTART", "SELECTED", 419967468Snon "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" 420067468Snon}; 420167468Snon 420267468Snonvoid 420367468Snonscsi_low_print(slp, ti) 420467468Snon struct scsi_low_softc *slp; 420567468Snon struct targ_info *ti; 420667468Snon{ 420779697Snon struct lun_info *li; 420879697Snon struct slccb *cb; 420979697Snon struct sc_p *sp; 421067468Snon 421179697Snon if (ti == NULL || ti == slp->sl_Tnexus) 421279697Snon { 421379697Snon ti = slp->sl_Tnexus; 421479697Snon li = slp->sl_Lnexus; 421579697Snon cb = slp->sl_Qnexus; 421679697Snon } 421779697Snon else 421879697Snon { 421979697Snon li = LIST_FIRST(&ti->ti_litab); 422079697Snon cb = TAILQ_FIRST(&li->li_discq); 422179697Snon } 422279697Snon sp = &slp->sl_scp; 422367468Snon 4224240325Sjhb device_printf(slp->sl_dev, 4225240325Sjhb "=== NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n", 4226240325Sjhb (u_long) ti, (u_long) li, (u_long) cb, slp->sl_nio); 422767468Snon 422867468Snon /* target stat */ 422967468Snon if (ti != NULL) 423067468Snon { 423179697Snon u_int flags = 0, maxnqio = 0, nqio = 0; 4232265632Smav int lun = CAM_LUN_WILDCARD; 423367468Snon 423467468Snon if (li != NULL) 423567468Snon { 423667468Snon lun = li->li_lun; 423767468Snon flags = li->li_flags; 423879697Snon maxnqio = li->li_maxnqio; 423979697Snon nqio = li->li_nqio; 424067468Snon } 424167468Snon 4242240325Sjhb device_printf(slp->sl_dev, 4243240325Sjhb "(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n", 424467468Snon ti->ti_id, lun, phase[(int) ti->ti_ophase], 424579697Snon phase[(int) ti->ti_phase], ti->ti_disc, 424679697Snon nqio, maxnqio); 424767468Snon 424879697Snon if (cb != NULL) 424979697Snon { 425079697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n", 425179697Snon (u_int) cb->ccb_scp.scp_cmd[0], 425279697Snon cb->ccb_scp.scp_cmdlen, 425379697Snon cb->ccb_datalen, 425479697Snon cb->ccb_scp.scp_datalen, 425579697Snon (u_int) cb->ccb_sscp.scp_status, 425679697Snon cb->ccb_error, SCSI_LOW_ERRORBITS); 425779697Snon } 425867468Snon 425979697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n", 426079697Snon (u_int) (ti->ti_msginptr), 426179697Snon (u_int) (ti->ti_msgin[0]), 426279697Snon (u_int) (ti->ti_msgin[1]), 426379697Snon (u_int) (ti->ti_msgin[2]), 426479697Snon (u_int) (ti->ti_msgin[3]), 426579697Snon (u_int) (ti->ti_msgin[4]), 426679697Snon slp->sl_atten); 426779697Snon 426867468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", 426979697Snon (u_int) ti->ti_msgflags, 427079697Snon (u_int) (ti->ti_msgoutstr[0]), 427179697Snon (u_int) (ti->ti_msgoutstr[1]), 427279697Snon (u_int) (ti->ti_msgoutstr[2]), 427379697Snon (u_int) (ti->ti_msgoutstr[3]), 427479697Snon (u_int) (ti->ti_msgoutstr[4]), 427579697Snon ti->ti_msgoutlen, 427679697Snon flags, SCSI_LOW_BITS); 427767468Snon 427879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 427979697Snon scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2); 428079697Snon scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2); 428179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 428267468Snon 428367468Snon } 428479697Snon 428579697Snon printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n", 428679697Snon (u_long) sp->scp_data, 428779697Snon sp->scp_datalen, 428879697Snon (u_int) sp->scp_status, 428979697Snon slp->sl_error, SCSI_LOW_ERRORBITS); 429067468Snon} 4291