diff --git a/sys/cam/scsi/scsi_low.c b/sys/cam/scsi/scsi_low.c index 8ca669e015eb..0c91e515b277 100644 --- a/sys/cam/scsi/scsi_low.c +++ b/sys/cam/scsi/scsi_low.c @@ -1,4290 +1,4209 @@ /* $NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $ */ /* $NetBSD$ */ #include __FBSDID("$FreeBSD$"); #define SCSI_LOW_STATICS #define SCSI_LOW_DEBUG #define SCSI_LOW_NEGOTIATE_BEFORE_SENSE #define SCSI_LOW_START_UP_CHECK /* #define SCSI_LOW_INFO_DETAIL */ /* #define SCSI_LOW_QCLEAR_AFTER_CA */ /* #define SCSI_LOW_FLAGS_QUIRKS_OK */ #define SCSI_LOW_FLAGS_QUIRKS_OK /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * [Ported for FreeBSD CAM] * Copyright (c) 2000, 2001 * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * When our host is reselected, * nexus establish processes are little complicated. * Normal steps are followings: * 1) Our host selected by target => target nexus (slp->sl_Tnexus) * 2) Identify msgin => lun nexus (slp->sl_Lnexus) * 3) Qtag msg => ccb nexus (slp->sl_Qnexus) */ #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /************************************************************** * Constants **************************************************************/ #define SCSI_LOW_POLL_HZ 1000 /* functions return values */ #define SCSI_LOW_START_NO_QTAG 0 #define SCSI_LOW_START_QTAG 1 #define SCSI_LOW_DONE_COMPLETE 0 #define SCSI_LOW_DONE_RETRY 1 /* internal disk flags */ #define SCSI_LOW_DISK_DISC 0x00000001 #define SCSI_LOW_DISK_QTAG 0x00000002 #define SCSI_LOW_DISK_LINK 0x00000004 #define SCSI_LOW_DISK_PARITY 0x00000008 #define SCSI_LOW_DISK_SYNC 0x00010000 #define SCSI_LOW_DISK_WIDE_16 0x00020000 #define SCSI_LOW_DISK_WIDE_32 0x00040000 #define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32) #define SCSI_LOW_DISK_LFLAGS 0x0000ffff #define SCSI_LOW_DISK_TFLAGS 0xffff0000 static MALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers"); /************************************************************** * Declarations **************************************************************/ /* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *); static void scsi_low_engage(void *); static struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t); static int scsi_low_done(struct scsi_low_softc *, struct slccb *); static int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *); static void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *); static void scsi_low_twiddle_wait(void); static struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int); static struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int); static void scsi_low_calcf_lun(struct lun_info *); static void scsi_low_calcf_target(struct targ_info *); static void scsi_low_calcf_show(struct lun_info *); static void scsi_low_reset_nexus(struct scsi_low_softc *, int); static void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int); static void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int); static int scsi_low_init(struct scsi_low_softc *, u_int); static void scsi_low_start(struct scsi_low_softc *); static void scsi_low_free_ti(struct scsi_low_softc *); static int scsi_low_alloc_qtag(struct slccb *); static int scsi_low_dealloc_qtag(struct slccb *); static int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int); static int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int); static void scsi_low_unit_ready_cmd(struct slccb *); static void scsi_low_timeout(void *); static int scsi_low_timeout_check(struct scsi_low_softc *); #ifdef SCSI_LOW_START_UP_CHECK static int scsi_low_start_up(struct scsi_low_softc *); #endif /* SCSI_LOW_START_UP_CHECK */ static int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *); static struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int); int scsi_low_version_major = 2; int scsi_low_version_minor = 17; static struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab); +static struct mtx sl_tab_lock; +MTX_SYSINIT(sl_tab_lock, &sl_tab_lock, "scsi low table", MTX_DEF); /************************************************************** * Debug, Run test and Statics **************************************************************/ #ifdef SCSI_LOW_INFO_DETAIL #define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s)) #else /* !SCSI_LOW_INFO_DETAIL */ #define SCSI_LOW_INFO(slp, ti, s) device_printf((slp)->sl_dev, "%s\n", (s)) #endif /* !SCSI_LOW_INFO_DETAIL */ #ifdef SCSI_LOW_STATICS static struct scsi_low_statics { int nexus_win; int nexus_fail; int nexus_disconnected; int nexus_reselected; int nexus_conflict; } scsi_low_statics; #endif /* SCSI_LOW_STATICS */ #ifdef SCSI_LOW_DEBUG #define SCSI_LOW_DEBUG_DONE 0x00001 #define SCSI_LOW_DEBUG_DISC 0x00002 #define SCSI_LOW_DEBUG_SENSE 0x00004 #define SCSI_LOW_DEBUG_CALCF 0x00008 #define SCSI_LOW_DEBUG_ACTION 0x10000 int scsi_low_debug = 0; #define SCSI_LOW_MAX_ATTEN_CHECK 32 #define SCSI_LOW_ATTEN_CHECK 0x0001 #define SCSI_LOW_CMDLNK_CHECK 0x0002 #define SCSI_LOW_ABORT_CHECK 0x0004 #define SCSI_LOW_NEXUS_CHECK 0x0008 int scsi_low_test = 0; int scsi_low_test_id = 0; static void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *); static void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *); static void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int); #define SCSI_LOW_DEBUG_TEST_GO(fl, id) \ ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) #define SCSI_LOW_DEBUG_GO(fl, id) \ ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) #endif /* SCSI_LOW_DEBUG */ /************************************************************** * CCB **************************************************************/ GENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) GENERIC_CCB(scsi_low, slccb, ccb_chain) /************************************************************** * Inline functions **************************************************************/ #define SCSI_LOW_INLINE static __inline SCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *); SCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *); SCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int); SCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *); SCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *); SCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *); SCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *); SCSI_LOW_INLINE void scsi_low_activate_qtag(cb) struct slccb *cb; { struct lun_info *li = cb->li; if (cb->ccb_tag != SCSI_LOW_UNKTAG) return; li->li_nqio ++; cb->ccb_tag = cb->ccb_otag; } SCSI_LOW_INLINE void scsi_low_deactivate_qtag(cb) struct slccb *cb; { struct lun_info *li = cb->li; if (cb->ccb_tag == SCSI_LOW_UNKTAG) return; li->li_nqio --; cb->ccb_tag = SCSI_LOW_UNKTAG; } SCSI_LOW_INLINE void scsi_low_ccb_message_exec(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0); cb->ccb_msgoutflag = 0; } SCSI_LOW_INLINE void scsi_low_ccb_message_assert(cb, msg) struct slccb *cb; u_int msg; { cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg; } SCSI_LOW_INLINE void scsi_low_ccb_message_retry(cb) struct slccb *cb; { cb->ccb_msgoutflag = cb->ccb_omsgoutflag; } SCSI_LOW_INLINE void scsi_low_ccb_message_clear(cb) struct slccb *cb; { cb->ccb_msgoutflag = 0; } SCSI_LOW_INLINE void scsi_low_init_msgsys(slp, ti) struct scsi_low_softc *slp; struct targ_info *ti; { ti->ti_msginptr = 0; ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; SCSI_LOW_DEASSERT_ATN(slp); SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); } /*============================================================= * START OF OS switch (All OS depend fucntions should be here) =============================================================*/ /* common os depend utitlities */ #define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001 #define SCSI_LOW_CMD_ORDERED_QTAG 0x0002 #define SCSI_LOW_CMD_ABORT_WARNING 0x0004 static u_int8_t scsi_low_cmd_flags[256] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, /*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, /*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5, /*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, }; struct scsi_low_error_code { int error_bits; int error_code; }; static struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *); static int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *); static struct slccb * scsi_low_find_ccb(slp, target, lun, osdep) struct scsi_low_softc *slp; u_int target, lun; void *osdep; { struct targ_info *ti; struct lun_info *li; struct slccb *cb; ti = slp->sl_ti[target]; li = scsi_low_alloc_li(ti, lun, 0); if (li == NULL) return NULL; if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep) return cb; TAILQ_FOREACH(cb, &slp->sl_start, ccb_chain) { if (cb->osdep == osdep) return cb; } TAILQ_FOREACH(cb, &li->li_discq, ccb_chain) { if (cb->osdep == osdep) return cb; } return NULL; } static int scsi_low_translate_error_code(cb, tp) struct slccb *cb; struct scsi_low_error_code *tp; { if (cb->ccb_error == 0) return tp->error_code; for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++) ; return tp->error_code; } /************************************************************** * SCSI INTERFACE (CAM) **************************************************************/ #define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) #define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) #define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb() static void scsi_low_poll_cam(struct cam_sim *); void scsi_low_scsi_action_cam(struct cam_sim *, union ccb *); static int scsi_low_attach_cam(struct scsi_low_softc *); -static int scsi_low_world_start_cam(struct scsi_low_softc *); -static int scsi_low_dettach_cam(struct scsi_low_softc *); +static int scsi_low_detach_cam(struct scsi_low_softc *); static int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *); static int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *); -static void scsi_low_timeout_cam(struct scsi_low_softc *, int, int); - -struct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = { - scsi_low_attach_cam, - scsi_low_world_start_cam, - scsi_low_dettach_cam, - scsi_low_ccb_setup_cam, - scsi_low_done_cam, - scsi_low_timeout_cam -}; - + struct scsi_low_error_code scsi_low_error_code_cam[] = { {0, CAM_REQ_CMP}, {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR}, {SENSEERR, CAM_AUTOSENSE_FAIL}, {UACAERR, CAM_SCSI_STATUS_ERROR}, {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR}, {SELTIMEOUTIO, CAM_SEL_TIMEOUT}, {TIMEOUTIO, CAM_CMD_TIMEOUT}, {PDMAERR, CAM_DATA_RUN_ERR}, {PARITYERR, CAM_UNCOR_PARITY}, {UBFERR, CAM_UNEXP_BUSFREE}, {ABORTIO, CAM_REQ_ABORTED}, {-1, CAM_UNREC_HBA_ERROR} }; #define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim))) /* XXX: * Please check a polling hz, currently we assume scsi_low_poll() is * called each 1 ms. */ #define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */ static void scsi_low_poll_cam(sim) struct cam_sim *sim; { struct scsi_low_softc *slp = SIM2SLP(sim); + SCSI_LOW_ASSERT_LOCKED(slp); (*slp->sl_funcs->scsi_low_poll) (slp); - if (slp->sl_si.si_poll_count ++ >= + if (slp->sl_poll_count ++ >= SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) { - slp->sl_si.si_poll_count = 0; + slp->sl_poll_count = 0; scsi_low_timeout_check(slp); } } void scsi_low_scsi_action_cam(sim, ccb) struct cam_sim *sim; union ccb *ccb; { struct scsi_low_softc *slp = SIM2SLP(sim); struct targ_info *ti; struct lun_info *li; struct slccb *cb; u_int lun, flags, msg, target; - int s, rv; + int rv; + SCSI_LOW_ASSERT_LOCKED(slp); target = (u_int) (ccb->ccb_h.target_id); lun = (u_int) ccb->ccb_h.target_lun; #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0) { device_printf(slp->sl_dev, "cam_action: func code 0x%x target: %d, lun: %d\n", ccb->ccb_h.func_code, target, lun); } #endif /* SCSI_LOW_DEBUG */ switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: /* Execute the requested I/O operation */ #ifdef SCSI_LOW_DIAGNOSTIC if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) { device_printf(slp->sl_dev, "invalid target/lun\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } #endif /* SCSI_LOW_DIAGNOSTIC */ if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(ccb); return; } ti = slp->sl_ti[target]; cb->osdep = ccb; cb->bp = NULL; if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) flags = CCB_AUTOSENSE | CCB_SCSIIO; else flags = CCB_SCSIIO; - s = splcam(); li = scsi_low_alloc_li(ti, lun, 1); if (ti->ti_setup_msg != 0) { scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE); } scsi_low_enqueue(slp, ti, li, cb, flags, 0); #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0) { scsi_low_test_abort(slp, ti, li); } #endif /* SCSI_LOW_DEBUG */ - splx(s); break; case XPT_EN_LUN: /* Enable LUN as a target */ case XPT_TARGET_IO: /* Execute target I/O request */ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ /* XXX Implement */ ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; case XPT_ABORT: /* Abort the specified CCB */ #ifdef SCSI_LOW_DIAGNOSTIC if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) { device_printf(slp->sl_dev, "invalid target/lun\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } #endif /* SCSI_LOW_DIAGNOSTIC */ - s = splcam(); cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb); rv = scsi_low_abort_ccb(slp, cb); - splx(s); if (rv == 0) ccb->ccb_h.status = CAM_REQ_CMP; else ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; case XPT_SET_TRAN_SETTINGS: { struct ccb_trans_settings_scsi *scsi; struct ccb_trans_settings_spi *spi; struct ccb_trans_settings *cts; u_int val; #ifdef SCSI_LOW_DIAGNOSTIC if (target == CAM_TARGET_WILDCARD) { device_printf(slp->sl_dev, "invalid target\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } #endif /* SCSI_LOW_DIAGNOSTIC */ cts = &ccb->cts; ti = slp->sl_ti[target]; if (lun == CAM_LUN_WILDCARD) lun = 0; - s = splcam(); scsi = &cts->proto_specific.scsi; spi = &cts->xport_specific.spi; if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH | CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET)) != 0) { if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { val = spi->bus_width; if (val < ti->ti_width) ti->ti_width = val; } if (spi->valid & CTS_SPI_VALID_SYNC_RATE) { val = spi->sync_period; if (val == 0 || val > ti->ti_maxsynch.period) ti->ti_maxsynch.period = val; } if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { val = spi->sync_offset; if (val < ti->ti_maxsynch.offset) ti->ti_maxsynch.offset = val; } ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; scsi_low_calcf_target(ti); } if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 || (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { li = scsi_low_alloc_li(ti, lun, 1); if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) { li->li_quirks |= SCSI_LOW_DISK_DISC; } else { li->li_quirks &= ~SCSI_LOW_DISK_DISC; } if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { li->li_quirks |= SCSI_LOW_DISK_QTAG; } else { li->li_quirks &= ~SCSI_LOW_DISK_QTAG; } li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; scsi_low_calcf_target(ti); scsi_low_calcf_lun(li); if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) scsi_low_calcf_show(li); } - splx(s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts; u_int diskflags; cts = &ccb->cts; #ifdef SCSI_LOW_DIAGNOSTIC if (target == CAM_TARGET_WILDCARD) { device_printf(slp->sl_dev, "invalid target\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } #endif /* SCSI_LOW_DIAGNOSTIC */ ti = slp->sl_ti[target]; if (lun == CAM_LUN_WILDCARD) lun = 0; - s = splcam(); li = scsi_low_alloc_li(ti, lun, 1); if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) { struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; #ifdef SCSI_LOW_DIAGNOSTIC if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) { ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; device_printf(slp->sl_dev, "invalid GET_TRANS_CURRENT_SETTINGS call\n"); goto settings_out; } #endif /* SCSI_LOW_DIAGNOSTIC */ cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_2; cts->transport = XPORT_SPI; cts->transport_version = 2; scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; diskflags = li->li_diskflags & li->li_cfgflags; if (diskflags & SCSI_LOW_DISK_DISC) spi->flags |= CTS_SPI_FLAGS_DISC_ENB; if (diskflags & SCSI_LOW_DISK_QTAG) scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; spi->sync_period = ti->ti_maxsynch.period; spi->valid |= CTS_SPI_VALID_SYNC_RATE; spi->sync_offset = ti->ti_maxsynch.offset; spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; spi->valid |= CTS_SPI_VALID_BUS_WIDTH; spi->bus_width = ti->ti_width; if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { scsi->valid = CTS_SCSI_VALID_TQ; spi->valid |= CTS_SPI_VALID_DISC; } else scsi->valid = 0; } else ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; settings_out: - splx(s); xpt_done(ccb); break; } case XPT_CALC_GEOMETRY: { /* not yet HN2 */ cam_calc_geometry(&ccb->ccg, /*extended*/1); xpt_done(ccb); break; } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ - s = splcam(); scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); - splx(s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; case XPT_TERM_IO: /* Terminate the I/O process */ ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ #ifdef SCSI_LOW_DIAGNOSTIC if (target == CAM_TARGET_WILDCARD) { device_printf(slp->sl_dev, "invalid target\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } #endif /* SCSI_LOW_DIAGNOSTIC */ msg = SCSI_LOW_MSG_RESET; if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(ccb); return; } ti = slp->sl_ti[target]; if (lun == CAM_LUN_WILDCARD) lun = 0; cb->osdep = ccb; cb->bp = NULL; if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT; else flags = CCB_NORETRY | CCB_URGENT; - s = splcam(); li = scsi_low_alloc_li(ti, lun, 1); scsi_low_enqueue(slp, ti, li, cb, flags, msg); - splx(s); break; case XPT_PATH_INQ: { /* Path routing inquiry */ struct ccb_pathinq *cpi = &ccb->cpi; cpi->version_num = scsi_low_version_major; cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB; ti = slp->sl_ti[slp->sl_hostid]; /* host id */ if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) cpi->hba_inquiry |= PI_WIDE_16; if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16) cpi->hba_inquiry |= PI_WIDE_32; if (ti->ti_maxsynch.offset > 0) cpi->hba_inquiry |= PI_SDTR_ABLE; cpi->target_sprt = 0; cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = slp->sl_ntargs - 1; cpi->max_lun = slp->sl_nluns - 1; cpi->initiator_id = slp->sl_hostid; cpi->bus_id = cam_sim_bus(sim); cpi->base_transfer_speed = 3300; cpi->transport = XPORT_SPI; cpi->transport_version = 2; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_2; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } default: printf("scsi_low: non support func_code = %d ", ccb->ccb_h.func_code); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } } static int scsi_low_attach_cam(slp) struct scsi_low_softc *slp; { struct cam_devq *devq; int tagged_openings; devq = cam_simq_alloc(SCSI_LOW_NCCB); if (devq == NULL) return (ENOMEM); /* * ask the adapter what subunits are present */ tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS); - slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, + slp->sl_sim = cam_sim_alloc(scsi_low_scsi_action_cam, scsi_low_poll_cam, device_get_name(slp->sl_dev), slp, - device_get_unit(slp->sl_dev), &Giant, + device_get_unit(slp->sl_dev), &slp->sl_lock, slp->sl_openings, tagged_openings, devq); - if (slp->sl_si.sim == NULL) { + if (slp->sl_sim == NULL) { cam_simq_free(devq); return ENODEV; } - if (xpt_bus_register(slp->sl_si.sim, NULL, 0) != CAM_SUCCESS) { - free(slp->sl_si.sim, M_SCSILOW); + SCSI_LOW_LOCK(slp); + if (xpt_bus_register(slp->sl_sim, slp->sl_dev, 0) != CAM_SUCCESS) { + cam_sim_free(slp->sl_sim, TRUE); + SCSI_LOW_UNLOCK(slp); return ENODEV; } - if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL, - cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD, + if (xpt_create_path(&slp->sl_path, /*periph*/NULL, + cam_sim_path(slp->sl_sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { - xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); - cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE); + xpt_bus_deregister(cam_sim_path(slp->sl_sim)); + cam_sim_free(slp->sl_sim, /*free_simq*/TRUE); + SCSI_LOW_UNLOCK(slp); return ENODEV; } slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */ + SCSI_LOW_UNLOCK(slp); return 0; } static int -scsi_low_world_start_cam(slp) - struct scsi_low_softc *slp; -{ - - return 0; -} - -static int -scsi_low_dettach_cam(slp) +scsi_low_detach_cam(slp) struct scsi_low_softc *slp; { - xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL); - xpt_free_path(slp->sl_si.path); - xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); - cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE); + xpt_async(AC_LOST_DEVICE, slp->sl_path, NULL); + xpt_free_path(slp->sl_path); + xpt_bus_deregister(cam_sim_path(slp->sl_sim)); + cam_sim_free(slp->sl_sim, /* free_devq */ TRUE); return 0; } static int scsi_low_ccb_setup_cam(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { union ccb *ccb = (union ccb *) cb->osdep; if ((cb->ccb_flags & CCB_SCSIIO) != 0) { cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; cb->ccb_scp.scp_data = ccb->csio.data_ptr; cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = ccb->ccb_h.timeout / 1000; } else { scsi_low_unit_ready_cmd(cb); } return SCSI_LOW_START_QTAG; } static int scsi_low_done_cam(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { union ccb *ccb; ccb = (union ccb *) cb->osdep; if (cb->ccb_error == 0) { ccb->ccb_h.status = CAM_REQ_CMP; ccb->csio.resid = 0; } else { if (cb->ccb_rcnt >= slp->sl_max_retry) cb->ccb_error |= ABORTIO; if ((cb->ccb_flags & CCB_NORETRY) == 0 && (cb->ccb_error & ABORTIO) == 0) return EJUSTRETURN; if ((cb->ccb_error & SENSEIO) != 0) { memcpy(&ccb->csio.sense_data, &cb->ccb_sense, sizeof(ccb->csio.sense_data)); } ccb->ccb_h.status = scsi_low_translate_error_code(cb, &scsi_low_error_code_cam[0]); #ifdef SCSI_LOW_DIAGNOSTIC if ((cb->ccb_flags & CCB_SILENT) == 0 && cb->ccb_scp.scp_cmdlen > 0 && (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & SCSI_LOW_CMD_ABORT_WARNING) != 0) { device_printf(slp->sl_dev, "WARNING: scsi_low IO abort\n"); scsi_low_print(slp, NULL); } #endif /* SCSI_LOW_DIAGNOSTIC */ } if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0) ccb->ccb_h.status |= CAM_REQ_CMP_ERR; if (cb->ccb_scp.scp_status == ST_UNKNOWN) ccb->csio.scsi_status = 0; /* XXX */ else ccb->csio.scsi_status = cb->ccb_scp.scp_status; if ((cb->ccb_flags & CCB_NOSDONE) == 0) xpt_done(ccb); return 0; } -static void -scsi_low_timeout_cam(slp, ch, action) - struct scsi_low_softc *slp; - int ch; - int action; -{ - - switch (ch) - { - case SCSI_LOW_TIMEOUT_CH_IO: - switch (action) - { - case SCSI_LOW_TIMEOUT_START: - slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp, - hz / SCSI_LOW_TIMEOUT_HZ); - break; - case SCSI_LOW_TIMEOUT_STOP: - untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch); - break; - } - break; - - case SCSI_LOW_TIMEOUT_CH_ENGAGE: - switch (action) - { - case SCSI_LOW_TIMEOUT_START: - slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1); - break; - case SCSI_LOW_TIMEOUT_STOP: - untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch); - break; - } - break; - case SCSI_LOW_TIMEOUT_CH_RECOVER: - break; - } -} - -/*============================================================= - * END OF OS switch (All OS depend fucntions should be above) - =============================================================*/ - /************************************************************** * scsi low deactivate and activate **************************************************************/ int scsi_low_is_busy(slp) struct scsi_low_softc *slp; { if (slp->sl_nio > 0) return EBUSY; return 0; } int scsi_low_deactivate(slp) struct scsi_low_softc *slp; { - int s; - s = splcam(); slp->sl_flags |= HW_INACTIVE; - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP); - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); - splx(s); + callout_stop(&slp->sl_timeout_timer); + callout_stop(&slp->sl_engage_timer); return 0; } int scsi_low_activate(slp) struct scsi_low_softc *slp; { - int error, s; + int error; - s = splcam(); slp->sl_flags &= ~HW_INACTIVE; if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0) { slp->sl_flags |= HW_INACTIVE; - splx(s); return error; } slp->sl_timeout_count = 0; - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); - splx(s); + callout_reset(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ, + scsi_low_timeout, slp); return 0; } /************************************************************** * scsi low log **************************************************************/ #ifdef SCSI_LOW_DIAGNOSTIC static void scsi_low_msg_log_init(struct scsi_low_msg_log *); static void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int); static void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int); static void scsi_low_msg_log_init(slmlp) struct scsi_low_msg_log *slmlp; { slmlp->slml_ptr = 0; } static void scsi_low_msg_log_write(slmlp, datap, len) struct scsi_low_msg_log *slmlp; u_int8_t *datap; int len; { int ptr, ind; if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN) return; ptr = slmlp->slml_ptr ++; for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++) slmlp->slml_msg[ptr].msg[ind] = datap[ind]; for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++) slmlp->slml_msg[ptr].msg[ind] = 0; } static void scsi_low_msg_log_show(slmlp, s, len) struct scsi_low_msg_log *slmlp; char *s; int len; { int ptr, ind; printf("%s: (%d) ", s, slmlp->slml_ptr); for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++) { for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]); ind ++) { printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]); } printf(">"); } printf("\n"); } #endif /* SCSI_LOW_DIAGNOSTIC */ /************************************************************** * power control **************************************************************/ static void scsi_low_engage(arg) void *arg; { struct scsi_low_softc *slp = arg; - int s = splcam(); + SCSI_LOW_ASSERT_LOCKED(slp); switch (slp->sl_rstep) { case 0: slp->sl_rstep ++; (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, - SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START); + callout_reset(&slp->sl_engage_timer, hz / 1000, + scsi_low_engage, slp); break; case 1: slp->sl_rstep ++; slp->sl_flags &= ~HW_RESUME; scsi_low_start(slp); break; case 2: break; } - splx(s); } static int scsi_low_init(slp, flags) struct scsi_low_softc *slp; u_int flags; { int rv = 0; slp->sl_flags |= HW_INITIALIZING; /* clear power control timeout */ if ((slp->sl_flags & HW_POWERCTRL) != 0) { - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, - SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); + callout_stop(&slp->sl_engage_timer); slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); slp->sl_active = 1; slp->sl_powc = SCSI_LOW_POWDOWN_TC; } /* reset current nexus */ scsi_low_reset_nexus(slp, flags); if ((slp->sl_flags & HW_INACTIVE) != 0) { rv = EBUSY; goto out; } if (flags != SCSI_LOW_RESTART_SOFT) { rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags)); } out: slp->sl_flags &= ~HW_INITIALIZING; return rv; } /************************************************************** * allocate lun_info **************************************************************/ static struct lun_info * scsi_low_alloc_li(ti, lun, alloc) struct targ_info *ti; int lun; int alloc; { struct scsi_low_softc *slp = ti->ti_sc; struct lun_info *li; li = LIST_FIRST(&ti->ti_litab); if (li != NULL) { if (li->li_lun == lun) return li; while ((li = LIST_NEXT(li, lun_chain)) != NULL) { if (li->li_lun == lun) { LIST_REMOVE(li, lun_chain); LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); return li; } } } if (alloc == 0) return li; li = SCSI_LOW_MALLOC(ti->ti_lunsize); if (li == NULL) panic("no lun info mem"); bzero(li, ti->ti_lunsize); li->li_lun = lun; li->li_ti = ti; li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC | SCSI_LOW_QTAG; li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS; li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID; #ifdef SCSI_LOW_FLAGS_QUIRKS_OK li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; #endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ li->li_qtagbits = (u_int) -1; TAILQ_INIT(&li->li_discq); LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); /* host specific structure initialization per lun */ if (slp->sl_funcs->scsi_low_lun_init != NULL) (*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li, SCSI_LOW_INFO_ALLOC); scsi_low_calcf_lun(li); return li; } /************************************************************** * allocate targ_info **************************************************************/ static struct targ_info * scsi_low_alloc_ti(slp, targ) struct scsi_low_softc *slp; int targ; { struct targ_info *ti; if (TAILQ_FIRST(&slp->sl_titab) == NULL) TAILQ_INIT(&slp->sl_titab); ti = SCSI_LOW_MALLOC(slp->sl_targsize); if (ti == NULL) panic("%s short of memory", device_get_nameunit(slp->sl_dev)); bzero(ti, slp->sl_targsize); ti->ti_id = targ; ti->ti_sc = slp; slp->sl_ti[targ] = ti; TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); LIST_INIT(&ti->ti_litab); ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID; #ifdef SCSI_LOW_FLAGS_QUIRKS_OK ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; #endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ if (slp->sl_funcs->scsi_low_targ_init != NULL) { (*slp->sl_funcs->scsi_low_targ_init) (slp, ti, SCSI_LOW_INFO_ALLOC); } scsi_low_calcf_target(ti); return ti; } static void scsi_low_free_ti(slp) struct scsi_low_softc *slp; { struct targ_info *ti, *tib; struct lun_info *li, *nli; for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) { for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) { if (slp->sl_funcs->scsi_low_lun_init != NULL) { (*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li, SCSI_LOW_INFO_DEALLOC); } nli = LIST_NEXT(li, lun_chain); SCSI_LOW_FREE(li); } if (slp->sl_funcs->scsi_low_targ_init != NULL) { (*slp->sl_funcs->scsi_low_targ_init) (slp, ti, SCSI_LOW_INFO_DEALLOC); } tib = TAILQ_NEXT(ti, ti_chain); SCSI_LOW_FREE(ti); } } /************************************************************** * timeout **************************************************************/ void scsi_low_bus_idle(slp) struct scsi_low_softc *slp; { slp->sl_retry_sel = 0; if (slp->sl_Tnexus == NULL) scsi_low_start(slp); } static void scsi_low_timeout(arg) void *arg; { struct scsi_low_softc *slp = arg; - int s; - s = splcam(); + SCSI_LOW_ASSERT_LOCKED(slp); (void) scsi_low_timeout_check(slp); - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); - splx(s); + callout_schedule(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ); } static int scsi_low_timeout_check(slp) struct scsi_low_softc *slp; { struct targ_info *ti; struct lun_info *li; struct slccb *cb = NULL; /* XXX */ /* selection restart */ if (slp->sl_retry_sel != 0) { slp->sl_retry_sel = 0; if (slp->sl_Tnexus != NULL) goto step1; cb = TAILQ_FIRST(&slp->sl_start); if (cb == NULL) goto step1; if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY) { cb->ccb_flags |= CCB_NORETRY; cb->ccb_error |= SELTIMEOUTIO; if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) panic("%s: ccb not finished", device_get_nameunit(slp->sl_dev)); } if (slp->sl_Tnexus == NULL) scsi_low_start(slp); } /* call hardware timeout */ step1: if (slp->sl_funcs->scsi_low_timeout != NULL) { (*slp->sl_funcs->scsi_low_timeout) (slp); } if (slp->sl_timeout_count ++ < SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ) return 0; slp->sl_timeout_count = 0; if (slp->sl_nio > 0) { if ((cb = slp->sl_Qnexus) != NULL) { cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; if (cb->ccb_tc < 0) goto bus_reset; } else if (slp->sl_disc == 0) { if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL) return 0; cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; if (cb->ccb_tc < 0) goto bus_reset; } else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; ti = TAILQ_NEXT(ti, ti_chain)) { if (ti->ti_disc == 0) continue; for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = LIST_NEXT(li, lun_chain)) { for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) { cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; if (cb->ccb_tc < 0) goto bus_reset; } } } } else if ((slp->sl_flags & HW_POWERCTRL) != 0) { if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) return 0; if (slp->sl_active != 0) { slp->sl_powc = SCSI_LOW_POWDOWN_TC; slp->sl_active = 0; return 0; } slp->sl_powc --; if (slp->sl_powc < 0) { slp->sl_powc = SCSI_LOW_POWDOWN_TC; slp->sl_flags |= HW_POWDOWN; (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_POWDOWN); } } return 0; bus_reset: cb->ccb_error |= TIMEOUTIO; device_printf(slp->sl_dev, "slccb (0x%lx) timeout!\n", (u_long) cb); scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); scsi_low_init(slp, SCSI_LOW_RESTART_HARD); scsi_low_start(slp); return ERESTART; } static int scsi_low_abort_ccb(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { struct targ_info *ti; struct lun_info *li; u_int msg; if (cb == NULL) return EINVAL; if ((cb->ccb_omsgoutflag & (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0) return EBUSY; ti = cb->ti; li = cb->li; if (cb->ccb_tag == SCSI_LOW_UNKTAG) msg = SCSI_LOW_MSG_ABORT; else msg = SCSI_LOW_MSG_ABORT_QTAG; cb->ccb_error |= ABORTIO; cb->ccb_flags |= CCB_NORETRY; scsi_low_ccb_message_assert(cb, msg); if (cb == slp->sl_Qnexus) { scsi_low_assert_msg(slp, ti, msg, 1); } else if ((cb->ccb_flags & CCB_DISCQ) != 0) { if (scsi_low_revoke_ccb(slp, cb, 0) == NULL) panic("%s: revoked ccb done", device_get_nameunit(slp->sl_dev)); cb->ccb_flags |= CCB_STARTQ; TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); if (slp->sl_Tnexus == NULL) scsi_low_start(slp); } else { if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) panic("%s: revoked ccb retried", device_get_nameunit(slp->sl_dev)); } return 0; } /************************************************************** * Generic SCSI INTERFACE **************************************************************/ int scsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize) struct scsi_low_softc *slp; int openings, ntargs, nluns, targsize, lunsize; { struct targ_info *ti; struct lun_info *li; - int s, i, nccb, rv; - - slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam; - - if (slp->sl_osdep_fp == NULL) - panic("scsi_low: interface not spcified"); + int i, nccb, rv; if (ntargs > SCSI_LOW_NTARGETS) { printf("scsi_low: %d targets are too large\n", ntargs); printf("change kernel options SCSI_LOW_NTARGETS"); return EINVAL; } if (openings <= 0) slp->sl_openings = (SCSI_LOW_NCCB / ntargs); else slp->sl_openings = openings; slp->sl_ntargs = ntargs; slp->sl_nluns = nluns; slp->sl_max_retry = SCSI_LOW_MAX_RETRY; if (lunsize < sizeof(struct lun_info)) lunsize = sizeof(struct lun_info); if (targsize < sizeof(struct targ_info)) targsize = sizeof(struct targ_info); slp->sl_targsize = targsize; for (i = 0; i < ntargs; i ++) { ti = scsi_low_alloc_ti(slp, i); ti->ti_lunsize = lunsize; li = scsi_low_alloc_li(ti, 0, 1); } /* initialize queue */ nccb = openings * ntargs; if (nccb >= SCSI_LOW_NCCB || nccb <= 0) nccb = SCSI_LOW_NCCB; scsi_low_init_ccbque(nccb); TAILQ_INIT(&slp->sl_start); /* call os depend attach */ - s = splcam(); - rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp); + rv = scsi_low_attach_cam(slp); if (rv != 0) { - splx(s); device_printf(slp->sl_dev, "scsi_low_attach: osdep attach failed\n"); - return EINVAL; + return (rv); } /* check hardware */ DELAY(1000); /* wait for 1ms */ + SCSI_LOW_LOCK(slp); if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) { - splx(s); device_printf(slp->sl_dev, "scsi_low_attach: initialization failed\n"); + SCSI_LOW_UNLOCK(slp); return EINVAL; } /* start watch dog */ slp->sl_timeout_count = 0; - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); + callout_reset(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ, + scsi_low_timeout, slp); + mtx_lock(&sl_tab_lock); LIST_INSERT_HEAD(&sl_tab, slp, sl_chain); + mtx_unlock(&sl_tab_lock); /* fake call */ scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL)); #ifdef SCSI_LOW_START_UP_CHECK /* probing devices */ scsi_low_start_up(slp); #endif /* SCSI_LOW_START_UP_CHECK */ + SCSI_LOW_UNLOCK(slp); - /* call os depend attach done*/ - (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp); - splx(s); return 0; } int -scsi_low_dettach(slp) +scsi_low_detach(slp) struct scsi_low_softc *slp; { - int s, rv; + int rv; - s = splcam(); + SCSI_LOW_LOCK(slp); if (scsi_low_is_busy(slp) != 0) { - splx(s); + SCSI_LOW_UNLOCK(slp); return EBUSY; } scsi_low_deactivate(slp); - rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp); + rv = scsi_low_detach_cam(slp); if (rv != 0) { - splx(s); + SCSI_LOW_UNLOCK(slp); return EBUSY; } scsi_low_free_ti(slp); + SCSI_LOW_UNLOCK(slp); + callout_drain(&slp->sl_timeout_timer); + callout_drain(&slp->sl_engage_timer); + mtx_lock(&sl_tab_lock); LIST_REMOVE(slp, sl_chain); - splx(s); + mtx_unlock(&sl_tab_lock); return 0; } /************************************************************** * Generic enqueue **************************************************************/ static int scsi_low_enqueue(slp, ti, li, cb, flags, msg) struct scsi_low_softc *slp; struct targ_info *ti; struct lun_info *li; struct slccb *cb; u_int flags, msg; { cb->ti = ti; cb->li = li; scsi_low_ccb_message_assert(cb, msg); cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG; scsi_low_alloc_qtag(cb); cb->ccb_flags = flags | CCB_STARTQ; cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; cb->ccb_error |= PENDINGIO; if ((flags & CCB_URGENT) != 0) { TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); } else { TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); } slp->sl_nio ++; if (slp->sl_Tnexus == NULL) scsi_low_start(slp); return 0; } static int scsi_low_message_enqueue(slp, ti, li, flags) struct scsi_low_softc *slp; struct targ_info *ti; struct lun_info *li; u_int flags; { struct slccb *cb; u_int tmsgflags; tmsgflags = ti->ti_setup_msg; ti->ti_setup_msg = 0; flags |= CCB_NORETRY; if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) return ENOMEM; cb->osdep = NULL; cb->bp = NULL; scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags); return 0; } /************************************************************** * Generic Start & Done **************************************************************/ #define SLSC_MODE_SENSE_SHORT 0x1a static u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0}; static u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0, sizeof(struct scsi_low_mode_sense_data), 0}; static u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0, sizeof(struct scsi_low_inq_data), 0}; static u_int8_t unit_ready_cmd[6]; static int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); static int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); static int scsi_low_resume(struct scsi_low_softc *); static void scsi_low_unit_ready_cmd(cb) struct slccb *cb; { cb->ccb_scp.scp_cmd = unit_ready_cmd; cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); cb->ccb_scp.scp_datalen = 0; cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = 15; } static int scsi_low_sense_abort_start(slp, ti, li, cb) struct scsi_low_softc *slp; struct targ_info *ti; struct lun_info *li; struct slccb *cb; { cb->ccb_scp.scp_cmdlen = 6; bzero(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen); cb->ccb_scsi_cmd[0] = REQUEST_SENSE; cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense); cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd; cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = 15; scsi_low_ccb_message_clear(cb); if ((cb->ccb_flags & CCB_CLEARQ) != 0) { scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); } else { bzero(&cb->ccb_sense, sizeof(cb->ccb_sense)); #ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0); #endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ } return SCSI_LOW_START_NO_QTAG; } static int scsi_low_setup_start(slp, ti, li, cb) struct scsi_low_softc *slp; struct targ_info *ti; struct lun_info *li; struct slccb *cb; { switch(li->li_state) { case SCSI_LOW_LUN_SLEEP: scsi_low_unit_ready_cmd(cb); break; case SCSI_LOW_LUN_START: cb->ccb_scp.scp_cmd = ss_cmd; cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); cb->ccb_scp.scp_datalen = 0; cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = 30; break; case SCSI_LOW_LUN_INQ: cb->ccb_scp.scp_cmd = inq_cmd; cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd); cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq; cb->ccb_scp.scp_datalen = sizeof(li->li_inq); cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = 15; break; case SCSI_LOW_LUN_MODEQ: cb->ccb_scp.scp_cmd = sms_cmd; cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd); cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms; cb->ccb_scp.scp_datalen = sizeof(li->li_sms); cb->ccb_scp.scp_direction = SCSI_LOW_READ; cb->ccb_tcmax = 15; return SCSI_LOW_START_QTAG; default: panic("%s: no setup phase", device_get_nameunit(slp->sl_dev)); } return SCSI_LOW_START_NO_QTAG; } static int scsi_low_resume(slp) struct scsi_low_softc *slp; { if (slp->sl_flags & HW_RESUME) return EJUSTRETURN; slp->sl_flags &= ~HW_POWDOWN; if (slp->sl_funcs->scsi_low_power != NULL) { slp->sl_flags |= HW_RESUME; slp->sl_rstep = 0; (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); - (*slp->sl_osdep_fp->scsi_low_osdep_timeout) - (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, - SCSI_LOW_TIMEOUT_START); + callout_reset(&slp->sl_engage_timer, hz / 1000, + scsi_low_engage, slp); return EJUSTRETURN; } return 0; } static void scsi_low_start(slp) struct scsi_low_softc *slp; { struct targ_info *ti; struct lun_info *li; struct slccb *cb; int rv; /* check hardware exists or under initializations ? */ if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) return; /* check hardware power up ? */ if ((slp->sl_flags & HW_POWERCTRL) != 0) { slp->sl_active ++; if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) { if (scsi_low_resume(slp) == EJUSTRETURN) return; } } /* setup nexus */ #ifdef SCSI_LOW_DIAGNOSTIC if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus) { scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); panic("%s: inconsistent", device_get_nameunit(slp->sl_dev)); } #endif /* SCSI_LOW_DIAGNOSTIC */ for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) { li = cb->li; if (li->li_disc == 0) { goto scsi_low_cmd_start; } else if (li->li_nqio > 0) { if (li->li_nqio < li->li_maxnqio || (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) goto scsi_low_cmd_start; } } return; scsi_low_cmd_start: cb->ccb_flags &= ~CCB_STARTQ; TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); ti = cb->ti; /* clear all error flag bits (for restart) */ cb->ccb_error = 0; cb->ccb_datalen = -1; cb->ccb_scp.scp_status = ST_UNKNOWN; /* setup nexus pointer */ slp->sl_Qnexus = cb; slp->sl_Lnexus = li; slp->sl_Tnexus = ti; /* initialize msgsys */ scsi_low_init_msgsys(slp, ti); /* exec cmd */ if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) { /* CA state or forced abort */ rv = scsi_low_sense_abort_start(slp, ti, li, cb); } else if (li->li_state >= SCSI_LOW_LUN_OK) { cb->ccb_flags &= ~CCB_INTERNAL; - rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb); + rv = scsi_low_ccb_setup_cam(slp, cb); if (cb->ccb_msgoutflag != 0) { scsi_low_ccb_message_exec(slp, cb); } } else { cb->ccb_flags |= CCB_INTERNAL; rv = scsi_low_setup_start(slp, ti, li, cb); } /* allocate qtag */ #define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC) if (rv == SCSI_LOW_START_QTAG && (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK && li->li_maxnqio > 0) { u_int qmsg; scsi_low_activate_qtag(cb); if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & SCSI_LOW_CMD_ORDERED_QTAG) != 0) qmsg = SCSI_LOW_MSG_ORDERED_QTAG; else if ((cb->ccb_flags & CCB_URGENT) != 0) qmsg = SCSI_LOW_MSG_HEAD_QTAG; else qmsg = SCSI_LOW_MSG_SIMPLE_QTAG; scsi_low_assert_msg(slp, ti, qmsg, 0); } /* timeout */ if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; cb->ccb_tc = cb->ccb_tcmax; /* setup saved scsi data pointer */ cb->ccb_sscp = cb->ccb_scp; /* setup current scsi pointer */ slp->sl_scp = cb->ccb_sscp; slp->sl_error = cb->ccb_error; /* assert always an identify msg */ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); /* debug section */ #ifdef SCSI_LOW_DIAGNOSTIC scsi_low_msg_log_init(&ti->ti_log_msgin); scsi_low_msg_log_init(&ti->ti_log_msgout); #endif /* SCSI_LOW_DIAGNOSTIC */ /* selection start */ slp->sl_selid = cb; rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); if (rv == SCSI_LOW_START_OK) { #ifdef SCSI_LOW_STATICS scsi_low_statics.nexus_win ++; #endif /* SCSI_LOW_STATICS */ return; } scsi_low_arbit_fail(slp, cb); #ifdef SCSI_LOW_STATICS scsi_low_statics.nexus_fail ++; #endif /* SCSI_LOW_STATICS */ } void scsi_low_arbit_fail(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { struct targ_info *ti = cb->ti; scsi_low_deactivate_qtag(cb); scsi_low_ccb_message_retry(cb); cb->ccb_flags |= CCB_STARTQ; TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); scsi_low_bus_release(slp, ti); cb->ccb_selrcnt ++; if (slp->sl_disc == 0) { #ifdef SCSI_LOW_DIAGNOSTIC device_printf(slp->sl_dev, "try selection again\n"); #endif /* SCSI_LOW_DIAGNOSTIC */ slp->sl_retry_sel = 1; } } static void scsi_low_bus_release(slp, ti) struct scsi_low_softc *slp; struct targ_info *ti; { if (ti->ti_disc > 0) { SCSI_LOW_SETUP_PHASE(ti, PH_DISC); } else { SCSI_LOW_SETUP_PHASE(ti, PH_NULL); } /* clear all nexus pointer */ slp->sl_Qnexus = NULL; slp->sl_Lnexus = NULL; slp->sl_Tnexus = NULL; /* clear selection assert */ slp->sl_selid = NULL; /* clear nexus data */ slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; /* clear phase change counter */ slp->sl_ph_count = 0; } static int scsi_low_setup_done(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { struct targ_info *ti; struct lun_info *li; ti = cb->ti; li = cb->li; if (cb->ccb_rcnt >= slp->sl_max_retry) { cb->ccb_error |= ABORTIO; return SCSI_LOW_DONE_COMPLETE; } /* XXX: special huck for selection timeout */ if (li->li_state == SCSI_LOW_LUN_SLEEP && (cb->ccb_error & SELTIMEOUTIO) != 0) { cb->ccb_error |= ABORTIO; return SCSI_LOW_DONE_COMPLETE; } switch(li->li_state) { case SCSI_LOW_LUN_INQ: if (cb->ccb_error != 0) { li->li_diskflags &= ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG); if (li->li_lun > 0) goto resume; ti->ti_diskflags &= ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE); } else if ((li->li_inq.sd_version & 7) >= 2 || (li->li_inq.sd_len >= 4)) { if ((li->li_inq.sd_support & 0x2) == 0) li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; if ((li->li_inq.sd_support & 0x8) == 0) li->li_diskflags &= ~SCSI_LOW_DISK_LINK; if (li->li_lun > 0) goto resume; if ((li->li_inq.sd_support & 0x10) == 0) ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC; if ((li->li_inq.sd_support & 0x20) == 0) ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16; if ((li->li_inq.sd_support & 0x40) == 0) ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32; } else { li->li_diskflags &= ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK); if (li->li_lun > 0) goto resume; ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE; } ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID; resume: scsi_low_calcf_target(ti); scsi_low_calcf_lun(li); break; case SCSI_LOW_LUN_MODEQ: if (cb->ccb_error != 0) { if (cb->ccb_error & SENSEIO) { #ifdef SCSI_LOW_DEBUG if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) { int error_code, sense_key, asc, ascq; scsi_extract_sense(&cb->ccb_sense, &error_code, &sense_key, &asc, &ascq); printf("SENSE: [%x][%x][%x][%x]\n", error_code, sense_key, asc, ascq); } #endif /* SCSI_LOW_DEBUG */ } else { li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; } } else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a) { if (li->li_sms.sms_cmp.cmp_qc & 0x02) li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR; else li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR; if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0) li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; } li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID; scsi_low_calcf_lun(li); break; default: break; } li->li_state ++; if (li->li_state == SCSI_LOW_LUN_OK) { scsi_low_calcf_target(ti); scsi_low_calcf_lun(li); if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID && (slp->sl_show_result & SHOW_CALCF_RES) != 0) { scsi_low_calcf_show(li); } } cb->ccb_rcnt --; return SCSI_LOW_DONE_RETRY; } static int scsi_low_done(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { int rv; if (cb->ccb_error == 0) { if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) { #ifdef SCSI_LOW_QCLEAR_AFTER_CA /* XXX: * SCSI-2 draft suggests * page 0x0a QErr bit determins if * the target aborts or continues * the queueing io's after CA state resolved. * However many targets seem not to support * the page 0x0a. Thus we should manually clear the * queuing io's after CA state. */ if ((cb->ccb_flags & CCB_CLEARQ) == 0) { cb->ccb_rcnt --; cb->ccb_flags |= CCB_CLEARQ; goto retry; } #endif /* SCSI_LOW_QCLEAR_AFTER_CA */ if ((cb->ccb_flags & CCB_SENSE) != 0) cb->ccb_error |= (SENSEIO | ABORTIO); cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ); } else switch (cb->ccb_sscp.scp_status) { case ST_GOOD: case ST_MET: case ST_INTERGOOD: case ST_INTERMET: if (cb->ccb_datalen == 0 || cb->ccb_scp.scp_datalen == 0) break; if (cb->ccb_scp.scp_cmdlen > 0 && (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & SCSI_LOW_CMD_RESIDUAL_CHK) == 0) break; cb->ccb_error |= PDMAERR; break; case ST_BUSY: case ST_QUEFULL: cb->ccb_error |= (BUSYERR | STATERR); break; case ST_CONFLICT: cb->ccb_error |= (STATERR | ABORTIO); break; case ST_CHKCOND: case ST_CMDTERM: if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL)) { cb->ccb_rcnt --; cb->ccb_flags |= CCB_SENSE; goto retry; } cb->ccb_error |= (UACAERR | STATERR | ABORTIO); break; case ST_UNKNOWN: default: cb->ccb_error |= FATALIO; break; } } else { if (cb->ccb_flags & CCB_SENSE) { cb->ccb_error |= (SENSEERR | ABORTIO); } cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE); } /* internal ccb */ if ((cb->ccb_flags & CCB_INTERNAL) != 0) { if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY) goto retry; } /* check a ccb msgout flag */ if (cb->ccb_omsgoutflag != 0) { #define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \ SCSI_LOW_MSG_ABORT_QTAG | \ SCSI_LOW_MSG_CLEAR_QTAG | \ SCSI_LOW_MSG_TERMIO) if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0) { cb->ccb_error |= ABORTIO; } } /* call OS depend done */ if (cb->osdep != NULL) { - rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb); + rv = scsi_low_done_cam(slp, cb); if (rv == EJUSTRETURN) goto retry; } else if (cb->ccb_error != 0) { if (cb->ccb_rcnt >= slp->sl_max_retry) cb->ccb_error |= ABORTIO; if ((cb->ccb_flags & CCB_NORETRY) == 0 && (cb->ccb_error & ABORTIO) == 0) goto retry; } /* free our target */ #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) { printf(">> SCSI_LOW_DONE_COMPLETE ===============\n"); scsi_low_print(slp, NULL); } #endif /* SCSI_LOW_DEBUG */ scsi_low_deactivate_qtag(cb); scsi_low_dealloc_qtag(cb); scsi_low_free_ccb(cb); slp->sl_nio --; return SCSI_LOW_DONE_COMPLETE; retry: #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) { printf("** SCSI_LOW_DONE_RETRY ===============\n"); scsi_low_print(slp, NULL); } #endif /* SCSI_LOW_DEBUG */ cb->ccb_rcnt ++; scsi_low_deactivate_qtag(cb); scsi_low_ccb_message_retry(cb); return SCSI_LOW_DONE_RETRY; } /************************************************************** * Reset **************************************************************/ static void scsi_low_reset_nexus_target(slp, ti, fdone) struct scsi_low_softc *slp; struct targ_info *ti; int fdone; { struct lun_info *li; for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = LIST_NEXT(li, lun_chain)) { scsi_low_reset_nexus_lun(slp, li, fdone); li->li_state = SCSI_LOW_LUN_SLEEP; li->li_maxnqio = 0; } ti->ti_disc = 0; ti->ti_setup_msg = 0; ti->ti_setup_msg_done = 0; ti->ti_osynch.offset = ti->ti_osynch.period = 0; ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID; if (slp->sl_funcs->scsi_low_targ_init != NULL) { ((*slp->sl_funcs->scsi_low_targ_init) (slp, ti, SCSI_LOW_INFO_REVOKE)); } scsi_low_calcf_target(ti); for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = LIST_NEXT(li, lun_chain)) { li->li_flags = 0; li->li_diskflags = SCSI_LOW_DISK_LFLAGS; li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID; if (slp->sl_funcs->scsi_low_lun_init != NULL) { ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li, SCSI_LOW_INFO_REVOKE)); } scsi_low_calcf_lun(li); } } static void scsi_low_reset_nexus(slp, fdone) struct scsi_low_softc *slp; int fdone; { struct targ_info *ti; struct slccb *cb, *topcb; if ((cb = slp->sl_Qnexus) != NULL) { topcb = scsi_low_revoke_ccb(slp, cb, fdone); } else { topcb = NULL; } for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; ti = TAILQ_NEXT(ti, ti_chain)) { scsi_low_reset_nexus_target(slp, ti, fdone); scsi_low_bus_release(slp, ti); scsi_low_init_msgsys(slp, ti); } if (topcb != NULL) { topcb->ccb_flags |= CCB_STARTQ; TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain); } slp->sl_disc = 0; slp->sl_retry_sel = 0; slp->sl_flags &= ~HW_PDMASTART; } /* misc */ static int tw_pos; static char tw_chars[] = "|/-\\"; #define TWIDDLEWAIT 10000 static void scsi_low_twiddle_wait(void) { cnputc('\b'); cnputc(tw_chars[tw_pos++]); tw_pos %= (sizeof(tw_chars) - 1); DELAY(TWIDDLEWAIT); } void scsi_low_bus_reset(slp) struct scsi_low_softc *slp; { int i; (*slp->sl_funcs->scsi_low_bus_reset) (slp); device_printf(slp->sl_dev, "try to reset scsi bus "); for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) scsi_low_twiddle_wait(); cnputc('\b'); printf("\n"); } int scsi_low_restart(slp, flags, s) struct scsi_low_softc *slp; int flags; u_char *s; { int error; if (s != NULL) device_printf(slp->sl_dev, "scsi bus restart. reason: %s\n", s); if ((error = scsi_low_init(slp, flags)) != 0) return error; scsi_low_start(slp); return 0; } /************************************************************** * disconnect and reselect **************************************************************/ #define MSGCMD_LUN(msg) (msg & 0x07) static struct slccb * scsi_low_establish_ccb(ti, li, tag) struct targ_info *ti; struct lun_info *li; scsi_low_tag_t tag; { struct scsi_low_softc *slp = ti->ti_sc; struct slccb *cb; if (li == NULL) return NULL; cb = TAILQ_FIRST(&li->li_discq); for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) if (cb->ccb_tag == tag) goto found; return cb; /* * establish our ccb nexus */ found: #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) { device_printf(slp->sl_dev, "nexus(0x%lx) abort check start\n", (u_long) cb); cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT); scsi_low_revoke_ccb(slp, cb, 1); return NULL; } if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0) { if (cb->ccb_omsgoutflag == 0) scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP); } #endif /* SCSI_LOW_DEBUG */ TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); cb->ccb_flags &= ~CCB_DISCQ; slp->sl_Qnexus = cb; slp->sl_scp = cb->ccb_sscp; slp->sl_error |= cb->ccb_error; slp->sl_disc --; ti->ti_disc --; li->li_disc --; /* inform "ccb nexus established" to the host driver */ (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); /* check msg */ if (cb->ccb_msgoutflag != 0) { scsi_low_ccb_message_exec(slp, cb); } return cb; } struct targ_info * scsi_low_reselected(slp, targ) struct scsi_low_softc *slp; u_int targ; { struct targ_info *ti; struct slccb *cb; u_char *s; /* * Check select vs reselected collision. */ if ((cb = slp->sl_selid) != NULL) { scsi_low_arbit_fail(slp, cb); #ifdef SCSI_LOW_STATICS scsi_low_statics.nexus_conflict ++; #endif /* SCSI_LOW_STATICS */ } /* * Check if no current active nexus. */ if (slp->sl_Tnexus != NULL) { s = "host busy"; goto world_restart; } /* * Check a valid target id asserted ? */ if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) { s = "scsi id illegal"; goto world_restart; } /* * Check the target scsi status. */ ti = slp->sl_ti[targ]; if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL) { s = "phase mismatch"; goto world_restart; } /* * Setup init msgsys */ slp->sl_error = 0; scsi_low_init_msgsys(slp, ti); /* * Establish our target nexus */ SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); slp->sl_Tnexus = ti; #ifdef SCSI_LOW_STATICS scsi_low_statics.nexus_reselected ++; #endif /* SCSI_LOW_STATICS */ return ti; world_restart: device_printf(slp->sl_dev, "reselect(%x:unknown) %s\n", targ, s); scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "reselect: scsi world confused"); return NULL; } /************************************************************** * cmd out pointer setup **************************************************************/ int scsi_low_cmd(slp, ti) struct scsi_low_softc *slp; struct targ_info *ti; { struct slccb *cb = slp->sl_Qnexus; slp->sl_ph_count ++; if (cb == NULL) { /* * no ccb, abort! */ slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); slp->sl_scp.scp_datalen = 0; slp->sl_scp.scp_direction = SCSI_LOW_READ; slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found"); return EINVAL; } else { #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id)) { scsi_low_test_cmdlnk(slp, cb); } #endif /* SCSI_LOW_DEBUG */ } return 0; } /************************************************************** * data out pointer setup **************************************************************/ int scsi_low_data(slp, ti, bp, direction) struct scsi_low_softc *slp; struct targ_info *ti; struct buf **bp; int direction; { struct slccb *cb = slp->sl_Qnexus; if (cb != NULL && direction == cb->ccb_sscp.scp_direction) { *bp = cb->bp; return 0; } slp->sl_error |= (FATALIO | PDMAERR); slp->sl_scp.scp_datalen = 0; slp->sl_scp.scp_direction = direction; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); if (ti->ti_ophase != ti->ti_phase) { char *s; if (cb == NULL) s = "DATA PHASE: ccb nexus not found"; else s = "DATA PHASE: xfer direction mismatch"; SCSI_LOW_INFO(slp, ti, s); } *bp = NULL; return EINVAL; } /************************************************************** * MSG_SYS **************************************************************/ #define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} #define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) #define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) #define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3]) #define MSGIN_DATA_LAST 0x30 static int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int); static int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int); static int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int); static int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int); static int scsi_low_msgfunc_synch(struct scsi_low_softc *); static int scsi_low_msgfunc_wide(struct scsi_low_softc *); static int scsi_low_msgfunc_identify(struct scsi_low_softc *); static int scsi_low_msgfunc_abort(struct scsi_low_softc *); static int scsi_low_msgfunc_qabort(struct scsi_low_softc *); static int scsi_low_msgfunc_qtag(struct scsi_low_softc *); static int scsi_low_msgfunc_reset(struct scsi_low_softc *); struct scsi_low_msgout_data { u_int md_flags; u_int8_t md_msg; int (*md_msgfunc)(struct scsi_low_softc *); int (*md_errfunc)(struct scsi_low_softc *, u_int); #define MSG_RELEASE_ATN 0x0001 u_int md_condition; }; struct scsi_low_msgout_data scsi_low_msgout_data[] = { /* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN}, /* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN}, /* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN}, /* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN}, /* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0}, /* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, /* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN}, /* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, /* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, /* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, /* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN}, /* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, /* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN}, /* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN}, /* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN}, /* 15 */{SCSI_LOW_MSG_ALL, 0}, }; static int scsi_low_msginfunc_ext(struct scsi_low_softc *); static int scsi_low_synch(struct scsi_low_softc *); static int scsi_low_wide(struct scsi_low_softc *); static int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *); static int scsi_low_msginfunc_rejop(struct scsi_low_softc *); static int scsi_low_msginfunc_rp(struct scsi_low_softc *); static int scsi_low_msginfunc_sdp(struct scsi_low_softc *); static int scsi_low_msginfunc_disc(struct scsi_low_softc *); static int scsi_low_msginfunc_cc(struct scsi_low_softc *); static int scsi_low_msginfunc_lcc(struct scsi_low_softc *); static int scsi_low_msginfunc_parity(struct scsi_low_softc *); static int scsi_low_msginfunc_noop(struct scsi_low_softc *); static int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *); static int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *); struct scsi_low_msgin_data { u_int md_len; int (*md_msgfunc)(struct scsi_low_softc *); }; struct scsi_low_msgin_data scsi_low_msgin_data[] = { /* 0 */ {1, scsi_low_msginfunc_cc}, /* 1 */ {2, scsi_low_msginfunc_ext}, /* 2 */ {1, scsi_low_msginfunc_sdp}, /* 3 */ {1, scsi_low_msginfunc_rp}, /* 4 */ {1, scsi_low_msginfunc_disc}, /* 5 */ {1, scsi_low_msginfunc_rejop}, /* 6 */ {1, scsi_low_msginfunc_rejop}, /* 7 */ {1, scsi_low_msginfunc_msg_reject}, /* 8 */ {1, scsi_low_msginfunc_noop}, /* 9 */ {1, scsi_low_msginfunc_parity}, /* a */ {1, scsi_low_msginfunc_lcc}, /* b */ {1, scsi_low_msginfunc_lcc}, /* c */ {1, scsi_low_msginfunc_rejop}, /* d */ {2, scsi_low_msginfunc_rejop}, /* e */ {1, scsi_low_msginfunc_rejop}, /* f */ {1, scsi_low_msginfunc_rejop}, /* 0x10 */ {1, scsi_low_msginfunc_rejop}, /* 0x11 */ {1, scsi_low_msginfunc_rejop}, /* 0x12 */ {1, scsi_low_msginfunc_rejop}, /* 0x13 */ {1, scsi_low_msginfunc_rejop}, /* 0x14 */ {1, scsi_low_msginfunc_rejop}, /* 0x15 */ {1, scsi_low_msginfunc_rejop}, /* 0x16 */ {1, scsi_low_msginfunc_rejop}, /* 0x17 */ {1, scsi_low_msginfunc_rejop}, /* 0x18 */ {1, scsi_low_msginfunc_rejop}, /* 0x19 */ {1, scsi_low_msginfunc_rejop}, /* 0x1a */ {1, scsi_low_msginfunc_rejop}, /* 0x1b */ {1, scsi_low_msginfunc_rejop}, /* 0x1c */ {1, scsi_low_msginfunc_rejop}, /* 0x1d */ {1, scsi_low_msginfunc_rejop}, /* 0x1e */ {1, scsi_low_msginfunc_rejop}, /* 0x1f */ {1, scsi_low_msginfunc_rejop}, /* 0x20 */ {2, scsi_low_msginfunc_simple_qtag}, /* 0x21 */ {2, scsi_low_msginfunc_rejop}, /* 0x22 */ {2, scsi_low_msginfunc_rejop}, /* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue}, /* 0x24 */ {2, scsi_low_msginfunc_rejop}, /* 0x25 */ {2, scsi_low_msginfunc_rejop}, /* 0x26 */ {2, scsi_low_msginfunc_rejop}, /* 0x27 */ {2, scsi_low_msginfunc_rejop}, /* 0x28 */ {2, scsi_low_msginfunc_rejop}, /* 0x29 */ {2, scsi_low_msginfunc_rejop}, /* 0x2a */ {2, scsi_low_msginfunc_rejop}, /* 0x2b */ {2, scsi_low_msginfunc_rejop}, /* 0x2c */ {2, scsi_low_msginfunc_rejop}, /* 0x2d */ {2, scsi_low_msginfunc_rejop}, /* 0x2e */ {2, scsi_low_msginfunc_rejop}, /* 0x2f */ {2, scsi_low_msginfunc_rejop}, /* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ }; /************************************************************** * msgout **************************************************************/ static int scsi_low_msgfunc_synch(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; int ptr = ti->ti_msgoutlen; ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period; ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset; return MSG_EXTEND_SYNCHLEN + 2; } static int scsi_low_msgfunc_wide(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; int ptr = ti->ti_msgoutlen; ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; ti->ti_msgoutstr[ptr + 3] = ti->ti_width; return MSG_EXTEND_WIDELEN + 2; } static int scsi_low_msgfunc_identify(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; struct lun_info *li = slp->sl_Lnexus; struct slccb *cb = slp->sl_Qnexus; int ptr = ti->ti_msgoutlen; u_int8_t msg; msg = MSG_IDENTIFY; if (cb == NULL) { slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown"); } else { if (scsi_low_is_disconnect_ok(cb) != 0) msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun); else msg |= li->li_lun; if (ti->ti_phase == PH_MSGOUT) { (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); if (cb->ccb_tag == SCSI_LOW_UNKTAG) { (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); } } } ti->ti_msgoutstr[ptr + 0] = msg; return 1; } static int scsi_low_msgfunc_abort(slp) struct scsi_low_softc *slp; { SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT); return 1; } static int scsi_low_msgfunc_qabort(slp) struct scsi_low_softc *slp; { SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM); return 1; } static int scsi_low_msgfunc_reset(slp) struct scsi_low_softc *slp; { SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET); return 1; } static int scsi_low_msgfunc_qtag(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; struct slccb *cb = slp->sl_Qnexus; int ptr = ti->ti_msgoutlen; if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG) { ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; return 1; } else { ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag; if (ti->ti_phase == PH_MSGOUT) { (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); } } return 2; } /* * The following functions are called when targets give unexpected * responces in msgin (after msgout). */ static int scsi_low_errfunc_identify(slp, msgflags) struct scsi_low_softc *slp; u_int msgflags; { if (slp->sl_Lnexus != NULL) { slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC; scsi_low_calcf_lun(slp->sl_Lnexus); } return 0; } static int scsi_low_errfunc_synch(slp, msgflags) struct scsi_low_softc *slp; u_int msgflags; { struct targ_info *ti = slp->sl_Tnexus; MSGIN_PERIOD(ti) = 0; MSGIN_OFFSET(ti) = 0; scsi_low_synch(slp); return 0; } static int scsi_low_errfunc_wide(slp, msgflags) struct scsi_low_softc *slp; u_int msgflags; { struct targ_info *ti = slp->sl_Tnexus; MSGIN_WIDTHP(ti) = 0; scsi_low_wide(slp); return 0; } static int scsi_low_errfunc_qtag(slp, msgflags) struct scsi_low_softc *slp; u_int msgflags; { if ((msgflags & SCSI_LOW_MSG_REJECT) != 0) { if (slp->sl_Qnexus != NULL) { scsi_low_deactivate_qtag(slp->sl_Qnexus); } if (slp->sl_Lnexus != NULL) { slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG; scsi_low_calcf_lun(slp->sl_Lnexus); } device_printf(slp->sl_dev, "scsi_low: qtag msg rejected\n"); } return 0; } int scsi_low_msgout(slp, ti, fl) struct scsi_low_softc *slp; struct targ_info *ti; u_int fl; { struct scsi_low_msgout_data *mdp; int len = 0; #ifdef SCSI_LOW_DIAGNOSTIC if (ti != slp->sl_Tnexus) { scsi_low_print(slp, NULL); panic("scsi_low_msgout: Target nexus inconsistent"); } #endif /* SCSI_LOW_DIAGNOSTIC */ slp->sl_ph_count ++; if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) { device_printf(slp->sl_dev, "too many phase changes\n"); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); } /* STEP I. * Scsi phase changes. * Previously msgs asserted are accepted by our target or * processed by scsi_low_msgin. * Thus clear all saved informations. */ if ((fl & SCSI_LOW_MSGOUT_INIT) != 0) { ti->ti_omsgflags = 0; ti->ti_emsgflags = 0; } else if (slp->sl_atten == 0) { /* STEP II. * We did not assert attention, however still our target required * msgs. Resend previous msgs. */ ti->ti_msgflags |= ti->ti_omsgflags; ti->ti_omsgflags = 0; #ifdef SCSI_LOW_DIAGNOSTIC device_printf(slp->sl_dev, "scsi_low_msgout: retry msgout\n"); #endif /* SCSI_LOW_DIAGNOSTIC */ } /* STEP III. * We have no msgs. send MSG_NOOP (OK?) */ if (scsi_low_is_msgout_continue(ti, 0) == 0) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); /* STEP IV. * Process all msgs */ ti->ti_msgoutlen = 0; slp->sl_clear_atten = 0; mdp = &scsi_low_msgout_data[0]; for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) { if ((ti->ti_msgflags & mdp->md_flags) != 0) { ti->ti_omsgflags |= mdp->md_flags; ti->ti_msgflags &= ~mdp->md_flags; ti->ti_emsgflags = mdp->md_flags; ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; if (mdp->md_msgfunc != NULL) len = (*mdp->md_msgfunc) (slp); else len = 1; #ifdef SCSI_LOW_DIAGNOSTIC scsi_low_msg_log_write(&ti->ti_log_msgout, &ti->ti_msgoutstr[ti->ti_msgoutlen], len); #endif /* SCSI_LOW_DIAGNOSTIC */ ti->ti_msgoutlen += len; if ((mdp->md_condition & MSG_RELEASE_ATN) != 0) { slp->sl_clear_atten = 1; break; } if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 || ti->ti_msgflags == 0) break; if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) break; } } if (scsi_low_is_msgout_continue(ti, 0) == 0) slp->sl_clear_atten = 1; return ti->ti_msgoutlen; } /************************************************************** * msgin **************************************************************/ static int scsi_low_msginfunc_noop(slp) struct scsi_low_softc *slp; { return 0; } static int scsi_low_msginfunc_rejop(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; u_int8_t msg = ti->ti_msgin[0]; device_printf(slp->sl_dev, "MSGIN: msg 0x%x rejected\n", (u_int) msg); scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); return 0; } static int scsi_low_msginfunc_cc(slp) struct scsi_low_softc *slp; { struct lun_info *li; SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); /* validate status */ if (slp->sl_Qnexus == NULL) return ENOENT; slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status; li = slp->sl_Lnexus; switch (slp->sl_scp.scp_status) { case ST_GOOD: li->li_maxnqio = li->li_maxnexus; break; case ST_CHKCOND: li->li_maxnqio = 0; if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR) scsi_low_reset_nexus_lun(slp, li, 0); break; case ST_BUSY: li->li_maxnqio = 0; break; case ST_QUEFULL: if (li->li_maxnexus >= li->li_nqio) li->li_maxnexus = li->li_nqio - 1; li->li_maxnqio = li->li_maxnexus; break; case ST_INTERGOOD: case ST_INTERMET: slp->sl_error |= MSGERR; break; default: break; } return 0; } static int scsi_low_msginfunc_lcc(slp) struct scsi_low_softc *slp; { struct targ_info *ti; struct lun_info *li; struct slccb *ncb, *cb; ti = slp->sl_Tnexus; li = slp->sl_Lnexus; if ((cb = slp->sl_Qnexus) == NULL) goto bad; cb->ccb_sscp.scp_status = slp->sl_scp.scp_status; switch (slp->sl_scp.scp_status) { case ST_INTERGOOD: case ST_INTERMET: li->li_maxnqio = li->li_maxnexus; break; default: slp->sl_error |= MSGERR; break; } if ((li->li_flags & SCSI_LOW_LINK) == 0) goto bad; cb->ccb_error |= slp->sl_error; if (cb->ccb_error != 0) goto bad; for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL; ncb = TAILQ_NEXT(ncb, ccb_chain)) { if (ncb->li == li) goto cmd_link_start; } bad: SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM); scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); return EIO; cmd_link_start: ncb->ccb_flags &= ~CCB_STARTQ; TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain); scsi_low_dealloc_qtag(ncb); ncb->ccb_tag = cb->ccb_tag; ncb->ccb_otag = cb->ccb_otag; cb->ccb_tag = SCSI_LOW_UNKTAG; cb->ccb_otag = SCSI_LOW_UNKTAG; if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) panic("%s: linked ccb retried", device_get_nameunit(slp->sl_dev)); slp->sl_Qnexus = ncb; slp->sl_ph_count = 0; ncb->ccb_error = 0; ncb->ccb_datalen = -1; ncb->ccb_scp.scp_status = ST_UNKNOWN; ncb->ccb_flags &= ~CCB_INTERNAL; scsi_low_init_msgsys(slp, ti); - (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb); + scsi_low_ccb_setup_cam(slp, ncb); if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT) ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT; ncb->ccb_tc = ncb->ccb_tcmax; /* setup saved scsi data pointer */ ncb->ccb_sscp = ncb->ccb_scp; slp->sl_scp = ncb->ccb_sscp; slp->sl_error = ncb->ccb_error; #ifdef SCSI_LOW_DIAGNOSTIC scsi_low_msg_log_init(&ti->ti_log_msgin); scsi_low_msg_log_init(&ti->ti_log_msgout); #endif /* SCSI_LOW_DIAGNOSTIC */ return EJUSTRETURN; } static int scsi_low_msginfunc_disc(slp) struct scsi_low_softc *slp; { SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); return 0; } static int scsi_low_msginfunc_sdp(slp) struct scsi_low_softc *slp; { struct slccb *cb = slp->sl_Qnexus; if (cb != NULL) { cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen; cb->ccb_sscp.scp_data = slp->sl_scp.scp_data; } else scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); return 0; } static int scsi_low_msginfunc_rp(slp) struct scsi_low_softc *slp; { if (slp->sl_Qnexus != NULL) slp->sl_scp = slp->sl_Qnexus->ccb_sscp; else scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); return 0; } static int scsi_low_synch(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; u_int period = 0, offset = 0, speed; u_char *s; int error; if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period && MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) || MSGIN_OFFSET(ti) == 0) { if ((offset = MSGIN_OFFSET(ti)) != 0) period = MSGIN_PERIOD(ti); s = offset ? "synchronous" : "async"; } else { /* XXX: * Target seems to be brain damaged. * Force async transfer. */ ti->ti_maxsynch.period = 0; ti->ti_maxsynch.offset = 0; device_printf(slp->sl_dev, "target brain damaged. async transfer\n"); return EINVAL; } ti->ti_maxsynch.period = period; ti->ti_maxsynch.offset = offset; error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); if (error != 0) { /* XXX: * Current period and offset are not acceptable * for our adapter. * The adapter changes max synch and max offset. */ device_printf(slp->sl_dev, "synch neg failed. retry synch msg neg ...\n"); return error; } ti->ti_osynch = ti->ti_maxsynch; if (offset > 0) { ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH; } /* inform data */ if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0) { #ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE struct slccb *cb = slp->sl_Qnexus; if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) return 0; #endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ device_printf(slp->sl_dev, "(%d:*): <%s> offset %d period %dns ", ti->ti_id, s, offset, period * 4); if (period != 0) { speed = 1000 * 10 / (period * 4); printf("%d.%d M/s", speed / 10, speed % 10); } printf("\n"); } return 0; } static int scsi_low_wide(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; int error; ti->ti_width = MSGIN_WIDTHP(ti); error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE); if (error != 0) { /* XXX: * Current width is not acceptable for our adapter. * The adapter changes max width. */ device_printf(slp->sl_dev, "wide neg failed. retry wide msg neg ...\n"); return error; } ti->ti_owidth = ti->ti_width; if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) { ti->ti_setup_msg_done |= (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE); } /* inform data */ if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0) { #ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE struct slccb *cb = slp->sl_Qnexus; if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) return 0; #endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ device_printf(slp->sl_dev, "(%d:*): transfer width %d bits\n", ti->ti_id, 1 << (3 + ti->ti_width)); } return 0; } static int scsi_low_msginfunc_simple_qtag(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1]; if (slp->sl_Qnexus != NULL) { if (slp->sl_Qnexus->ccb_tag != etag) { slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch"); } } else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL) { #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id)) return 0; #endif /* SCSI_LOW_DEBUG */ slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0); SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found"); } return 0; } static int scsi_low_msginfunc_i_wide_residue(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; struct slccb *cb = slp->sl_Qnexus; int res = (int) ti->ti_msgin[1]; if (cb == NULL || res <= 0 || (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) || (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3)) return EINVAL; if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen) return EINVAL; slp->sl_scp.scp_datalen += res; slp->sl_scp.scp_data -= res; scsi_low_data_finish(slp); return 0; } static int scsi_low_msginfunc_ext(slp) struct scsi_low_softc *slp; { struct slccb *cb = slp->sl_Qnexus; struct lun_info *li = slp->sl_Lnexus; struct targ_info *ti = slp->sl_Tnexus; int count, retry; u_int32_t *ptr; if (ti->ti_msginptr == 2) { ti->ti_msginlen = ti->ti_msgin[1] + 2; return 0; } switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) { case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): if (cb == NULL) break; ptr = (u_int32_t *)(&ti->ti_msgin[3]); count = (int) htonl((long) (*ptr)); if(slp->sl_scp.scp_datalen - count < 0 || slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) break; slp->sl_scp.scp_datalen -= count; slp->sl_scp.scp_data += count; return 0; case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): if (li == NULL) break; retry = scsi_low_synch(slp); if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) { scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH); } #endif /* SCSI_LOW_DEBUG */ return 0; case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): if (li == NULL) break; retry = scsi_low_wide(slp); if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); return 0; default: break; } scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); return EINVAL; } static int scsi_low_msginfunc_parity(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; /* only I -> T, invalid! */ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); return 0; } static int scsi_low_msginfunc_msg_reject(slp) struct scsi_low_softc *slp; { struct targ_info *ti = slp->sl_Tnexus; struct scsi_low_msgout_data *mdp; u_int msgflags; if (ti->ti_emsgflags != 0) { device_printf(slp->sl_dev, "msg flags [0x%x] rejected\n", ti->ti_emsgflags); msgflags = SCSI_LOW_MSG_REJECT; mdp = &scsi_low_msgout_data[0]; for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) { if ((ti->ti_emsgflags & mdp->md_flags) != 0) { ti->ti_emsgflags &= ~mdp->md_flags; if (mdp->md_errfunc != NULL) (*mdp->md_errfunc) (slp, msgflags); break; } } return 0; } else { SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found"); slp->sl_error |= MSGERR; } return EINVAL; } int scsi_low_msgin(slp, ti, c) struct scsi_low_softc *slp; struct targ_info *ti; u_int c; { struct scsi_low_msgin_data *sdp; struct lun_info *li; u_int8_t msg; #ifdef SCSI_LOW_DIAGNOSTIC if (ti != slp->sl_Tnexus) { scsi_low_print(slp, NULL); panic("scsi_low_msgin: Target nexus inconsistent"); } #endif /* SCSI_LOW_DIAGNOSTIC */ /* * Phase changes, clear the pointer. */ if (ti->ti_ophase != ti->ti_phase) { MSGINPTR_CLR(ti); ti->ti_msgin_parity_error = 0; slp->sl_ph_count ++; if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) { device_printf(slp->sl_dev, "too many phase changes\n"); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); } } /* * Store a current messages byte into buffer and * wait for the completion of the current msg. */ ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c; if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) { ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); } /* * Check parity errors. */ if ((c & SCSI_LOW_DATA_PE) != 0) { ti->ti_msgin_parity_error ++; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); goto out; } if (ti->ti_msgin_parity_error != 0) goto out; /* * Calculate messages length. */ msg = ti->ti_msgin[0]; if (msg < MSGIN_DATA_LAST) sdp = &scsi_low_msgin_data[msg]; else sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; if (ti->ti_msginlen == 0) { ti->ti_msginlen = sdp->md_len; } /* * Check comletion. */ if (ti->ti_msginptr < ti->ti_msginlen) return EJUSTRETURN; /* * Do process. */ if ((msg & MSG_IDENTIFY) == 0) { if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN) return EJUSTRETURN; } else { li = slp->sl_Lnexus; if (li == NULL) { li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0); if (li == NULL) goto badlun; slp->sl_Lnexus = li; (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); } else { if (MSGCMD_LUN(msg) != li->li_lun) goto badlun; } if (slp->sl_Qnexus == NULL && li->li_nqio == 0) { if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) { #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) { goto out; } #endif /* SCSI_LOW_DEBUG */ goto badlun; } } } goto out; /* * Msg process completed, reset msgin pointer and assert ATN if desired. */ badlun: slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong"); out: if (ti->ti_msginptr < ti->ti_msginlen) return EJUSTRETURN; #ifdef SCSI_LOW_DIAGNOSTIC scsi_low_msg_log_write(&ti->ti_log_msgin, &ti->ti_msgin[0], ti->ti_msginlen); #endif /* SCSI_LOW_DIAGNOSTIC */ MSGINPTR_CLR(ti); return 0; } /********************************************************** * disconnect **********************************************************/ int scsi_low_disconnected(slp, ti) struct scsi_low_softc *slp; struct targ_info *ti; { struct slccb *cb = slp->sl_Qnexus; /* check phase completion */ switch (slp->sl_msgphase) { case MSGPH_RESET: scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); scsi_low_msginfunc_cc(slp); scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0); goto io_resume; case MSGPH_ABORT: scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); scsi_low_msginfunc_cc(slp); scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0); goto io_resume; case MSGPH_TERM: scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); scsi_low_msginfunc_cc(slp); goto io_resume; case MSGPH_DISC: if (cb != NULL) { struct lun_info *li; li = cb->li; TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain); cb->ccb_flags |= CCB_DISCQ; cb->ccb_error |= slp->sl_error; li->li_disc ++; ti->ti_disc ++; slp->sl_disc ++; } #ifdef SCSI_LOW_STATICS scsi_low_statics.nexus_disconnected ++; #endif /* SCSI_LOW_STATICS */ #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0) { printf("## SCSI_LOW_DISCONNECTED ===============\n"); scsi_low_print(slp, NULL); } #endif /* SCSI_LOW_DEBUG */ break; case MSGPH_NULL: slp->sl_error |= FATALIO; if (ti->ti_phase == PH_SELSTART) slp->sl_error |= SELTIMEOUTIO; else slp->sl_error |= UBFERR; /* fall through */ case MSGPH_LCTERM: case MSGPH_CMDC: io_resume: if (cb == NULL) break; #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) { if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP && (cb->ccb_msgoutflag != 0 || (ti->ti_msgflags & SCSI_LOW_MSG_NOOP))) { scsi_low_info(slp, ti, "ATTEN CHECK FAILED"); } } #endif /* SCSI_LOW_DEBUG */ cb->ccb_error |= slp->sl_error; if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) { cb->ccb_flags |= CCB_STARTQ; TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); } break; } scsi_low_bus_release(slp, ti); scsi_low_start(slp); return 1; } /********************************************************** * TAG operations **********************************************************/ static int scsi_low_alloc_qtag(cb) struct slccb *cb; { struct lun_info *li = cb->li; scsi_low_tag_t etag; if (cb->ccb_otag != SCSI_LOW_UNKTAG) return 0; #ifndef SCSI_LOW_ALT_QTAG_ALLOCATE etag = ffs(li->li_qtagbits); if (etag == 0) return ENOSPC; li->li_qtagbits &= ~(1 << (etag - 1)); cb->ccb_otag = etag; return 0; #else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++) if (li->li_qtagarray[li->li_qd] == 0) goto found; for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++) if (li->li_qtagarray[li->li_qd] == 0) goto found; return ENOSPC; found: li->li_qtagarray[li->li_qd] ++; cb->ccb_otag = (li->li_qd ++); return 0; #endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ } static int scsi_low_dealloc_qtag(cb) struct slccb *cb; { struct lun_info *li = cb->li; scsi_low_tag_t etag; if (cb->ccb_otag == SCSI_LOW_UNKTAG) return 0; #ifndef SCSI_LOW_ALT_QTAG_ALLOCATE etag = cb->ccb_otag - 1; #ifdef SCSI_LOW_DIAGNOSTIC if (etag >= sizeof(li->li_qtagbits) * NBBY) panic("scsi_low_dealloc_tag: illegal tag"); #endif /* SCSI_LOW_DIAGNOSTIC */ li->li_qtagbits |= (1 << etag); #else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ etag = cb->ccb_otag; #ifdef SCSI_LOW_DIAGNOSTIC if (etag >= SCSI_LOW_MAXNEXUS) panic("scsi_low_dealloc_tag: illegal tag"); #endif /* SCSI_LOW_DIAGNOSTIC */ li->li_qtagarray[etag] --; #endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ cb->ccb_otag = SCSI_LOW_UNKTAG; return 0; } static struct slccb * scsi_low_revoke_ccb(slp, cb, fdone) struct scsi_low_softc *slp; struct slccb *cb; int fdone; { struct targ_info *ti = cb->ti; struct lun_info *li = cb->li; #ifdef SCSI_LOW_DIAGNOSTIC if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) == (CCB_STARTQ | CCB_DISCQ)) { panic("%s: ccb in both queue", device_get_nameunit(slp->sl_dev)); } #endif /* SCSI_LOW_DIAGNOSTIC */ if ((cb->ccb_flags & CCB_STARTQ) != 0) { TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); } if ((cb->ccb_flags & CCB_DISCQ) != 0) { TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); li->li_disc --; ti->ti_disc --; slp->sl_disc --; } cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ | CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL); if (fdone != 0 && (cb->ccb_rcnt ++ >= slp->sl_max_retry || (cb->ccb_flags & CCB_NORETRY) != 0)) { cb->ccb_error |= FATALIO; cb->ccb_flags &= ~CCB_AUTOSENSE; if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE) panic("%s: done ccb retried", device_get_nameunit(slp->sl_dev)); return NULL; } else { cb->ccb_error |= PENDINGIO; scsi_low_deactivate_qtag(cb); scsi_low_ccb_message_retry(cb); cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; return cb; } } static void scsi_low_reset_nexus_lun(slp, li, fdone) struct scsi_low_softc *slp; struct lun_info *li; int fdone; { struct slccb *cb, *ncb, *ecb; if (li == NULL) return; ecb = NULL; for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb) { ncb = TAILQ_NEXT(cb, ccb_chain); cb = scsi_low_revoke_ccb(slp, cb, fdone); if (cb != NULL) { /* * presumely keep ordering of io */ cb->ccb_flags |= CCB_STARTQ; if (ecb == NULL) { TAILQ_INSERT_HEAD(&slp->sl_start,\ cb, ccb_chain); } else { TAILQ_INSERT_AFTER(&slp->sl_start,\ ecb, cb, ccb_chain); } ecb = cb; } } } /************************************************************** * Qurik setup **************************************************************/ static void scsi_low_calcf_lun(li) struct lun_info *li; { struct targ_info *ti = li->li_ti; struct scsi_low_softc *slp = ti->ti_sc; u_int cfgflags, diskflags; if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID) cfgflags = li->li_cfgflags; else cfgflags = 0; diskflags = li->li_diskflags & li->li_quirks; /* disconnect */ li->li_flags &= ~SCSI_LOW_DISC; if ((slp->sl_cfgflags & CFG_NODISC) == 0 && (diskflags & SCSI_LOW_DISK_DISC) != 0 && (cfgflags & SCSI_LOW_DISC) != 0) li->li_flags |= SCSI_LOW_DISC; /* parity */ li->li_flags |= SCSI_LOW_NOPARITY; if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && (diskflags & SCSI_LOW_DISK_PARITY) != 0 && (cfgflags & SCSI_LOW_NOPARITY) == 0) li->li_flags &= ~SCSI_LOW_NOPARITY; /* qtag */ if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 && (cfgflags & SCSI_LOW_QTAG) != 0 && (diskflags & SCSI_LOW_DISK_QTAG) != 0) { li->li_flags |= SCSI_LOW_QTAG; li->li_maxnexus = SCSI_LOW_MAXNEXUS; li->li_maxnqio = li->li_maxnexus; } else { li->li_flags &= ~SCSI_LOW_QTAG; li->li_maxnexus = 0; li->li_maxnqio = li->li_maxnexus; } /* cmd link */ li->li_flags &= ~SCSI_LOW_LINK; if ((cfgflags & SCSI_LOW_LINK) != 0 && (diskflags & SCSI_LOW_DISK_LINK) != 0) li->li_flags |= SCSI_LOW_LINK; /* compatible flags */ li->li_flags &= ~SCSI_LOW_SYNC; if (ti->ti_maxsynch.offset > 0) li->li_flags |= SCSI_LOW_SYNC; #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) { scsi_low_calcf_show(li); } #endif /* SCSI_LOW_DEBUG */ } static void scsi_low_calcf_target(ti) struct targ_info *ti; { struct scsi_low_softc *slp = ti->ti_sc; u_int offset, period, diskflags; diskflags = ti->ti_diskflags & ti->ti_quirks; /* synch */ if ((slp->sl_cfgflags & CFG_ASYNC) == 0 && (diskflags & SCSI_LOW_DISK_SYNC) != 0) { offset = ti->ti_maxsynch.offset; period = ti->ti_maxsynch.period; if (offset == 0 || period == 0) offset = period = 0; } else { offset = period = 0; } ti->ti_maxsynch.offset = offset; ti->ti_maxsynch.period = period; /* wide */ if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 && ti->ti_width > SCSI_LOW_BUS_WIDTH_16) ti->ti_width = SCSI_LOW_BUS_WIDTH_16; if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 && ti->ti_width > SCSI_LOW_BUS_WIDTH_8) ti->ti_width = SCSI_LOW_BUS_WIDTH_8; if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID) { if (ti->ti_maxsynch.offset != ti->ti_osynch.offset || ti->ti_maxsynch.period != ti->ti_osynch.period) ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH; if (ti->ti_width != ti->ti_owidth) ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH); ti->ti_osynch = ti->ti_maxsynch; ti->ti_owidth = ti->ti_width; } #ifdef SCSI_LOW_DEBUG if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) { device_printf(slp->sl_dev, "(%d:*): max period(%dns) offset(%d) width(%d)\n", ti->ti_id, ti->ti_maxsynch.period * 4, ti->ti_maxsynch.offset, ti->ti_width); } #endif /* SCSI_LOW_DEBUG */ } static void scsi_low_calcf_show(li) struct lun_info *li; { struct targ_info *ti = li->li_ti; struct scsi_low_softc *slp = ti->ti_sc; device_printf(slp->sl_dev, "(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n", ti->ti_id, li->li_lun, ti->ti_maxsynch.period * 4, ti->ti_maxsynch.offset, ti->ti_width, li->li_flags, SCSI_LOW_BITS); } #ifdef SCSI_LOW_START_UP_CHECK /************************************************************** * scsi world start up **************************************************************/ static int scsi_low_poll(struct scsi_low_softc *, struct slccb *); static int scsi_low_start_up(slp) struct scsi_low_softc *slp; { struct targ_info *ti; struct lun_info *li; struct slccb *cb; int target, lun; device_printf(slp->sl_dev, "scsi_low: probing all devices ....\n"); for (target = 0; target < slp->sl_ntargs; target ++) { if (target == slp->sl_hostid) { if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) { device_printf(slp->sl_dev, "scsi_low: target %d (host card)\n", target); } continue; } if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) { device_printf(slp->sl_dev, "scsi_low: target %d lun ", target); } ti = slp->sl_ti[target]; for (lun = 0; lun < slp->sl_nluns; lun ++) { if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) break; cb->osdep = NULL; cb->bp = NULL; li = scsi_low_alloc_li(ti, lun, 1); scsi_low_enqueue(slp, ti, li, cb, CCB_AUTOSENSE | CCB_POLLED, 0); scsi_low_poll(slp, cb); if (li->li_state != SCSI_LOW_LUN_OK) break; if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) { printf("%d ", lun); } } if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) { printf("\n"); } } return 0; } static int scsi_low_poll(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { int tcount; tcount = 0; while (slp->sl_nio > 0) { DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ); (*slp->sl_funcs->scsi_low_poll) (slp); if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) continue; tcount = 0; scsi_low_timeout_check(slp); } return 0; } #endif /* SCSI_LOW_START_UP_CHECK */ /********************************************************** * DEBUG SECTION **********************************************************/ #ifdef SCSI_LOW_DEBUG static void scsi_low_test_abort(slp, ti, li) struct scsi_low_softc *slp; struct targ_info *ti; struct lun_info *li; { struct slccb *acb; if (li->li_disc > 1) { acb = TAILQ_FIRST(&li->li_discq); if (scsi_low_abort_ccb(slp, acb) == 0) { device_printf(slp->sl_dev, "aborting ccb(0x%lx) start\n", (u_long) acb); } } } static void scsi_low_test_atten(slp, ti, msg) struct scsi_low_softc *slp; struct targ_info *ti; u_int msg; { if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK) scsi_low_assert_msg(slp, ti, msg, 0); else device_printf(slp->sl_dev, "atten check OK\n"); } static void scsi_low_test_cmdlnk(slp, cb) struct scsi_low_softc *slp; struct slccb *cb; { #define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ) if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0) return; memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1; slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd; } #endif /* SCSI_LOW_DEBUG */ /* static */ void scsi_low_info(slp, ti, s) struct scsi_low_softc *slp; struct targ_info *ti; u_char *s; { if (slp == NULL) slp = LIST_FIRST(&sl_tab); if (s == NULL) s = "no message"; printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s); if (ti == NULL) { TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain) { scsi_low_print(slp, ti); } } else { scsi_low_print(slp, ti); } } static u_char *phase[] = { "FREE", "ARBSTART", "SELSTART", "SELECTED", "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" }; void scsi_low_print(slp, ti) struct scsi_low_softc *slp; struct targ_info *ti; { struct lun_info *li; struct slccb *cb; struct sc_p *sp; if (ti == NULL || ti == slp->sl_Tnexus) { ti = slp->sl_Tnexus; li = slp->sl_Lnexus; cb = slp->sl_Qnexus; } else { li = LIST_FIRST(&ti->ti_litab); cb = TAILQ_FIRST(&li->li_discq); } sp = &slp->sl_scp; device_printf(slp->sl_dev, "=== NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n", (u_long) ti, (u_long) li, (u_long) cb, slp->sl_nio); /* target stat */ if (ti != NULL) { u_int flags = 0, maxnqio = 0, nqio = 0; int lun = CAM_LUN_WILDCARD; if (li != NULL) { lun = li->li_lun; flags = li->li_flags; maxnqio = li->li_maxnqio; nqio = li->li_nqio; } device_printf(slp->sl_dev, "(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n", ti->ti_id, lun, phase[(int) ti->ti_ophase], phase[(int) ti->ti_phase], ti->ti_disc, nqio, maxnqio); if (cb != NULL) { printf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n", (u_int) cb->ccb_scp.scp_cmd[0], cb->ccb_scp.scp_cmdlen, cb->ccb_datalen, cb->ccb_scp.scp_datalen, (u_int) cb->ccb_sscp.scp_status, cb->ccb_error, SCSI_LOW_ERRORBITS); } printf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n", (u_int) (ti->ti_msginptr), (u_int) (ti->ti_msgin[0]), (u_int) (ti->ti_msgin[1]), (u_int) (ti->ti_msgin[2]), (u_int) (ti->ti_msgin[3]), (u_int) (ti->ti_msgin[4]), slp->sl_atten); printf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", (u_int) ti->ti_msgflags, (u_int) (ti->ti_msgoutstr[0]), (u_int) (ti->ti_msgoutstr[1]), (u_int) (ti->ti_msgoutstr[2]), (u_int) (ti->ti_msgoutstr[3]), (u_int) (ti->ti_msgoutstr[4]), ti->ti_msgoutlen, flags, SCSI_LOW_BITS); #ifdef SCSI_LOW_DIAGNOSTIC scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2); scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2); #endif /* SCSI_LOW_DIAGNOSTIC */ } printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n", (u_long) sp->scp_data, sp->scp_datalen, (u_int) sp->scp_status, slp->sl_error, SCSI_LOW_ERRORBITS); } diff --git a/sys/cam/scsi/scsi_low.h b/sys/cam/scsi/scsi_low.h index 2cca8ae4f346..8d82eff66343 100644 --- a/sys/cam/scsi/scsi_low.h +++ b/sys/cam/scsi/scsi_low.h @@ -1,825 +1,791 @@ /* $FreeBSD$ */ /* $NecBSD: scsi_low.h,v 1.24.10.5 2001/06/26 07:31:46 honda Exp $ */ /* $NetBSD$ */ #define SCSI_LOW_DIAGNOSTIC #define SCSI_LOW_ALT_QTAG_ALLOCATE /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * [Ported for FreeBSD CAM] * Copyright (c) 2000, 2001 * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SCSI_LOW_H_ #define _SCSI_LOW_H_ -/*================================================ - * Scsi low OSDEP - * (All os depend structures should be here!) - ================================================*/ /******** includes *******************************/ #include #include #include #include #include #include #include #include #include /******** functions macro ************************/ #undef MSG_IDENTIFY -/******** os depend interface structures **********/ -typedef struct scsi_sense_data scsi_low_osdep_sense_data_t; - -struct scsi_low_osdep_interface { - device_t si_dev; - - struct cam_sim *sim; - struct cam_path *path; - - int si_poll_count; - - struct callout_handle engage_ch; - struct callout_handle timeout_ch; -#ifdef SCSI_LOW_POWFUNC - struct callout_handle recover_ch; -#endif -}; - -/******** os depend interface functions *************/ -struct slccb; -struct scsi_low_softc; -#define SCSI_LOW_TIMEOUT_STOP 0 -#define SCSI_LOW_TIMEOUT_START 1 -#define SCSI_LOW_TIMEOUT_CH_IO 0 -#define SCSI_LOW_TIMEOUT_CH_ENGAGE 1 -#define SCSI_LOW_TIMEOUT_CH_RECOVER 2 - -struct scsi_low_osdep_funcs { - int (*scsi_low_osdep_attach) \ - (struct scsi_low_softc *); - int (*scsi_low_osdep_world_start) \ - (struct scsi_low_softc *); - int (*scsi_low_osdep_dettach) \ - (struct scsi_low_softc *); - int (*scsi_low_osdep_ccb_setup) \ - (struct scsi_low_softc *, struct slccb *); - int (*scsi_low_osdep_done) \ - (struct scsi_low_softc *, struct slccb *); - void (*scsi_low_osdep_timeout) \ - (struct scsi_low_softc *, int, int); -}; - /*================================================ * Generic Scsi Low header file - * (All os depend structures should be above!) ================================================*/ /************************************************* * Scsi low definitions *************************************************/ #define SCSI_LOW_SYNC DVF_SCSI_SYNC #define SCSI_LOW_DISC DVF_SCSI_DISC #define SCSI_LOW_WAIT DVF_SCSI_WAIT #define SCSI_LOW_LINK DVF_SCSI_LINK #define SCSI_LOW_QTAG DVF_SCSI_QTAG #define SCSI_LOW_NOPARITY DVF_SCSI_NOPARITY #define SCSI_LOW_SAVESP DVF_SCSI_SAVESP #define SCSI_LOW_DEFCFG DVF_SCSI_DEFCFG #define SCSI_LOW_BITS DVF_SCSI_BITS #define SCSI_LOW_PERIOD(n) DVF_SCSI_PERIOD(n) #define SCSI_LOW_OFFSET(n) DVF_SCSI_OFFSET(n) /* host scsi id and targets macro */ #ifndef SCSI_LOW_NTARGETS #define SCSI_LOW_NTARGETS 8 #endif /* SCSI_LOW_NTARGETS */ #define SCSI_LOW_NCCB 128 #define SCSI_LOW_MAX_RETRY 3 #define SCSI_LOW_MAX_SELECTION_RETRY 10 /* timeout control macro */ #define SCSI_LOW_TIMEOUT_HZ 10 #define SCSI_LOW_MIN_TOUT 12 #define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 1 #define SCSI_LOW_POWDOWN_TC 15 #define SCSI_LOW_MAX_PHCHANGES 256 #define SCSI2_RESET_DELAY 5000000 /* msg */ #define SCSI_LOW_MAX_MSGLEN 32 #define SCSI_LOW_MSG_LOG_DATALEN 8 /************************************************* * Scsi Data Pointer *************************************************/ /* scsi pointer */ struct sc_p { u_int8_t *scp_data; int scp_datalen; u_int8_t *scp_cmd; int scp_cmdlen; u_int8_t scp_direction; #define SCSI_LOW_RWUNK (-1) #define SCSI_LOW_WRITE 0 #define SCSI_LOW_READ 1 u_int8_t scp_status; u_int8_t scp_spare[2]; }; /************************************************* * Command Control Block Structure *************************************************/ typedef int scsi_low_tag_t; struct targ_info; #define SCSI_LOW_UNKLUN ((u_int) -1) #define SCSI_LOW_UNKTAG ((scsi_low_tag_t) -1) struct slccb { TAILQ_ENTRY(slccb) ccb_chain; void *osdep; /* os depend structure */ struct targ_info *ti; /* targ_info */ struct lun_info *li; /* lun info */ struct buf *bp; /* io bufs */ scsi_low_tag_t ccb_tag; /* effective qtag */ scsi_low_tag_t ccb_otag; /* allocated qtag */ /***************************************** * Scsi data pointers (original and saved) *****************************************/ struct sc_p ccb_scp; /* given */ struct sc_p ccb_sscp; /* saved scsi data pointer */ int ccb_datalen; /* transfered data counter */ /***************************************** * Msgout *****************************************/ u_int ccb_msgoutflag; u_int ccb_omsgoutflag; /***************************************** * Error or Timeout counters *****************************************/ u_int ccb_flags; #define CCB_INTERNAL 0x0001 #define CCB_SENSE 0x0002 #define CCB_CLEARQ 0x0004 #define CCB_DISCQ 0x0008 #define CCB_STARTQ 0x0010 #define CCB_POLLED 0x0100 /* polling ccb */ #define CCB_NORETRY 0x0200 /* do NOT retry */ #define CCB_AUTOSENSE 0x0400 /* do a sence after CA */ #define CCB_URGENT 0x0800 /* an urgent ccb */ #define CCB_NOSDONE 0x1000 /* do not call an os done routine */ #define CCB_SCSIIO 0x2000 /* a normal scsi io coming from upper layer */ #define CCB_SILENT 0x4000 /* no terminate messages */ u_int ccb_error; int ccb_rcnt; /* retry counter */ int ccb_selrcnt; /* selection retry counter */ int ccb_tc; /* timer counter */ int ccb_tcmax; /* max timeout */ /***************************************** * Sense data buffer *****************************************/ u_int8_t ccb_scsi_cmd[12]; - scsi_low_osdep_sense_data_t ccb_sense; + struct scsi_sense_data ccb_sense; }; /************************************************* * Slccb functions *************************************************/ GENERIC_CCB_ASSERT(scsi_low, slccb) /************************************************* * Target and Lun structures *************************************************/ struct scsi_low_softc; LIST_HEAD(scsi_low_softc_tab, scsi_low_softc); TAILQ_HEAD(targ_info_tab, targ_info); LIST_HEAD(lun_info_tab, lun_info); struct lun_info { int li_lun; struct targ_info *li_ti; /* my target */ LIST_ENTRY(lun_info) lun_chain; /* targ_info link */ struct slccbtab li_discq; /* disconnect queue */ /* * qtag control */ int li_maxnexus; int li_maxnqio; int li_nqio; int li_disc; #define SCSI_LOW_MAXNEXUS (sizeof(u_int) * NBBY) u_int li_qtagbits; #ifdef SCSI_LOW_ALT_QTAG_ALLOCATE u_int8_t li_qtagarray[SCSI_LOW_MAXNEXUS]; u_int li_qd; #endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ #define SCSI_LOW_QFLAG_CA_QCLEAR 0x01 u_int li_qflags; /* * lun state */ #define SCSI_LOW_LUN_SLEEP 0x00 #define SCSI_LOW_LUN_START 0x01 #define SCSI_LOW_LUN_INQ 0x02 #define SCSI_LOW_LUN_MODEQ 0x03 #define SCSI_LOW_LUN_OK 0x04 u_int li_state; /* target lun state */ /* * lun control flags */ u_int li_flags_valid; /* valid flags */ #define SCSI_LOW_LUN_FLAGS_USER_VALID 0x0001 #define SCSI_LOW_LUN_FLAGS_DISK_VALID 0x0002 #define SCSI_LOW_LUN_FLAGS_QUIRKS_VALID 0x0004 #define SCSI_LOW_LUN_FLAGS_ALL_VALID \ (SCSI_LOW_LUN_FLAGS_USER_VALID | \ SCSI_LOW_LUN_FLAGS_DISK_VALID | SCSI_LOW_LUN_FLAGS_QUIRKS_VALID) u_int li_flags; /* real lun control flags */ u_int li_cfgflags; /* lun control flags given by user */ u_int li_diskflags; /* lun control flags given by hardware info */ u_int li_quirks; /* lun control flags given by upper layer */ /* inq buffer */ struct scsi_low_inq_data { u_int8_t sd_type; u_int8_t sd_sp1; u_int8_t sd_version; u_int8_t sd_resp; u_int8_t sd_len; u_int8_t sd_sp2[2]; u_int8_t sd_support; } __packed li_inq; /* modeq buffer */ struct scsi_low_mode_sense_data { u_int8_t sms_header[4]; struct { u_int8_t cmp_page; u_int8_t cmp_length; u_int8_t cmp_rlec; u_int8_t cmp_qc; u_int8_t cmp_eca; u_int8_t cmp_spare[3]; } __packed sms_cmp; } li_sms; }; struct scsi_low_msg_log { int slml_ptr; struct { u_int8_t msg[2]; } slml_msg[SCSI_LOW_MSG_LOG_DATALEN]; }; struct targ_info { TAILQ_ENTRY(targ_info) ti_chain; /* targ_info link */ struct scsi_low_softc *ti_sc; /* our softc */ u_int ti_id; /* scsi id */ /* * Lun chain */ struct lun_info_tab ti_litab; /* lun chain */ /* * total disconnected nexus */ int ti_disc; /* * Scsi phase control */ #define PH_NULL 0x00 #define PH_ARBSTART 0x01 #define PH_SELSTART 0x02 #define PH_SELECTED 0x03 #define PH_CMD 0x04 #define PH_DATA 0x05 #define PH_MSGIN 0x06 #define PH_MSGOUT 0x07 #define PH_STAT 0x08 #define PH_DISC 0x09 #define PH_RESEL 0x0a u_int ti_phase; /* scsi phase */ u_int ti_ophase; /* old scsi phase */ /* * Msg in */ u_int ti_msginptr; /* msgin ptr */ u_int ti_msginlen; /* expected msg length */ int ti_msgin_parity_error; /* parity error detected */ u_int8_t ti_msgin[SCSI_LOW_MAX_MSGLEN]; /* msgin buffer */ /* * Msg out */ u_int ti_msgflags; /* msgs to be asserted */ u_int ti_omsgflags; /* msgs asserted */ u_int ti_emsgflags; /* a msg currently asserted */ #define SCSI_LOW_MSG_RESET 0x00000001 #define SCSI_LOW_MSG_REJECT 0x00000002 #define SCSI_LOW_MSG_PARITY 0x00000004 #define SCSI_LOW_MSG_ERROR 0x00000008 #define SCSI_LOW_MSG_IDENTIFY 0x00000010 #define SCSI_LOW_MSG_ABORT 0x00000020 #define SCSI_LOW_MSG_TERMIO 0x00000040 #define SCSI_LOW_MSG_SIMPLE_QTAG 0x00000080 #define SCSI_LOW_MSG_ORDERED_QTAG 0x00000100 #define SCSI_LOW_MSG_HEAD_QTAG 0x00000200 #define SCSI_LOW_MSG_ABORT_QTAG 0x00000400 #define SCSI_LOW_MSG_CLEAR_QTAG 0x00000800 #define SCSI_LOW_MSG_WIDE 0x00001000 #define SCSI_LOW_MSG_SYNCH 0x00002000 #define SCSI_LOW_MSG_NOOP 0x00004000 #define SCSI_LOW_MSG_LAST 0x00008000 #define SCSI_LOW_MSG_ALL 0xffffffff /* msgout buffer */ u_int8_t ti_msgoutstr[SCSI_LOW_MAX_MSGLEN]; /* scsi msgout */ u_int ti_msgoutlen; /* msgout strlen */ /* * target initialize msgout */ u_int ti_setup_msg; /* setup msgout requests */ u_int ti_setup_msg_done; /* * synch and wide data info */ u_int ti_flags_valid; /* valid flags */ #define SCSI_LOW_TARG_FLAGS_USER_VALID 0x0001 #define SCSI_LOW_TARG_FLAGS_DISK_VALID 0x0002 #define SCSI_LOW_TARG_FLAGS_QUIRKS_VALID 0x0004 #define SCSI_LOW_TARG_FLAGS_ALL_VALID \ (SCSI_LOW_TARG_FLAGS_USER_VALID | \ SCSI_LOW_TARG_FLAGS_DISK_VALID | SCSI_LOW_TARG_FLAGS_QUIRKS_VALID) u_int ti_diskflags; /* given target disk flags */ u_int ti_quirks; /* given target quirk */ struct synch { u_int8_t offset; u_int8_t period; } ti_osynch, ti_maxsynch; /* synch data */ #define SCSI_LOW_BUS_WIDTH_8 0 #define SCSI_LOW_BUS_WIDTH_16 1 #define SCSI_LOW_BUS_WIDTH_32 2 u_int ti_owidth, ti_width; /* * lun info size. */ int ti_lunsize; #ifdef SCSI_LOW_DIAGNOSTIC struct scsi_low_msg_log ti_log_msgout; struct scsi_low_msg_log ti_log_msgin; #endif /* SCSI_LOW_DIAGNOSTIC */ }; /************************************************* * COMMON HEADER STRUCTURE *************************************************/ struct scsi_low_softc; struct proc; typedef struct scsi_low_softc *sc_low_t; #define SCSI_LOW_START_OK 0 #define SCSI_LOW_START_FAIL 1 #define SCSI_LOW_INFO_ALLOC 0 #define SCSI_LOW_INFO_REVOKE 1 #define SCSI_LOW_INFO_DEALLOC 2 #define SCSI_LOW_POWDOWN 1 #define SCSI_LOW_ENGAGE 2 #define SC_LOW_INIT_T (int (*)(sc_low_t, int)) #define SC_LOW_BUSRST_T (void (*)(sc_low_t)) #define SC_LOW_TARG_INIT_T (int (*)(sc_low_t, struct targ_info *, int)) #define SC_LOW_LUN_INIT_T (int (*)(sc_low_t, struct targ_info *, struct lun_info *, int)) #define SC_LOW_SELECT_T (int (*)(sc_low_t, struct slccb *)) #define SC_LOW_ATTEN_T (void (*)(sc_low_t)) #define SC_LOW_NEXUS_T (int (*)(sc_low_t)) #define SC_LOW_MSG_T (int (*)(sc_low_t, struct targ_info *, u_int)) #define SC_LOW_POLL_T (int (*)(void *)) #define SC_LOW_POWER_T (int (*)(sc_low_t, u_int)) #define SC_LOW_TIMEOUT_T (int (*)(sc_low_t)) struct scsi_low_funcs { int (*scsi_low_init)(sc_low_t, int); void (*scsi_low_bus_reset)(sc_low_t); int (*scsi_low_targ_init)(sc_low_t, struct targ_info *, int); int (*scsi_low_lun_init)(sc_low_t, struct targ_info *, struct lun_info *, int); int (*scsi_low_start_bus)(sc_low_t, struct slccb *); int (*scsi_low_establish_lun_nexus)(sc_low_t); int (*scsi_low_establish_ccb_nexus)(sc_low_t); void (*scsi_low_attention)(sc_low_t); int (*scsi_low_msg)(sc_low_t, struct targ_info *, u_int); int (*scsi_low_timeout)(sc_low_t); int (*scsi_low_poll)(void *); int (*scsi_low_power)(sc_low_t, u_int); int (*scsi_low_ioctl)(sc_low_t, u_long, caddr_t, int, struct proc *); }; struct scsi_low_softc { - /* os depend structure */ - struct scsi_low_osdep_interface sl_si; -#define sl_dev sl_si.si_dev - struct scsi_low_osdep_funcs *sl_osdep_fp; + device_t sl_dev; + + struct cam_sim *sl_sim; + struct cam_path *sl_path; + + int sl_poll_count; + + struct mtx sl_lock; + struct callout sl_engage_timer; + struct callout sl_timeout_timer; +#ifdef SCSI_LOW_POWFUNC + struct callout sl_recover_timer; +#endif /* our chain */ LIST_ENTRY(scsi_low_softc) sl_chain; /* my targets */ struct targ_info *sl_ti[SCSI_LOW_NTARGETS]; struct targ_info_tab sl_titab; /* current active T_L_Q nexus */ struct targ_info *sl_Tnexus; /* Target nexus */ struct lun_info *sl_Lnexus; /* Lun nexus */ struct slccb *sl_Qnexus; /* Qtag nexus */ int sl_nexus_call; /* ccb start queue */ struct slccbtab sl_start; /* retry limit and phase change counter */ int sl_max_retry; int sl_ph_count; int sl_timeout_count; /* selection & total num disconnect targets */ int sl_nio; int sl_disc; int sl_retry_sel; struct slccb *sl_selid; /* attention */ int sl_atten; /* ATN asserted */ int sl_clear_atten; /* negate ATN required */ /* scsi phase suggested by scsi msg */ u_int sl_msgphase; #define MSGPH_NULL 0x00 /* no msg */ #define MSGPH_DISC 0x01 /* disconnect msg */ #define MSGPH_CMDC 0x02 /* cmd complete msg */ #define MSGPH_ABORT 0x03 /* abort seq */ #define MSGPH_TERM 0x04 /* current io terminate */ #define MSGPH_LCTERM 0x05 /* cmd link terminated */ #define MSGPH_RESET 0x06 /* reset target */ /* error */ u_int sl_error; /* error flags */ #define FATALIO 0x0001 /* generic io error & retry io */ #define ABORTIO 0x0002 /* generic io error & terminate io */ #define TIMEOUTIO 0x0004 /* watch dog timeout */ #define SELTIMEOUTIO 0x0008 /* selection timeout */ #define PDMAERR 0x0010 /* dma xfer error */ #define MSGERR 0x0020 /* msgsys error */ #define PARITYERR 0x0040 /* parity error */ #define BUSYERR 0x0080 /* target busy error */ #define STATERR 0x0100 /* status error */ #define UACAERR 0x0200 /* target CA state, no sense check */ #define SENSEIO 0x1000 /* cmd not excuted but sense data ok */ #define SENSEERR 0x2000 /* cmd not excuted and sense data bad */ #define UBFERR 0x4000 /* unexpected bus free */ #define PENDINGIO 0x8000 /* ccb start not yet */ #define SCSI_LOW_ERRORBITS "\020\017ubferr\016senseerr\015senseio\012uacaerr\011staterr\010busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal" /* current scsi data pointer */ struct sc_p sl_scp; /* power control */ u_int sl_active; /* host is busy state */ int sl_powc; /* power down timer counter */ u_int sl_rstep; /* resume step */ /* configuration flags */ u_int sl_flags; #define HW_POWDOWN 0x0001 #define HW_RESUME 0x0002 #define HW_PDMASTART 0x0004 #define HW_INACTIVE 0x0008 #define HW_POWERCTRL 0x0010 #define HW_INITIALIZING 0x0020 #define HW_READ_PADDING 0x1000 #define HW_WRITE_PADDING 0x2000 u_int sl_cfgflags; #define CFG_NODISC 0x0001 #define CFG_NOPARITY 0x0002 #define CFG_NOATTEN 0x0004 #define CFG_ASYNC 0x0008 #define CFG_NOQTAG 0x0010 int sl_show_result; #define SHOW_SYNCH_NEG 0x0001 #define SHOW_WIDE_NEG 0x0002 #define SHOW_CALCF_RES 0x0010 #define SHOW_PROBE_RES 0x0020 #define SHOW_ALL_NEG -1 /* host informations */ u_int sl_hostid; int sl_nluns; int sl_ntargs; int sl_openings; /* interface functions */ struct scsi_low_funcs *sl_funcs; /* targinfo size */ int sl_targsize; }; +#define SCSI_LOW_LOCK(sl) mtx_lock(&(sl)->sl_lock) +#define SCSI_LOW_UNLOCK(sl) mtx_unlock(&(sl)->sl_lock) +#define SCSI_LOW_ASSERT_LOCKED(sl) mtx_assert(&(sl)->sl_lock, MA_OWNED) + /************************************************* * SCSI LOW service functions *************************************************/ /* * Scsi low attachment function. */ int scsi_low_attach(struct scsi_low_softc *, int, int, int, int, int); -int scsi_low_dettach(struct scsi_low_softc *); +int scsi_low_detach(struct scsi_low_softc *); /* * Scsi low interface activate or deactivate functions */ int scsi_low_is_busy(struct scsi_low_softc *); int scsi_low_activate(struct scsi_low_softc *); int scsi_low_deactivate(struct scsi_low_softc *); /* * Scsi phase "bus service" functions. * These functions are corresponding to each scsi bus phaeses. */ /* bus idle phase (other initiators or targets release bus) */ void scsi_low_bus_idle(struct scsi_low_softc *); /* arbitration and selection phase */ void scsi_low_arbit_fail(struct scsi_low_softc *, struct slccb *); static __inline void scsi_low_arbit_win(struct scsi_low_softc *); /* msgout phase */ #define SCSI_LOW_MSGOUT_INIT 0x00000001 #define SCSI_LOW_MSGOUT_UNIFY 0x00000002 int scsi_low_msgout(struct scsi_low_softc *, struct targ_info *, u_int); /* msgin phase */ #define SCSI_LOW_DATA_PE 0x80000000 int scsi_low_msgin(struct scsi_low_softc *, struct targ_info *, u_int); /* statusin phase */ static __inline int scsi_low_statusin(struct scsi_low_softc *, struct targ_info *, u_int); /* data phase */ int scsi_low_data(struct scsi_low_softc *, struct targ_info *, struct buf **, int); static __inline void scsi_low_data_finish(struct scsi_low_softc *); /* cmd phase */ int scsi_low_cmd(struct scsi_low_softc *, struct targ_info *); /* reselection phase */ struct targ_info *scsi_low_reselected(struct scsi_low_softc *, u_int); /* disconnection phase */ int scsi_low_disconnected(struct scsi_low_softc *, struct targ_info *); /* * Scsi bus restart function. * Canncel all established nexuses => scsi system initialized => restart jobs. */ #define SCSI_LOW_RESTART_HARD 1 #define SCSI_LOW_RESTART_SOFT 0 int scsi_low_restart(struct scsi_low_softc *, int, u_char *); /* * Scsi utility fucntions */ /* print current status */ void scsi_low_print(struct scsi_low_softc *, struct targ_info *); /* bus reset utility */ void scsi_low_bus_reset(struct scsi_low_softc *); /************************************************* * Message macro defs *************************************************/ #define SCSI_LOW_SETUP_PHASE(ti, phase) \ { \ (ti)->ti_ophase = ti->ti_phase; \ (ti)->ti_phase = (phase); \ } #define SCSI_LOW_SETUP_MSGPHASE(slp, PHASE) \ { \ (slp)->sl_msgphase = (PHASE); \ } #define SCSI_LOW_ASSERT_ATN(slp) \ { \ (slp)->sl_atten = 1; \ } #define SCSI_LOW_DEASSERT_ATN(slp) \ { \ (slp)->sl_atten = 0; \ } /************************************************* * Inline functions *************************************************/ static __inline void scsi_low_attention(struct scsi_low_softc *); static __inline int scsi_low_is_msgout_continue(struct targ_info *, u_int); static __inline int scsi_low_assert_msg(struct scsi_low_softc *, struct targ_info *, u_int, int); static __inline int scsi_low_is_disconnect_ok(struct slccb *); static __inline int scsi_low_is_msgout_continue(ti, mask) struct targ_info *ti; u_int mask; { return ((ti->ti_msgflags & (~mask)) != 0); } static __inline int scsi_low_is_disconnect_ok(cb) struct slccb *cb; { return ((cb->li->li_flags & SCSI_LOW_DISC) != 0 && (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) == 0); } static __inline void scsi_low_attention(slp) struct scsi_low_softc *slp; { if (slp->sl_atten != 0) return; (*slp->sl_funcs->scsi_low_attention) (slp); SCSI_LOW_ASSERT_ATN(slp); } static __inline int scsi_low_assert_msg(slp, ti, msg, now) struct scsi_low_softc *slp; struct targ_info *ti; u_int msg; int now; { ti->ti_msgflags |= msg; if (now != 0) scsi_low_attention(slp); return 0; } static __inline void scsi_low_arbit_win(slp) struct scsi_low_softc *slp; { slp->sl_selid = NULL; } static __inline void scsi_low_data_finish(slp) struct scsi_low_softc *slp; { if (slp->sl_Qnexus != NULL) { slp->sl_Qnexus->ccb_datalen = slp->sl_scp.scp_datalen; } } static __inline int scsi_low_statusin(slp, ti, c) struct scsi_low_softc *slp; struct targ_info *ti; u_int c; { slp->sl_ph_count ++; if ((c & SCSI_LOW_DATA_PE) != 0) { scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 0); return EIO; } slp->sl_scp.scp_status = (u_int8_t) c; return 0; } /************************************************* * Message out defs *************************************************/ /* XXX: use scsi_message.h */ #define ST_GOOD 0x00 #define ST_CHKCOND 0x02 #define ST_MET 0x04 #define ST_BUSY 0x08 #define ST_INTERGOOD 0x10 #define ST_INTERMET 0x14 #define ST_CONFLICT 0x18 #define ST_CMDTERM 0x22 #define ST_QUEFULL 0x28 #define ST_UNKNOWN 0xff #define MSG_COMP 0x00 #define MSG_EXTEND 0x01 #define MKMSG_EXTEND(XLEN, XCODE) ((((u_int)(XLEN)) << NBBY) | ((u_int)(XCODE))) #define MSG_EXTEND_MDPCODE 0x00 #define MSG_EXTEND_MDPLEN 0x05 #define MSG_EXTEND_SYNCHCODE 0x01 #define MSG_EXTEND_SYNCHLEN 0x03 #define MSG_EXTEND_WIDECODE 0x03 #define MSG_EXTEND_WIDELEN 0x02 #define MSG_SAVESP 0x02 #define MSG_RESTORESP 0x03 #define MSG_DISCON 0x04 #define MSG_I_ERROR 0x05 #define MSG_ABORT 0x06 #define MSG_REJECT 0x07 #define MSG_NOOP 0x08 #define MSG_PARITY 0x09 #define MSG_LCOMP 0x0a #define MSG_LCOMP_F 0x0b #define MSG_RESET 0x0c #define MSG_ABORT_QTAG 0x0d #define MSG_CLEAR_QTAG 0x0e #define MSG_TERM_IO 0x11 #define MSG_SIMPLE_QTAG 0x20 #define MSG_HEAD_QTAG 0x21 #define MSG_ORDERED_QTAG 0x22 #define MSG_IDENTIFY 0x80 #define MSG_IDENTIFY_DISCPRIV 0x40 #endif /* !_SCSI_LOW_H_ */ diff --git a/sys/dev/ct/bshw_machdep.c b/sys/dev/ct/bshw_machdep.c index ba89e559cdb8..046aa7d9430c 100644 --- a/sys/dev/ct/bshw_machdep.c +++ b/sys/dev/ct/bshw_machdep.c @@ -1,742 +1,743 @@ /* $NecBSD: bshw_machdep.c,v 1.8.12.6 2001/06/29 06:28:05 honda Exp $ */ #include __FBSDID("$FreeBSD$"); /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "opt_ddb.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #define BSHW_IO_CONTROL_FLAGS 0 u_int bshw_io_control = BSHW_IO_CONTROL_FLAGS; int bshw_data_read_bytes = 4096; int bshw_data_write_bytes = 4096; /********************************************************* * OS dep part *********************************************************/ typedef unsigned long vaddr_t; /********************************************************* * GENERIC MACHDEP FUNCTIONS *********************************************************/ void bshw_synch_setup(struct ct_softc *ct, struct targ_info *ti) { struct ct_bus_access_handle *chp = &ct->sc_ch; struct ct_targ_info *cti = (void *) ti; struct bshw_softc *bs = ct->ct_hw; struct bshw *hw = bs->sc_hw; if (hw->hw_sregaddr == 0) return; ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg); if (hw->hw_flags & BSHW_DOUBLE_DMACHAN) { ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8, cti->cti_syncreg); } } void bshw_bus_reset(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct bshw_softc *bs = ct->ct_hw; struct bshw *hw = bs->sc_hw; bus_addr_t offs; u_int8_t regv; int i; /* open hardware busmaster mode */ if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0) { device_printf(slp->sl_dev, "change mode using external DMA (%x)\n", (u_int)ct_cr_read_1(chp, 0x37)); } /* clear hardware synch registers */ offs = hw->hw_sregaddr; if (offs != 0) { for (i = 0; i < 8; i ++, offs ++) { ct_cr_write_1(chp, offs, 0); if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0) ct_cr_write_1(chp, offs + 8, 0); } } /* disable interrupt & assert reset */ regv = ct_cr_read_1(chp, wd3s_mbank); regv |= MBR_RST; regv &= ~MBR_IEN; ct_cr_write_1(chp, wd3s_mbank, regv); DELAY(500000); /* reset signal off */ regv &= ~MBR_RST; ct_cr_write_1(chp, wd3s_mbank, regv); /* interrupt enable */ regv |= MBR_IEN; ct_cr_write_1(chp, wd3s_mbank, regv); } /* probe */ int bshw_read_settings(struct ct_bus_access_handle *chp, struct bshw_softc *bs) { static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 }; bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM); bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7]; bs->sc_drq = ct_cmdp_read_1(chp) & 3; return 0; } /********************************************************* * DMA PIO TRANSFER (SMIT) *********************************************************/ #define LC_SMIT_TIMEOUT 2 /* 2 sec: timeout for a fifo status ready */ #define LC_SMIT_OFFSET 0x1000 #define LC_FSZ DEV_BSIZE #define LC_SFSZ 0x0c #define LC_REST (LC_FSZ - LC_SFSZ) #define BSHW_LC_FSET 0x36 #define BSHW_LC_FCTRL 0x44 #define FCTRL_EN 0x01 #define FCTRL_WRITE 0x02 #define SF_ABORT 0x08 #define SF_RDY 0x10 static __inline void bshw_lc_smit_start(struct ct_softc *, int, u_int); static __inline void bshw_lc_smit_stop(struct ct_softc *); static int bshw_lc_smit_fstat(struct ct_softc *, int, int); static __inline void bshw_lc_smit_stop(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; ct_cr_write_1(chp, BSHW_LC_FCTRL, 0); ct_cmdp_write_1(chp, CMDP_DMER); } static __inline void bshw_lc_smit_start(struct ct_softc *ct, int count, u_int direction) { struct ct_bus_access_handle *chp = &ct->sc_ch; u_int8_t pval, val; val = ct_cr_read_1(chp, BSHW_LC_FSET); cthw_set_count(chp, count); pval = FCTRL_EN; if (direction == SCSI_LOW_WRITE) pval |= (val & 0xe0) | FCTRL_WRITE; ct_cr_write_1(chp, BSHW_LC_FCTRL, pval); ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); } static int bshw_lc_smit_fstat(struct ct_softc *ct, int wc, int read) { struct ct_bus_access_handle *chp = &ct->sc_ch; u_int8_t stat; while (wc -- > 0) { chp->ch_bus_weight(chp); stat = ct_cmdp_read_1(chp); if (read == SCSI_LOW_READ) { if ((stat & SF_RDY) != 0) return 0; if ((stat & SF_ABORT) != 0) return EIO; } else { if ((stat & SF_ABORT) != 0) return EIO; if ((stat & SF_RDY) != 0) return 0; } } device_printf(ct->sc_sclow.sl_dev, "SMIT fifo status timeout\n"); return EIO; } void bshw_smit_xfer_stop(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct bshw_softc *bs = ct->ct_hw; struct targ_info *ti; struct sc_p *sp = &slp->sl_scp; u_int count; bshw_lc_smit_stop(ct); ti = slp->sl_Tnexus; if (ti == NULL) return; if (ti->ti_phase == PH_DATA) { count = cthw_get_count(&ct->sc_ch); if (count < bs->sc_sdatalen) { if (sp->scp_direction == SCSI_LOW_READ && count != bs->sc_edatalen) goto bad; count = bs->sc_sdatalen - count; if (count > (u_int) sp->scp_datalen) goto bad; sp->scp_data += count; sp->scp_datalen -= count; } else if (count > bs->sc_sdatalen) { bad: device_printf(slp->sl_dev, "smit_xfer_end: cnt error\n"); slp->sl_error |= PDMAERR; } scsi_low_data_finish(slp); } else { device_printf(slp->sl_dev, "smit_xfer_end: phase miss\n"); slp->sl_error |= PDMAERR; } } int bshw_smit_xfer_start(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct bshw_softc *bs = ct->ct_hw; struct sc_p *sp = &slp->sl_scp; struct targ_info *ti = slp->sl_Tnexus; struct ct_targ_info *cti = (void *) ti; u_int datalen, count, io_control; int wc; u_int8_t *data; io_control = bs->sc_io_control | bshw_io_control; if ((io_control & BSHW_SMIT_BLOCK) != 0) return EINVAL; if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0) return EINVAL; datalen = sp->scp_datalen; if (slp->sl_scp.scp_direction == SCSI_LOW_READ) { if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 && datalen > bshw_data_read_bytes) datalen = bshw_data_read_bytes; } else { if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 && datalen > bshw_data_write_bytes) datalen = bshw_data_write_bytes; } bs->sc_sdatalen = datalen; data = sp->scp_data; wc = LC_SMIT_TIMEOUT * 1024 * 1024; ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); bshw_lc_smit_start(ct, datalen, sp->scp_direction); if (sp->scp_direction == SCSI_LOW_READ) { do { if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ)) break; count = (datalen > LC_FSZ ? LC_FSZ : datalen); - bus_space_read_region_4(chp->ch_memt, chp->ch_memh, + bus_read_region_4(chp->ch_mem, LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); data += count; datalen -= count; } while (datalen > 0); bs->sc_edatalen = datalen; } else { do { if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) break; if (cti->cti_syncreg == 0) { /* XXX: * If async transfer, reconfirm a scsi phase * again. Unless C bus might hang up. */ if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) break; } count = (datalen > LC_SFSZ ? LC_SFSZ : datalen); - bus_space_write_region_4(chp->ch_memt, chp->ch_memh, + bus_write_region_4(chp->ch_mem, LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); data += count; datalen -= count; if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) break; count = (datalen > LC_REST ? LC_REST : datalen); - bus_space_write_region_4(chp->ch_memt, chp->ch_memh, + bus_write_region_4(chp->ch_mem, LC_SMIT_OFFSET + LC_SFSZ, (u_int32_t *) data, count >> 2); data += count; datalen -= count; } while (datalen > 0); } return 0; } /********************************************************* * DMA TRANSFER (BS) *********************************************************/ static __inline void bshw_dma_write_1 \ (struct ct_bus_access_handle *, bus_addr_t, u_int8_t); static void bshw_dmastart(struct ct_softc *); static void bshw_dmadone(struct ct_softc *); int bshw_dma_xfer_start(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct sc_p *sp = &slp->sl_scp; struct ct_bus_access_handle *chp = &ct->sc_ch; struct bshw_softc *bs = ct->ct_hw; vaddr_t va, endva, phys, nphys; u_int io_control; io_control = bs->sc_io_control | bshw_io_control; if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256) return EINVAL; ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); phys = vtophys((vaddr_t) sp->scp_data); if (phys >= bs->sc_minphys) { /* setup segaddr */ bs->sc_segaddr = bs->sc_bounce_phys; /* setup seglen */ bs->sc_seglen = sp->scp_datalen; if (bs->sc_seglen > bs->sc_bounce_size) bs->sc_seglen = bs->sc_bounce_size; /* setup bufp */ bs->sc_bufp = bs->sc_bounce_addr; if (sp->scp_direction == SCSI_LOW_WRITE) bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen); } else { /* setup segaddr */ bs->sc_segaddr = (u_int8_t *) phys; /* setup seglen */ endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen); for (va = (vaddr_t) sp->scp_data; ; phys = nphys) { if ((va += PAGE_SIZE) >= endva) { bs->sc_seglen = sp->scp_datalen; break; } nphys = vtophys(va); if (phys + PAGE_SIZE != nphys || nphys >= bs->sc_minphys) { bs->sc_seglen = (u_int8_t *) trunc_page(va) - sp->scp_data; break; } } /* setup bufp */ bs->sc_bufp = NULL; } bshw_dmastart(ct); cthw_set_count(chp, bs->sc_seglen); ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); return 0; } void bshw_dma_xfer_stop(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct sc_p *sp = &slp->sl_scp; struct bshw_softc *bs = ct->ct_hw; struct targ_info *ti; u_int count, transbytes; bshw_dmadone(ct); ti = slp->sl_Tnexus; if (ti == NULL) return; if (ti->ti_phase == PH_DATA) { count = cthw_get_count(&ct->sc_ch); if (count < (u_int) bs->sc_seglen) { transbytes = bs->sc_seglen - count; if (bs->sc_bufp != NULL && sp->scp_direction == SCSI_LOW_READ) bcopy(bs->sc_bufp, sp->scp_data, transbytes); sp->scp_data += transbytes; sp->scp_datalen -= transbytes; } else if (count > (u_int) bs->sc_seglen) { device_printf(slp->sl_dev, "port data %x != seglen %x\n", count, bs->sc_seglen); slp->sl_error |= PDMAERR; } scsi_low_data_finish(slp); } else { device_printf(slp->sl_dev, "extra DMA interrupt\n"); slp->sl_error |= PDMAERR; } bs->sc_bufp = NULL; } /* common dma settings */ #undef DMA1_SMSK #define DMA1_SMSK (0x15) #undef DMA1_MODE #define DMA1_MODE (0x17) #undef DMA1_FFC #define DMA1_FFC (0x19) #undef DMA1_CHN #define DMA1_CHN(c) (0x01 + ((c) << 2)) #define DMA37SM_SET 0x04 #define DMA37MD_WRITE 0x04 #define DMA37MD_READ 0x08 #define DMA37MD_SINGLE 0x40 static bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 }; static __inline void bshw_dma_write_1(struct ct_bus_access_handle *chp, bus_addr_t port, u_int8_t val) { CT_BUS_WEIGHT(chp); outb(port, val); } static void bshw_dmastart(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct bshw_softc *bs = ct->ct_hw; struct ct_bus_access_handle *chp = &ct->sc_ch; int chan = bs->sc_drq; bus_addr_t waport; u_int8_t regv, *phys = bs->sc_segaddr; u_int nbytes = bs->sc_seglen; /* flush cpu cache */ (*bs->sc_dmasync_before) (ct); /* * Program one of DMA channels 0..3. These are * byte mode channels. */ /* set dma channel mode, and reset address ff */ if (slp->sl_scp.scp_direction == SCSI_LOW_READ) regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan; else regv = DMA37MD_READ | DMA37MD_SINGLE | chan; bshw_dma_write_1(chp, DMA1_MODE, regv); bshw_dma_write_1(chp, DMA1_FFC, 0); /* send start address */ waport = DMA1_CHN(chan); bshw_dma_write_1(chp, waport, (u_int) phys); bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8); bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16); /* send count */ bshw_dma_write_1(chp, waport + 2, --nbytes); bshw_dma_write_1(chp, waport + 2, nbytes >> 8); /* vendor unique hook */ if (bs->sc_hw->hw_dma_start) (*bs->sc_hw->hw_dma_start)(ct); bshw_dma_write_1(chp, DMA1_SMSK, chan); ct_cmdp_write_1(chp, CMDP_DMES); } static void bshw_dmadone(struct ct_softc *ct) { struct bshw_softc *bs = ct->ct_hw; struct ct_bus_access_handle *chp = &ct->sc_ch; bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET)); ct_cmdp_write_1(chp, CMDP_DMER); /* vendor unique hook */ if (bs->sc_hw->hw_dma_stop) (*bs->sc_hw->hw_dma_stop) (ct); /* flush cpu cache */ (*bs->sc_dmasync_after) (ct); } /********************************************** * VENDOR UNIQUE DMA FUNCS **********************************************/ static int bshw_dma_init_sc98(struct ct_softc *); static void bshw_dma_start_sc98(struct ct_softc *); static void bshw_dma_stop_sc98(struct ct_softc *); static int bshw_dma_init_texa(struct ct_softc *); static void bshw_dma_start_elecom(struct ct_softc *); static void bshw_dma_stop_elecom(struct ct_softc *); static int bshw_dma_init_texa(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; u_int8_t regval; if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08) return 0; ct_cr_write_1(chp, 0x37, regval | 0x08); regval = ct_cr_read_1(chp, 0x3f); ct_cr_write_1(chp, 0x3f, regval | 0x08); return 1; } static int bshw_dma_init_sc98(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; if (ct_cr_read_1(chp, 0x37) & 0x08) return 0; /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */ ct_cr_write_1(chp, 0x37, 0x1a); ct_cr_write_1(chp, 0x3f, 0x1a); #if 0 /* only valid for IO */ ct_cr_write_1(chp, 0x40, 0xf4); ct_cr_write_1(chp, 0x41, 0x9); ct_cr_write_1(chp, 0x43, 0xff); ct_cr_write_1(chp, 0x46, 0x4e); ct_cr_write_1(chp, 0x48, 0xf4); ct_cr_write_1(chp, 0x49, 0x9); ct_cr_write_1(chp, 0x4b, 0xff); ct_cr_write_1(chp, 0x4e, 0x4e); #endif return 1; } static void bshw_dma_start_sc98(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; ct_cr_write_1(chp, 0x73, 0x32); ct_cr_write_1(chp, 0x74, 0x23); } static void bshw_dma_stop_sc98(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; ct_cr_write_1(chp, 0x73, 0x43); ct_cr_write_1(chp, 0x74, 0x34); } static void bshw_dma_start_elecom(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; u_int8_t tmp = ct_cr_read_1(chp, 0x4c); ct_cr_write_1(chp, 0x32, tmp & 0xdf); } static void bshw_dma_stop_elecom(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; u_int8_t tmp = ct_cr_read_1(chp, 0x4c); ct_cr_write_1(chp, 0x32, tmp | 0x20); } static struct bshw bshw_generic = { BSHW_SYNC_RELOAD, 0, NULL, NULL, NULL, }; static struct bshw bshw_sc98 = { BSHW_DOUBLE_DMACHAN, 0x60, bshw_dma_init_sc98, bshw_dma_start_sc98, bshw_dma_stop_sc98, }; static struct bshw bshw_texa = { BSHW_DOUBLE_DMACHAN, 0x60, bshw_dma_init_texa, NULL, NULL, }; static struct bshw bshw_elecom = { 0, 0x38, NULL, bshw_dma_start_elecom, bshw_dma_stop_elecom, }; static struct bshw bshw_lc_smit = { BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN, 0x60, NULL, NULL, NULL, }; static struct bshw bshw_lha20X = { BSHW_DOUBLE_DMACHAN, 0x60, NULL, NULL, NULL, }; /* hw tabs */ static dvcfg_hw_t bshw_hwsel_array[] = { /* 0x00 */ &bshw_generic, /* 0x01 */ &bshw_sc98, /* 0x02 */ &bshw_texa, /* 0x03 */ &bshw_elecom, /* 0x04 */ &bshw_lc_smit, /* 0x05 */ &bshw_lha20X, }; struct dvcfg_hwsel bshw_hwsel = { DVCFG_HWSEL_SZ(bshw_hwsel_array), bshw_hwsel_array }; diff --git a/sys/dev/ct/ct.c b/sys/dev/ct/ct.c index 1d3f0db1c3ad..6a96c9c486e6 100644 --- a/sys/dev/ct/ct.c +++ b/sys/dev/ct/ct.c @@ -1,1229 +1,1242 @@ /* $NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $ */ #include __FBSDID("$FreeBSD$"); /* $NetBSD$ */ #define CT_DEBUG #define CT_IO_CONTROL_FLAGS (CT_USE_CCSEQ | CT_FAST_INTR) /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #define CT_NTARGETS 8 #define CT_NLUNS 8 #define CT_RESET_DEFAULT 2000 #define CT_DELAY_MAX (2 * 1000 * 1000) #define CT_DELAY_INTERVAL (1) /*************************************************** * DEBUG ***************************************************/ #ifdef CT_DEBUG int ct_debug; #endif /* CT_DEBUG */ /*************************************************** * IO control ***************************************************/ #define CT_USE_CCSEQ 0x0100 #define CT_FAST_INTR 0x0200 u_int ct_io_control = CT_IO_CONTROL_FLAGS; /*************************************************** * default data ***************************************************/ u_int8_t cthw_cmdlevel[256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C E D F */ /*0*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , /*1*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*2*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , /*3*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*4*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*5*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*6*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*7*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*8*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*9*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*A*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*B*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*C*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*D*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*E*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /*F*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , }; #if 0 /* default synch data table */ /* A 10 6.6 5.0 4.0 3.3 2.8 2.5 2.0 M/s */ /* X 100 150 200 250 300 350 400 500 ns */ static struct ct_synch_data ct_synch_data_FSCSI[] = { {25, 0xa0}, {37, 0xb0}, {50, 0x20}, {62, 0xd0}, {75, 0x30}, {87, 0xf0}, {100, 0x40}, {125, 0x50}, {0, 0} }; static struct ct_synch_data ct_synch_data_SCSI[] = { {50, 0x20}, {75, 0x30}, {100, 0x40}, {125, 0x50}, {0, 0} }; #endif /*************************************************** * DEVICE STRUCTURE ***************************************************/ extern struct cfdriver ct_cd; /***************************************************************** * Interface functions *****************************************************************/ static int ct_xfer(struct ct_softc *, u_int8_t *, int, int, u_int *); static void ct_io_xfer(struct ct_softc *); static int ct_reselected(struct ct_softc *, u_int8_t); static void ct_phase_error(struct ct_softc *, u_int8_t); static int ct_start_selection(struct ct_softc *, struct slccb *); static int ct_msg(struct ct_softc *, struct targ_info *, u_int); static int ct_world_start(struct ct_softc *, int); static __inline void cthw_phase_bypass(struct ct_softc *, u_int8_t); static int cthw_chip_reset(struct ct_bus_access_handle *, int *, int, int); static void cthw_bus_reset(struct ct_softc *); static int ct_ccb_nexus_establish(struct ct_softc *); static int ct_lun_nexus_establish(struct ct_softc *); static int ct_target_nexus_establish(struct ct_softc *, int, int); static void cthw_attention(struct ct_softc *); static int ct_targ_init(struct ct_softc *, struct targ_info *, int); static int ct_unbusy(struct ct_softc *); static void ct_attention(struct ct_softc *); static struct ct_synch_data *ct_make_synch_table(struct ct_softc *); static int ct_catch_intr(struct ct_softc *); +static int ct_poll(void *); struct scsi_low_funcs ct_funcs = { SC_LOW_INIT_T ct_world_start, SC_LOW_BUSRST_T cthw_bus_reset, SC_LOW_TARG_INIT_T ct_targ_init, SC_LOW_LUN_INIT_T NULL, SC_LOW_SELECT_T ct_start_selection, SC_LOW_NEXUS_T ct_lun_nexus_establish, SC_LOW_NEXUS_T ct_ccb_nexus_establish, SC_LOW_ATTEN_T cthw_attention, SC_LOW_MSG_T ct_msg, SC_LOW_TIMEOUT_T NULL, - SC_LOW_POLL_T ctintr, + SC_LOW_POLL_T ct_poll, NULL, /* SC_LOW_POWER_T cthw_power, */ }; /************************************************** * HW functions **************************************************/ static __inline void cthw_phase_bypass(struct ct_softc *ct, u_int8_t ph) { struct ct_bus_access_handle *chp = &ct->sc_ch; ct_cr_write_1(chp, wd3s_cph, ph); ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR); } static void cthw_bus_reset(struct ct_softc *ct) { /* * wd33c93 does not have bus reset function. */ if (ct->ct_bus_reset != NULL) ((*ct->ct_bus_reset) (ct)); } static int cthw_chip_reset(struct ct_bus_access_handle *chp, int *chiprevp, int chipclk, int hostid) { #define CT_SELTIMEOUT_20MHz_REGV (0x80) u_int8_t aux, regv; u_int seltout; int wc; /* issue abort cmd */ ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT); DELAY(1000); /* 1ms wait */ (void) ct_stat_read_1(chp); (void) ct_cr_read_1(chp, wd3s_stat); /* setup chip registers */ regv = 0; seltout = CT_SELTIMEOUT_20MHz_REGV; switch (chipclk) { case 8: case 10: seltout = (seltout * chipclk) / 20; regv = IDR_FS_8_10; break; case 12: case 15: seltout = (seltout * chipclk) / 20; regv = IDR_FS_12_15; break; case 16: case 20: seltout = (seltout * chipclk) / 20; regv = IDR_FS_16_20; break; default: panic("ct: illegal chip clk rate"); break; } regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF; ct_cr_write_1(chp, wd3s_oid, regv); ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); for (wc = CT_RESET_DEFAULT; wc > 0; wc --) { aux = ct_stat_read_1(chp); if (aux != 0xff && (aux & STR_INT)) { regv = ct_cr_read_1(chp, wd3s_stat); if (regv == BSR_RESET || regv == BSR_AFM_RESET) break; ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); } DELAY(1); } if (wc == 0) return ENXIO; ct_cr_write_1(chp, wd3s_tout, seltout); ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL); ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT); ct_cr_write_1(chp, wd3s_synch, 0); if (chiprevp != NULL) { *chiprevp = CT_WD33C93; if (regv == BSR_RESET) goto out; *chiprevp = CT_WD33C93_A; ct_cr_write_1(chp, wd3s_qtag, 0xaa); if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa) { ct_cr_write_1(chp, wd3s_qtag, 0x0); goto out; } ct_cr_write_1(chp, wd3s_qtag, 0x55); if (ct_cr_read_1(chp, wd3s_qtag) != 0x55) { ct_cr_write_1(chp, wd3s_qtag, 0x0); goto out; } ct_cr_write_1(chp, wd3s_qtag, 0x0); *chiprevp = CT_WD33C93_B; } out: (void) ct_stat_read_1(chp); (void) ct_cr_read_1(chp, wd3s_stat); return 0; } static struct ct_synch_data * ct_make_synch_table(struct ct_softc *ct) { struct ct_synch_data *sdtp, *sdp; u_int base, i, period; sdtp = sdp = &ct->sc_default_sdt[0]; if ((ct->sc_chipclk % 5) == 0) base = 1000 / (5 * 2); /* 5 MHz type */ else base = 1000 / (4 * 2); /* 4 MHz type */ if (ct->sc_chiprev >= CT_WD33C93_B) { /* fast scsi */ for (i = 2; i < 8; i ++, sdp ++) { period = (base * i) / 2; if (period >= 200) /* 5 MHz */ break; sdp->cs_period = period / 4; sdp->cs_syncr = (i * 0x10) | 0x80; } } for (i = 2; i < 8; i ++, sdp ++) { period = (base * i); if (period > 500) /* 2 MHz */ break; sdp->cs_period = period / 4; sdp->cs_syncr = (i * 0x10); } sdp->cs_period = 0; sdp->cs_syncr = 0; return sdtp; } /************************************************** * Attach & Probe **************************************************/ int ctprobesubr(struct ct_bus_access_handle *chp, u_int dvcfg, int hsid, u_int chipclk, int *chiprevp) { #if 0 if ((ct_stat_read_1(chp) & STR_BSY) != 0) return 0; #endif if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0) return 0; return 1; } void ctattachsubr(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ slp->sl_funcs = &ct_funcs; slp->sl_flags |= HW_READ_PADDING; (void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS, sizeof(struct ct_targ_info), 0); } /************************************************** * SCSI LOW interface functions **************************************************/ static void cthw_attention(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; ct->sc_atten = 1; if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0) return; ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN); DELAY(10); if ((ct_stat_read_1(chp) & STR_LCI) == 0) ct->sc_atten = 0; ct_unbusy(ct); return; } static void ct_attention(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; if (slp->sl_atten == 0) { ct_unbusy(ct); scsi_low_attention(slp); } else if (ct->sc_atten != 0) { ct_unbusy(ct); cthw_attention(ct); } } static int ct_targ_init(struct ct_softc *ct, struct targ_info *ti, int action) { struct ct_targ_info *cti = (void *) ti; if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) { if (ct->sc_sdp == NULL) { ct->sc_sdp = ct_make_synch_table(ct); } switch (ct->sc_chiprev) { default: ti->ti_maxsynch.offset = 5; break; case CT_WD33C93_A: case CT_AM33C93_A: ti->ti_maxsynch.offset = 12; break; case CT_WD33C93_B: case CT_WD33C93_C: ti->ti_maxsynch.offset = 12; break; } ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period; ti->ti_width = SCSI_LOW_BUS_WIDTH_8; cti->cti_syncreg = 0; } return 0; } static int ct_world_start(struct ct_softc *ct, int fdone) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; if (ct->sc_sdp == NULL) { ct->sc_sdp = ct_make_synch_table(ct); } if (slp->sl_cfgflags & CFG_NOPARITY) ct->sc_creg = CR_DEFAULT; else ct->sc_creg = CR_DEFAULT_HP; if (ct->sc_dma & CT_DMA_DMASTART) (*ct->ct_dma_xfer_stop) (ct); if (ct->sc_dma & CT_DMA_PIOSTART) (*ct->ct_pio_xfer_stop) (ct); ct->sc_dma = 0; ct->sc_atten = 0; cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); scsi_low_bus_reset(slp); cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); return 0; } static int ct_start_selection(struct ct_softc *ct, struct slccb *cb) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct targ_info *ti = slp->sl_Tnexus; struct lun_info *li = slp->sl_Lnexus; int s, satok; u_int8_t cmd; ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; ct->sc_atten = 0; satok = 0; if (scsi_low_is_disconnect_ok(cb) != 0) { if (ct->sc_chiprev >= CT_WD33C93_A) satok = 1; else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0) satok = 1; } if (satok != 0 && scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0) { cmd = WD3S_SELECT_ATN_TFR; ct->sc_satgo = CT_SAT_GOING; } else { cmd = WD3S_SELECT_ATN; ct->sc_satgo = 0; } if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0) return SCSI_LOW_START_FAIL; if ((ct->sc_satgo & CT_SAT_GOING) != 0) { (void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT); scsi_low_cmd(slp, ti); ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); } else { /* anyway attention assert */ SCSI_LOW_ASSERT_ATN(slp); } ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction); s = splhigh(); if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0) { /* XXX: * Reload a lun again here. */ ct_cr_write_1(chp, wd3s_lun, li->li_lun); ct_cr_write_1(chp, wd3s_cmd, cmd); if ((ct_stat_read_1(chp) & STR_LCI) == 0) { splx(s); SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); return SCSI_LOW_START_OK; } } splx(s); return SCSI_LOW_START_FAIL; } static int ct_msg(struct ct_softc *ct, struct targ_info *ti, u_int msg) { struct ct_bus_access_handle *chp = &ct->sc_ch; struct ct_targ_info *cti = (void *) ti; struct ct_synch_data *csp = ct->sc_sdp; u_int offset, period; int error; if ((msg & SCSI_LOW_MSG_WIDE) != 0) { if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; return EINVAL; } return 0; } if ((msg & SCSI_LOW_MSG_SYNCH) == 0) return 0; offset = ti->ti_maxsynch.offset; period = ti->ti_maxsynch.period; for ( ; csp->cs_period != 0; csp ++) { if (period == csp->cs_period) break; } if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0) { ti->ti_maxsynch.period = 0; ti->ti_maxsynch.offset = 0; cti->cti_syncreg = 0; error = EINVAL; } else { cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr); error = 0; } if (ct->ct_synch_setup != 0) (*ct->ct_synch_setup) (ct, ti); ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); return error; } /************************************************* * *************************************************/ static int ct_xfer(struct ct_softc *ct, u_int8_t *data, int len, int direction, u_int *statp) { struct ct_bus_access_handle *chp = &ct->sc_ch; int wc; register u_int8_t aux; *statp = 0; if (len == 1) { ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO); } else { cthw_set_count(chp, len); ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); } aux = ct_stat_read_1(chp); if ((aux & STR_LCI) != 0) { cthw_set_count(chp, 0); return len; } for (wc = 0; wc < ct->sc_tmaxcnt; wc ++) { /* check data ready */ if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR)) { if (direction == SCSI_LOW_READ) { *data = ct_cr_read_1(chp, wd3s_data); if ((aux & STR_PE) != 0) *statp |= SCSI_LOW_DATA_PE; } else { ct_cr_write_1(chp, wd3s_data, *data); } len --; if (len <= 0) break; data ++; } else { DELAY(1); } /* check phase miss */ aux = ct_stat_read_1(chp); if ((aux & STR_INT) != 0) break; } return len; } #define CT_PADDING_BUF_SIZE 32 static void ct_io_xfer(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct sc_p *sp = &slp->sl_scp; u_int stat; int len; u_int8_t pbuf[CT_PADDING_BUF_SIZE]; /* polling mode */ ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg); if (sp->scp_datalen <= 0) { slp->sl_error |= PDMAERR; if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) bzero(pbuf, CT_PADDING_BUF_SIZE); ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE, sp->scp_direction, &stat); } else { len = ct_xfer(ct, sp->scp_data, sp->scp_datalen, sp->scp_direction, &stat); sp->scp_data += (sp->scp_datalen - len); sp->scp_datalen = len; } } /************************************************** * **************************************************/ struct ct_err { u_char *pe_msg; u_int pe_err; u_int pe_errmsg; int pe_done; }; struct ct_err ct_cmderr[] = { /*0*/ { "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1}, /*1*/ { "unexpected bus free", FATALIO, 0, 1}, /*2*/ { NULL, SELTIMEOUTIO, 0, 1}, /*3*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, /*4*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, /*5*/ { "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1}, /*6*/ { "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0}, /*7*/ { "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, }; static void ct_phase_error(struct ct_softc *ct, u_int8_t scsi_status) { struct scsi_low_softc *slp = &ct->sc_sclow; struct targ_info *ti = slp->sl_Tnexus; struct ct_err *pep; u_int msg = 0; if ((scsi_status & BSR_CM) == BSR_CMDERR && (scsi_status & BSR_PHVALID) == 0) { pep = &ct_cmderr[scsi_status & BSR_PM]; slp->sl_error |= pep->pe_err; if ((pep->pe_err & PARITYERR) != 0) { if (ti->ti_phase == PH_MSGIN) msg = SCSI_LOW_MSG_PARITY; else msg = SCSI_LOW_MSG_ERROR; } else msg = pep->pe_errmsg; if (msg != 0) scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1); if (pep->pe_msg != NULL) { device_printf(slp->sl_dev, "phase error: %s", pep->pe_msg); scsi_low_print(slp, slp->sl_Tnexus); } if (pep->pe_done != 0) scsi_low_disconnected(slp, ti); } else { slp->sl_error |= FATALIO; scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error"); } } /************************************************** * ### SCSI PHASE SEQUENCER ### **************************************************/ static int ct_reselected(struct ct_softc *ct, u_int8_t scsi_status) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct targ_info *ti; u_int sid; u_int8_t regv; ct->sc_atten = 0; ct->sc_satgo &= ~CT_SAT_GOING; regv = ct_cr_read_1(chp, wd3s_sid); if ((regv & SIDR_VALID) == 0) return EJUSTRETURN; sid = regv & SIDR_IDM; if ((ti = scsi_low_reselected(slp, sid)) == NULL) return EJUSTRETURN; ct_target_nexus_establish(ct, 0, SCSI_LOW_READ); if (scsi_status != BSR_AFM_RESEL) return EJUSTRETURN; SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); regv = ct_cr_read_1(chp, wd3s_data); if (scsi_low_msgin(slp, ti, (u_int) regv) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { /* XXX: scsi_low_attetion */ scsi_low_attention(slp); } } if (ct->sc_atten != 0) { ct_attention(ct); } ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); return EJUSTRETURN; } static int ct_target_nexus_establish(struct ct_softc *ct, int lun, int dir) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct targ_info *ti = slp->sl_Tnexus; struct ct_targ_info *cti = (void *) ti; if (dir == SCSI_LOW_WRITE) ct_cr_write_1(chp, wd3s_did, ti->ti_id); else ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); ct_cr_write_1(chp, wd3s_lun, lun); ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); ct_cr_write_1(chp, wd3s_cph, 0); ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); cthw_set_count(chp, 0); return 0; } static int ct_lun_nexus_establish(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct lun_info *li = slp->sl_Lnexus; ct_cr_write_1(chp, wd3s_lun, li->li_lun); return 0; } static int ct_ccb_nexus_establish(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct lun_info *li = slp->sl_Lnexus; struct targ_info *ti = slp->sl_Tnexus; struct ct_targ_info *cti = (void *) ti; struct slccb *cb = slp->sl_Qnexus; ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; if ((ct->sc_satgo & CT_SAT_GOING) != 0) { ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); } if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) ct_cr_write_1(chp, wd3s_did, ti->ti_id); else ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); ct_cr_write_1(chp, wd3s_lun, li->li_lun); ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); return 0; } static int ct_unbusy(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; int wc; register u_int8_t regv; for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) { regv = ct_stat_read_1(chp); if ((regv & (STR_BSY | STR_CIP)) == 0) return 0; if (regv == (u_int8_t) -1) return EIO; DELAY(CT_DELAY_INTERVAL); } device_printf(slp->sl_dev, "unbusy timeout\n"); return EBUSY; } static int ct_catch_intr(struct ct_softc *ct) { struct ct_bus_access_handle *chp = &ct->sc_ch; int wc; register u_int8_t regv; for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) { regv = ct_stat_read_1(chp); if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT) return 0; DELAY(CT_DELAY_INTERVAL); } return EJUSTRETURN; } -int +void ctintr(void *arg) +{ + struct ct_softc *ct = arg; + struct scsi_low_softc *slp = &ct->sc_sclow; + + SCSI_LOW_LOCK(slp); + ct_poll(ct); + SCSI_LOW_UNLOCK(slp); +} + +static int +ct_poll(void *arg) { struct ct_softc *ct = arg; struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct targ_info *ti; struct buf *bp; u_int derror, flags; int len, satgo, error; u_int8_t scsi_status, regv; again: if (slp->sl_flags & HW_INACTIVE) return 0; /************************************************** * Get status & bus phase **************************************************/ if ((ct_stat_read_1(chp) & STR_INT) == 0) return 0; scsi_status = ct_cr_read_1(chp, wd3s_stat); if (scsi_status == ((u_int8_t) -1)) return 1; /************************************************** * Check reselection, or nexus **************************************************/ if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL) { if (ct_reselected(ct, scsi_status) == EJUSTRETURN) return 1; } if ((ti = slp->sl_Tnexus) == NULL) return 1; /************************************************** * Debug section **************************************************/ #ifdef CT_DEBUG if (ct_debug > 0) { scsi_low_print(slp, NULL); device_printf(slp->sl_dev, "scsi_status 0x%x\n\n", (u_int) scsi_status); #ifdef KDB if (ct_debug > 1) kdb_enter(KDB_WHY_CAM, "ct"); #endif /* KDB */ } #endif /* CT_DEBUG */ /************************************************** * Internal scsi phase **************************************************/ satgo = ct->sc_satgo; ct->sc_satgo &= ~CT_SAT_GOING; switch (ti->ti_phase) { case PH_SELSTART: if ((satgo & CT_SAT_GOING) == 0) { if (scsi_status != BSR_SELECTED) { ct_phase_error(ct, scsi_status); return 1; } scsi_low_arbit_win(slp); SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); return 1; } else { scsi_low_arbit_win(slp); SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */ } break; case PH_RESEL: if ((scsi_status & BSR_PHVALID) == 0 || (scsi_status & BSR_PM) != BSR_MSGIN) { scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase miss after reselect"); return 1; } break; default: if (slp->sl_flags & HW_PDMASTART) { slp->sl_flags &= ~HW_PDMASTART; if (ct->sc_dma & CT_DMA_DMASTART) { (*ct->ct_dma_xfer_stop) (ct); ct->sc_dma &= ~CT_DMA_DMASTART; } else if (ct->sc_dma & CT_DMA_PIOSTART) { (*ct->ct_pio_xfer_stop) (ct); ct->sc_dma &= ~CT_DMA_PIOSTART; } else { scsi_low_data_finish(slp); } } break; } /************************************************** * parse scsi phase **************************************************/ if (scsi_status & BSR_PHVALID) { /************************************************** * Normal SCSI phase. **************************************************/ if ((scsi_status & BSR_CM) == BSR_CMDABT) { ct_phase_error(ct, scsi_status); return 1; } switch (scsi_status & BSR_PM) { case BSR_DATAOUT: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) { ct_attention(ct); } goto common_data_phase; case BSR_DATAIN: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) { ct_attention(ct); } common_data_phase: if (slp->sl_scp.scp_datalen > 0) { slp->sl_flags |= HW_PDMASTART; if ((ct->sc_xmode & CT_XMODE_PIO) != 0) { error = (*ct->ct_pio_xfer_start) (ct); if (error == 0) { ct->sc_dma |= CT_DMA_PIOSTART; return 1; } } if ((ct->sc_xmode & CT_XMODE_DMA) != 0) { error = (*ct->ct_dma_xfer_start) (ct); if (error == 0) { ct->sc_dma |= CT_DMA_DMASTART; return 1; } } } else { if (slp->sl_scp.scp_direction == SCSI_LOW_READ) { if (!(slp->sl_flags & HW_READ_PADDING)) { device_printf(slp->sl_dev, "read padding required\n"); return 1; } } else { if (!(slp->sl_flags & HW_WRITE_PADDING)) { device_printf(slp->sl_dev, "write padding required\n"); return 1; } } slp->sl_flags |= HW_PDMASTART; } ct_io_xfer(ct); return 1; case BSR_CMDOUT: SCSI_LOW_SETUP_PHASE(ti, PH_CMD); if (scsi_low_cmd(slp, ti) != 0) { ct_attention(ct); } if (ct_xfer(ct, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen, SCSI_LOW_WRITE, &derror) != 0) { device_printf(slp->sl_dev, "scsi cmd xfer short\n"); } return 1; case BSR_STATIN: SCSI_LOW_SETUP_PHASE(ti, PH_STAT); if ((ct_io_control & CT_USE_CCSEQ) != 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0 || ct->sc_atten != 0) { ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); scsi_low_statusin(slp, ti, regv | derror); } else { ct->sc_satgo |= CT_SAT_GOING; cthw_set_count(chp, 0); cthw_phase_bypass(ct, 0x41); } } else { ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); scsi_low_statusin(slp, ti, regv | derror); } return 1; case BSR_UNSPINFO0: case BSR_UNSPINFO1: device_printf(slp->sl_dev, "illegal bus phase (0x%x)\n", (u_int) scsi_status); scsi_low_print(slp, ti); return 1; case BSR_MSGOUT: SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); flags = SCSI_LOW_MSGOUT_UNIFY; if (ti->ti_ophase != ti->ti_phase) flags |= SCSI_LOW_MSGOUT_INIT; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { ct_attention(ct); } if (ct_xfer(ct, ti->ti_msgoutstr, len, SCSI_LOW_WRITE, &derror) != 0) { device_printf(slp->sl_dev, "scsi msgout xfer short\n"); } SCSI_LOW_DEASSERT_ATN(slp); ct->sc_atten = 0; return 1; case BSR_MSGIN:/* msg in */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); if (scsi_low_msgin(slp, ti, regv | derror) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { /* XXX: scsi_low_attetion */ scsi_low_attention(slp); } } if ((ct_io_control & CT_FAST_INTR) != 0) { if (ct_catch_intr(ct) == 0) goto again; } return 1; } } else { /************************************************** * Special SCSI phase **************************************************/ switch (scsi_status) { case BSR_SATSDP: /* SAT with save data pointer */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); ct->sc_satgo |= CT_SAT_GOING; scsi_low_msgin(slp, ti, MSG_SAVESP); cthw_phase_bypass(ct, 0x41); return 1; case BSR_SATFIN: /* SAT COMPLETE */ /* * emulate statusin => msgin */ SCSI_LOW_SETUP_PHASE(ti, PH_STAT); scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun)); SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); scsi_low_msgin(slp, ti, MSG_COMP); scsi_low_disconnected(slp, ti); return 1; case BSR_ACKREQ: /* negate ACK */ if (ct->sc_atten != 0) { ct_attention(ct); } ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); if ((ct_io_control & CT_FAST_INTR) != 0) { /* XXX: * Should clear a pending interrupt and * sync with a next interrupt! */ ct_catch_intr(ct); } return 1; case BSR_DISC: /* disconnect */ if (slp->sl_msgphase == MSGPH_NULL && (satgo & CT_SAT_GOING) != 0) { /* * emulate disconnect msg */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); scsi_low_msgin(slp, ti, MSG_DISCON); } scsi_low_disconnected(slp, ti); return 1; default: break; } } ct_phase_error(ct, scsi_status); return 1; } diff --git a/sys/dev/ct/ct_isa.c b/sys/dev/ct/ct_isa.c index d17af2358464..444d9f75b108 100644 --- a/sys/dev/ct/ct_isa.c +++ b/sys/dev/ct/ct_isa.c @@ -1,390 +1,382 @@ /* $NecBSD: ct_isa.c,v 1.6 1999/07/26 06:32:01 honda Exp $ */ #include __FBSDID("$FreeBSD$"); /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define SCSIBUS_RESCAN #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BSHW_IOSZ 0x08 #define BSHW_IOBASE 0xcc0 #define BSHW_MEMSZ (PAGE_SIZE * 2) static int ct_isa_match(device_t); static int ct_isa_attach(device_t); static int ct_space_map(device_t, struct bshw *, struct resource **, struct resource **); static void ct_space_unmap(device_t, struct ct_softc *); static struct bshw *ct_find_hw(device_t); static void ct_dmamap(void *, bus_dma_segment_t *, int, int); static void ct_isa_bus_access_weight(struct ct_bus_access_handle *); static void ct_isa_dmasync_before(struct ct_softc *); static void ct_isa_dmasync_after(struct ct_softc *); struct ct_isa_softc { struct ct_softc sc_ct; struct bshw_softc sc_bshw; }; static struct isa_pnp_id ct_pnp_ids[] = { { 0x0100e7b1, "Logitec LHA-301" }, { 0x110154dc, "I-O DATA SC-98III" }, { 0x4120acb4, "MELCO IFC-NN" }, { 0, NULL } }; static device_method_t ct_isa_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ct_isa_match), DEVMETHOD(device_attach, ct_isa_attach), { 0, 0 } }; static driver_t ct_isa_driver = { "ct", ct_isa_methods, sizeof(struct ct_isa_softc), }; static devclass_t ct_devclass; DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, 0, 0); static int ct_isa_match(device_t dev) { struct bshw *hw; struct resource *port_res, *mem_res; struct ct_bus_access_handle ch; int rv; if (ISA_PNP_PROBE(device_get_parent(dev), dev, ct_pnp_ids) == ENXIO) return ENXIO; switch (isa_get_logicalid(dev)) { case 0x0100e7b1: /* LHA-301 */ case 0x110154dc: /* SC-98III */ case 0x4120acb4: /* IFC-NN */ /* XXX - force to SMIT mode */ device_set_flags(dev, device_get_flags(dev) | 0x40000); break; } if (isa_get_port(dev) == -1) bus_set_resource(dev, SYS_RES_IOPORT, 0, BSHW_IOBASE, BSHW_IOSZ); if ((hw = ct_find_hw(dev)) == NULL) return ENXIO; if (ct_space_map(dev, hw, &port_res, &mem_res) != 0) return ENXIO; bzero(&ch, sizeof(ch)); - ch.ch_iot = rman_get_bustag(port_res); - ch.ch_ioh = rman_get_bushandle(port_res), + ch.ch_io = port_res; ch.ch_bus_weight = ct_isa_bus_access_weight; rv = ctprobesubr(&ch, 0, BSHW_DEFAULT_HOSTID, BSHW_DEFAULT_CHIPCLK, NULL); if (rv != 0) { struct bshw_softc bshw_tab; struct bshw_softc *bs = &bshw_tab; memset(bs, 0, sizeof(*bs)); bshw_read_settings(&ch, bs); bus_set_resource(dev, SYS_RES_IRQ, 0, bs->sc_irq, 1); bus_set_resource(dev, SYS_RES_DRQ, 0, bs->sc_drq, 1); } bus_release_resource(dev, SYS_RES_IOPORT, 0, port_res); if (mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, mem_res); if (rv != 0) - return 0; + return (BUS_PROBE_DEFAULT); return ENXIO; } static int ct_isa_attach(device_t dev) { struct ct_isa_softc *pct = device_get_softc(dev); struct ct_softc *ct = &pct->sc_ct; struct ct_bus_access_handle *chp = &ct->sc_ch; struct scsi_low_softc *slp = &ct->sc_sclow; struct bshw_softc *bs = &pct->sc_bshw; struct bshw *hw; int irq_rid, drq_rid, chiprev; u_int8_t *vaddr; bus_addr_t addr; - intrmask_t s; hw = ct_find_hw(dev); if (ct_space_map(dev, hw, &ct->port_res, &ct->mem_res) != 0) { device_printf(dev, "bus io mem map failed\n"); return ENXIO; } - bzero(chp, sizeof(*chp)); - chp->ch_iot = rman_get_bustag(ct->port_res); - chp->ch_ioh = rman_get_bushandle(ct->port_res); - if (ct->mem_res) { - chp->ch_memt = rman_get_bustag(ct->mem_res); - chp->ch_memh = rman_get_bushandle(ct->mem_res); - } + chp->ch_io = ct->port_res; + chp->ch_mem = ct->mem_res; chp->ch_bus_weight = ct_isa_bus_access_weight; irq_rid = 0; ct->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, RF_ACTIVE); drq_rid = 0; ct->drq_res = bus_alloc_resource_any(dev, SYS_RES_DRQ, &drq_rid, RF_ACTIVE); if (ct->irq_res == NULL || ct->drq_res == NULL) { ct_space_unmap(dev, ct); return ENXIO; } if (ctprobesubr(chp, 0, BSHW_DEFAULT_HOSTID, BSHW_DEFAULT_CHIPCLK, &chiprev) == 0) { device_printf(dev, "hardware missing\n"); ct_space_unmap(dev, ct); return ENXIO; } /* setup DMA map */ if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXBSIZE, 1, BUS_SPACE_MAXSIZE_32BIT, BUS_DMA_ALLOCNOW, NULL, NULL, &ct->sc_dmat) != 0) { device_printf(dev, "can't set up ISA DMA map\n"); ct_space_unmap(dev, ct); return ENXIO; } if (bus_dmamem_alloc(ct->sc_dmat, (void **)&vaddr, BUS_DMA_NOWAIT, &ct->sc_dmamapt) != 0) { device_printf(dev, "can't set up ISA DMA map\n"); ct_space_unmap(dev, ct); return ENXIO; } bus_dmamap_load(ct->sc_dmat, ct->sc_dmamapt, vaddr, MAXBSIZE, ct_dmamap, &addr, BUS_DMA_NOWAIT); /* setup machdep softc */ bs->sc_hw = hw; bs->sc_io_control = 0; bs->sc_bounce_phys = (u_int8_t *)addr; bs->sc_bounce_addr = vaddr; bs->sc_bounce_size = MAXBSIZE; bs->sc_minphys = (1 << 24); bs->sc_dmasync_before = ct_isa_dmasync_before; bs->sc_dmasync_after = ct_isa_dmasync_after; bshw_read_settings(chp, bs); /* setup ct driver softc */ ct->ct_hw = bs; ct->ct_dma_xfer_start = bshw_dma_xfer_start; ct->ct_pio_xfer_start = bshw_smit_xfer_start; ct->ct_dma_xfer_stop = bshw_dma_xfer_stop; ct->ct_pio_xfer_stop = bshw_smit_xfer_stop; ct->ct_bus_reset = bshw_bus_reset; ct->ct_synch_setup = bshw_synch_setup; ct->sc_xmode = CT_XMODE_DMA; - if (chp->ch_memh != NULL) + if (chp->ch_mem != NULL) ct->sc_xmode |= CT_XMODE_PIO; ct->sc_chiprev = chiprev; switch (chiprev) { case CT_WD33C93: /* s = "WD33C93"; */ ct->sc_chipclk = 8; break; case CT_WD33C93_A: if (DVCFG_MAJOR(device_get_flags(dev)) > 0) { /* s = "AM33C93_A"; */ ct->sc_chipclk = 20; ct->sc_chiprev = CT_AM33C93_A; } else { /* s = "WD33C93_A"; */ ct->sc_chipclk = 10; } break; case CT_AM33C93_A: /* s = "AM33C93_A"; */ ct->sc_chipclk = 20; break; default: case CT_WD33C93_B: /* s = "WD33C93_B"; */ ct->sc_chipclk = 20; break; } #if 0 printf("%s: chiprev %s chipclk %d MHz\n", slp->sl_dev.dv_xname, s, ct->sc_chipclk); #endif slp->sl_dev = dev; slp->sl_hostid = bs->sc_hostid; slp->sl_cfgflags = device_get_flags(dev); + mtx_init(&slp->sl_lock, "ct", NULL, MTX_DEF); - s = splcam(); ctattachsubr(ct); - splx(s); - if (bus_setup_intr(dev, ct->irq_res, INTR_TYPE_CAM, - NULL, (driver_intr_t *)ctintr, ct, &ct->sc_ih)) { + if (bus_setup_intr(dev, ct->irq_res, INTR_TYPE_CAM | INTR_MPSAFE, + NULL, ctintr, ct, &ct->sc_ih)) { ct_space_unmap(dev, ct); return ENXIO; } return 0; } static struct bshw * ct_find_hw(device_t dev) { return DVCFG_HW(&bshw_hwsel, DVCFG_MAJOR(device_get_flags(dev))); } static int ct_space_map(device_t dev, struct bshw *hw, struct resource **iohp, struct resource **memhp) { int port_rid, mem_rid; *memhp = NULL; port_rid = 0; - *iohp = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 0, ~0, + *iohp = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 0ul, ~0ul, BSHW_IOSZ, RF_ACTIVE); if (*iohp == NULL) return ENXIO; if ((hw->hw_flags & BSHW_SMFIFO) == 0 || isa_get_maddr(dev) == -1) return 0; mem_rid = 0; - *memhp = bus_alloc_resource(dev, SYS_RES_MEMORY, &mem_rid, 0, ~0, + *memhp = bus_alloc_resource(dev, SYS_RES_MEMORY, &mem_rid, 0ul, ~0ul, BSHW_MEMSZ, RF_ACTIVE); if (*memhp == NULL) { bus_release_resource(dev, SYS_RES_IOPORT, port_rid, *iohp); return ENXIO; } return 0; } static void ct_space_unmap(device_t dev, struct ct_softc *ct) { if (ct->port_res != NULL) bus_release_resource(dev, SYS_RES_IOPORT, 0, ct->port_res); if (ct->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, ct->mem_res); if (ct->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, ct->irq_res); if (ct->drq_res != NULL) bus_release_resource(dev, SYS_RES_DRQ, 0, ct->drq_res); } static void ct_dmamap(void *arg, bus_dma_segment_t *seg, int nseg, int error) { bus_addr_t *addr = (bus_addr_t *)arg; *addr = seg->ds_addr; } static void ct_isa_bus_access_weight(struct ct_bus_access_handle *chp) { outb(0x5f, 0); } static void ct_isa_dmasync_before(struct ct_softc *ct) { if (need_pre_dma_flush) wbinvd(); } static void ct_isa_dmasync_after(struct ct_softc *ct) { if (need_post_dma_flush) invd(); } diff --git a/sys/dev/ct/ct_machdep.h b/sys/dev/ct/ct_machdep.h index a6b8b1551989..7d92526125eb 100644 --- a/sys/dev/ct/ct_machdep.h +++ b/sys/dev/ct/ct_machdep.h @@ -1,196 +1,186 @@ /* $FreeBSD$ */ /* $NecBSD: ct_machdep.h,v 1.4.12.2 2001/06/20 06:13:34 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _CT_MACHDEP_H_ #define _CT_MACHDEP_H_ #include "opt_ct.h" /* * Principal rules: * 1) do not use bus_space_write/read_X directly in ct.c. * 2) do not use port offset defs directly in ct.c. */ /* special weight if requried */ #ifdef CT_BUS_WEIGHT #undef CT_BUS_WEIGHT #define CT_BUS_WEIGHT(chp) \ { \ if ((chp)->ch_bus_weight != NULL) \ (chp)->ch_bus_weight((chp)); \ } #else /* !CT_BUS_WEIGHT */ #define CT_BUS_WEIGHT(chp) #endif /* !CT_BUS_WEIGHT */ /* port offset */ #ifndef CT_USE_RELOCATE_OFFSET #define addr_port 0 #define stat_port 0 #define ctrl_port 2 #define cmd_port 4 #else /* CT_USE_RELOCATE_OFFSET */ #define addr_port ((chp)->ch_offset[0]) #define stat_port ((chp)->ch_offset[1]) #define ctrl_port ((chp)->ch_offset[2]) #define cmd_port ((chp)->ch_offset[3]) #endif /* CT_USE_RELOCATE_OFFSET */ /* * All port accesses primitive methods */ static __inline u_int8_t ct_stat_read_1 (struct ct_bus_access_handle *); static __inline u_int8_t ct_cmdp_read_1 (struct ct_bus_access_handle *); static __inline void ct_cmdp_write_1 (struct ct_bus_access_handle *, u_int8_t); static __inline u_int8_t ct_cr_read_1 (struct ct_bus_access_handle *, bus_addr_t); static __inline void ct_cr_write_1 (struct ct_bus_access_handle *, bus_addr_t, u_int8_t); static __inline void ct_write_cmds (struct ct_bus_access_handle *, u_int8_t *, int); static __inline u_int cthw_get_count (struct ct_bus_access_handle *); static __inline void cthw_set_count (struct ct_bus_access_handle *, u_int); static __inline u_int8_t ct_stat_read_1(struct ct_bus_access_handle *chp) { u_int8_t regv; - regv = bus_space_read_1(chp->ch_iot, chp->ch_ioh, stat_port); + regv = bus_read_1(chp->ch_io, stat_port); CT_BUS_WEIGHT(chp) return regv; } static __inline void cthw_set_count(struct ct_bus_access_handle *chp, u_int count) { - bus_space_tag_t bst = chp->ch_iot; - bus_space_handle_t bsh = chp->ch_ioh; - bus_space_write_1(bst, bsh, addr_port, wd3s_cnt); + bus_write_1(chp->ch_io, addr_port, wd3s_cnt); CT_BUS_WEIGHT(chp) - bus_space_write_1(bst, bsh, ctrl_port, count >> 16); + bus_write_1(chp->ch_io, ctrl_port, count >> 16); CT_BUS_WEIGHT(chp) - bus_space_write_1(bst, bsh, ctrl_port, count >> 8); + bus_write_1(chp->ch_io, ctrl_port, count >> 8); CT_BUS_WEIGHT(chp) - bus_space_write_1(bst, bsh, ctrl_port, count); + bus_write_1(chp->ch_io, ctrl_port, count); CT_BUS_WEIGHT(chp) } static __inline u_int cthw_get_count(struct ct_bus_access_handle *chp) { - bus_space_tag_t bst = chp->ch_iot; - bus_space_handle_t bsh = chp->ch_ioh; u_int count; - bus_space_write_1(bst, bsh, addr_port, wd3s_cnt); + bus_write_1(chp->ch_io, addr_port, wd3s_cnt); CT_BUS_WEIGHT(chp) - count = (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 16); + count = (((u_int) bus_read_1(chp->ch_io, ctrl_port)) << 16); CT_BUS_WEIGHT(chp) - count += (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 8); + count += (((u_int) bus_read_1(chp->ch_io, ctrl_port)) << 8); CT_BUS_WEIGHT(chp) - count += ((u_int) bus_space_read_1(bst, bsh, ctrl_port)); + count += ((u_int) bus_read_1(chp->ch_io, ctrl_port)); CT_BUS_WEIGHT(chp) return count; } static __inline void ct_write_cmds(struct ct_bus_access_handle *chp, u_int8_t *cmd, int len) { - bus_space_tag_t bst = chp->ch_iot; - bus_space_handle_t bsh = chp->ch_ioh; int i; - bus_space_write_1(bst, bsh, addr_port, wd3s_cdb); + bus_write_1(chp->ch_io, addr_port, wd3s_cdb); CT_BUS_WEIGHT(chp) for (i = 0; i < len; i ++) { - bus_space_write_1(bst, bsh, ctrl_port, cmd[i]); + bus_write_1(chp->ch_io, ctrl_port, cmd[i]); CT_BUS_WEIGHT(chp) } } static __inline u_int8_t ct_cr_read_1(struct ct_bus_access_handle *chp, bus_addr_t offs) { - bus_space_tag_t bst = chp->ch_iot; - bus_space_handle_t bsh = chp->ch_ioh; u_int8_t regv; - bus_space_write_1(bst, bsh, addr_port, offs); + bus_write_1(chp->ch_io, addr_port, offs); CT_BUS_WEIGHT(chp) - regv = bus_space_read_1(bst, bsh, ctrl_port); + regv = bus_read_1(chp->ch_io, ctrl_port); CT_BUS_WEIGHT(chp) return regv; } static __inline void ct_cr_write_1(struct ct_bus_access_handle *chp, bus_addr_t offs, u_int8_t val) { - bus_space_tag_t bst = chp->ch_iot; - bus_space_handle_t bsh = chp->ch_ioh; - bus_space_write_1(bst, bsh, addr_port, offs); + bus_write_1(chp->ch_io, addr_port, offs); CT_BUS_WEIGHT(chp) - bus_space_write_1(bst, bsh, ctrl_port, val); + bus_write_1(chp->ch_io, ctrl_port, val); CT_BUS_WEIGHT(chp) } static __inline u_int8_t ct_cmdp_read_1(struct ct_bus_access_handle *chp) { u_int8_t regv; - regv = bus_space_read_1(chp->ch_iot, chp->ch_ioh, cmd_port); + regv = bus_read_1(chp->ch_io, cmd_port); CT_BUS_WEIGHT(chp) return regv; } static __inline void ct_cmdp_write_1(struct ct_bus_access_handle *chp, u_int8_t val) { - bus_space_write_1(chp->ch_iot, chp->ch_ioh, cmd_port, val); + bus_write_1(chp->ch_io, cmd_port, val); CT_BUS_WEIGHT(chp) } #endif /* !_CT_MACHDEP_H_ */ diff --git a/sys/dev/ct/ctvar.h b/sys/dev/ct/ctvar.h index 052542ea2d26..10ce2d891200 100644 --- a/sys/dev/ct/ctvar.h +++ b/sys/dev/ct/ctvar.h @@ -1,136 +1,129 @@ /* $FreeBSD$ */ /* $NecBSD: ctvar.h,v 1.4.14.3 2001/06/20 06:13:34 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _CTVAR_H_ #define _CTVAR_H_ /* * ctvar.h * Generic wd33c93 chip driver's definitions */ /***************************************************************** * Host adapter structure *****************************************************************/ struct ct_bus_access_handle { - bus_space_tag_t ch_iot; /* core chip ctrl port tag */ - bus_space_tag_t ch_delayt; /* delay port tag */ - bus_space_tag_t ch_datat; /* data port tag (pio) */ - bus_space_tag_t ch_memt; /* data port tag (shm) */ - - bus_space_handle_t ch_ioh; - bus_space_handle_t ch_delaybah; - bus_space_handle_t ch_datah; - bus_space_handle_t ch_memh; + struct resource *ch_io; /* core chip ctrl port */ + struct resource *ch_mem; /* data port (shm) */ void (*ch_bus_weight)(struct ct_bus_access_handle *); #ifdef CT_USE_RELOCATE_OFFSET bus_addr_t ch_offset[4]; #endif /* CT_USE_RELOCATE_OFFSET */ }; struct ct_softc { struct scsi_low_softc sc_sclow; /* generic data */ struct ct_bus_access_handle sc_ch; /* bus access handle */ struct resource *port_res; struct resource *mem_res; struct resource *irq_res; struct resource *drq_res; bus_dma_tag_t sc_dmat; /* data DMA tag */ bus_dmamap_t sc_dmamapt; /* data DMAMAP tag */ void *sc_ih; int sc_chiprev; /* chip version */ #define CT_WD33C93 0x00000 #define CT_WD33C93_A 0x10000 #define CT_AM33C93_A 0x10001 #define CT_WD33C93_B 0x20000 #define CT_WD33C93_C 0x30000 int sc_xmode; #define CT_XMODE_PIO 1 #define CT_XMODE_DMA 2 int sc_dma; /* dma transfer start */ #define CT_DMA_PIOSTART 1 #define CT_DMA_DMASTART 2 int sc_satgo; /* combination cmd start */ #define CT_SAT_GOING 1 int sc_tmaxcnt; int sc_atten; /* attention */ u_int8_t sc_creg; /* control register value */ int sc_chipclk; /* chipclk 0, 10, 15, 20 */ struct ct_synch_data { u_int cs_period; u_int cs_syncr; } *sc_sdp; /* synchronous data table pt */ struct ct_synch_data sc_default_sdt[16]; /* * Machdep stuff. */ void *ct_hw; /* point to bshw_softc etc ... */ int (*ct_dma_xfer_start)(struct ct_softc *); int (*ct_pio_xfer_start)(struct ct_softc *); void (*ct_dma_xfer_stop)(struct ct_softc *); void (*ct_pio_xfer_stop)(struct ct_softc *); void (*ct_bus_reset)(struct ct_softc *); void (*ct_synch_setup)(struct ct_softc *, struct targ_info *); }; /***************************************************************** * Lun information *****************************************************************/ struct ct_targ_info { struct targ_info cti_ti; u_int8_t cti_syncreg; }; /***************************************************************** * PROTO *****************************************************************/ int ctprobesubr(struct ct_bus_access_handle *, u_int, int, u_int, int *); void ctattachsubr(struct ct_softc *); -int ctintr(void *); +void ctintr(void *); #endif /* !_CTVAR_H_ */ diff --git a/sys/dev/ncv/ncr53c500.c b/sys/dev/ncv/ncr53c500.c index 3bbded420836..836268281e48 100644 --- a/sys/dev/ncv/ncr53c500.c +++ b/sys/dev/ncv/ncr53c500.c @@ -1,1289 +1,1238 @@ /* $NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $ */ /* $NetBSD$ */ #define NCV_DEBUG #define NCV_STATICS #define NCV_IO_CONTROL_FLAGS (0) /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #define NCV_MAX_DATA_SIZE (64 * 1024) #define NCV_DELAY_MAX (2 * 1000 * 1000) #define NCV_DELAY_INTERVAL (1) #define NCV_PADDING_SIZE (32) /*************************************************** * IO control ***************************************************/ #define NCV_READ_INTERRUPTS_DRIVEN 0x0001 #define NCV_WRITE_INTERRUPTS_DRIVEN 0x0002 #define NCV_ENABLE_FAST_SCSI 0x0010 #define NCV_FAST_INTERRUPTS 0x0100 u_int ncv_io_control = NCV_IO_CONTROL_FLAGS; int ncv_data_read_bytes = 4096; int ncv_data_write_bytes = 4096; /*************************************************** * DEBUG ***************************************************/ #ifdef NCV_DEBUG static int ncv_debug; #endif /* NCV_DEBUG */ #ifdef NCV_STATICS static struct ncv_statics { int disconnect; int reselect; } ncv_statics; #endif /* NCV_STATICS */ /*************************************************** * DEVICE STRUCTURE ***************************************************/ extern struct cfdriver ncv_cd; /************************************************************** * DECLARE **************************************************************/ /* static */ static void ncv_pio_read(struct ncv_softc *, u_int8_t *, u_int); static void ncv_pio_write(struct ncv_softc *, u_int8_t *, u_int); static int ncv_msg(struct ncv_softc *, struct targ_info *, u_int); static int ncv_reselected(struct ncv_softc *); static int ncv_disconnected(struct ncv_softc *, struct targ_info *); -static __inline void ncvhw_set_count(bus_space_tag_t, bus_space_handle_t, int); -static __inline u_int ncvhw_get_count(bus_space_tag_t, bus_space_handle_t); -static __inline void ncvhw_select_register_0(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); -static __inline void ncvhw_select_register_1(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); -static __inline void ncvhw_fpush(bus_space_tag_t, bus_space_handle_t, u_int8_t *, int); +static __inline void ncvhw_set_count(struct resource *, int); +static __inline u_int ncvhw_get_count(struct resource *); +static __inline void ncvhw_select_register_0(struct resource *, struct ncv_hw *); +static __inline void ncvhw_select_register_1(struct resource *, struct ncv_hw *); +static __inline void ncvhw_fpush(struct resource *, u_int8_t *, int); static void ncv_pdma_end(struct ncv_softc *sc, struct targ_info *); static int ncv_world_start(struct ncv_softc *, int); static void ncvhw_bus_reset(struct ncv_softc *); -static void ncvhw_reset(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); -static int ncvhw_check(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); -static void ncvhw_init(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); +static void ncvhw_reset(struct resource *, struct ncv_hw *); +static int ncvhw_check(struct resource *, struct ncv_hw *); +static void ncvhw_init(struct resource *, struct ncv_hw *); static int ncvhw_start_selection(struct ncv_softc *sc, struct slccb *); static void ncvhw_attention(struct ncv_softc *); static int ncv_ccb_nexus_establish(struct ncv_softc *); static int ncv_lun_nexus_establish(struct ncv_softc *); static int ncv_target_nexus_establish(struct ncv_softc *); static int ncv_targ_init(struct ncv_softc *, struct targ_info *, int); static int ncv_catch_intr(struct ncv_softc *); #ifdef NCV_POWER_CONTROL static int ncvhw_power(struct ncv_softc *, u_int); #endif /* NCV_POWER_CONTROL */ static __inline void ncv_setup_and_start_pio(struct ncv_softc *, u_int); struct scsi_low_funcs ncv_funcs = { SC_LOW_INIT_T ncv_world_start, SC_LOW_BUSRST_T ncvhw_bus_reset, SC_LOW_TARG_INIT_T ncv_targ_init, SC_LOW_LUN_INIT_T NULL, SC_LOW_SELECT_T ncvhw_start_selection, SC_LOW_NEXUS_T ncv_lun_nexus_establish, SC_LOW_NEXUS_T ncv_ccb_nexus_establish, SC_LOW_ATTEN_T ncvhw_attention, SC_LOW_MSG_T ncv_msg, SC_LOW_TIMEOUT_T NULL, SC_LOW_POLL_T ncvintr, NULL, /* SC_LOW_POWER_T ncvhw_power, */ }; /************************************************************** * hwfuncs **************************************************************/ static __inline void -ncvhw_select_register_0(iot, ioh, hw) - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct ncv_hw *hw; +ncvhw_select_register_0(struct resource *res, struct ncv_hw *hw) { - bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4); + bus_write_1(res, cr0_cfg4, hw->hw_cfg4); } static __inline void -ncvhw_select_register_1(iot, ioh, hw) - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct ncv_hw *hw; +ncvhw_select_register_1(struct resource *res, struct ncv_hw *hw) { - bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5); + bus_write_1(res, cr1_cfg5, hw->hw_cfg5); } static __inline void -ncvhw_fpush(iot, ioh, buf, len) - bus_space_tag_t iot; - bus_space_handle_t ioh; - u_int8_t *buf; - int len; +ncvhw_fpush(struct resource *res, u_int8_t *buf, int len) { int ptr; for (ptr = 0; ptr < len; ptr ++) - bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]); + bus_write_1(res, cr0_sfifo, buf[ptr]); } static __inline void -ncvhw_set_count(iot, ioh, count) - bus_space_tag_t iot; - bus_space_handle_t ioh; - int count; +ncvhw_set_count(struct resource *res, int count) { - bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count); - bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY)); - bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2))); + bus_write_1(res, cr0_tclsb, (u_int8_t) count); + bus_write_1(res, cr0_tcmsb, (u_int8_t) (count >> NBBY)); + bus_write_1(res, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2))); } static __inline u_int -ncvhw_get_count(iot, ioh) - bus_space_tag_t iot; - bus_space_handle_t ioh; +ncvhw_get_count(struct resource *res) { u_int count; - count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb); - count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY; - count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2); + count = (u_int) bus_read_1(res, cr0_tclsb); + count |= ((u_int) bus_read_1(res, cr0_tcmsb)) << NBBY; + count |= ((u_int) bus_read_1(res, cr0_tchsb)) << (NBBY * 2); return count; } static int -ncvhw_check(iot, ioh, hw) - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct ncv_hw *hw; +ncvhw_check(struct resource *res, struct ncv_hw *hw) { u_int8_t stat; - ncvhw_select_register_0(iot, ioh, hw); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); - if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA)) + ncvhw_select_register_0(res, hw); + bus_write_1(res, cr0_cmd, CMD_NOP | CMD_DMA); + if (bus_read_1(res, cr0_cmd) != (CMD_NOP | CMD_DMA)) { #ifdef NCV_DEBUG printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n"); #endif /* NCV_DEBUG */ return ENODEV; } - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); - if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP) + bus_write_1(res, cr0_cmd, CMD_NOP); + if (bus_read_1(res, cr0_cmd) != CMD_NOP) { #ifdef NCV_DEBUG printf("ncv: cr0_cmd CMD_NOP failed\n"); #endif /* NCV_DEBUG */ return ENODEV; } /* hardware reset */ - ncvhw_reset(iot, ioh, hw); - ncvhw_init(iot, ioh, hw); + ncvhw_reset(res, hw); + ncvhw_init(res, hw); /* bus reset */ - ncvhw_select_register_0(iot, ioh, hw); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); + ncvhw_select_register_0(res, hw); + bus_write_1(res, cr0_cmd, CMD_FLUSH); + bus_write_1(res, cr0_cmd, CMD_RSTSCSI); + bus_write_1(res, cr0_cmd, CMD_NOP | CMD_DMA); DELAY(100 * 1000); /* check response */ - bus_space_read_1(iot, ioh, cr0_stat); - stat = bus_space_read_1(iot, ioh, cr0_istat); + bus_read_1(res, cr0_stat); + stat = bus_read_1(res, cr0_istat); DELAY(1000); if (((stat & INTR_SBR) == 0) || - (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR)) + (bus_read_1(res, cr0_istat) & INTR_SBR)) { #ifdef NCV_DEBUG printf("ncv: cr0_istat SCSI BUS RESET failed\n"); #endif /* NCV_DEBUG */ return ENODEV; } return 0; } static void -ncvhw_reset(iot, ioh, hw) - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct ncv_hw *hw; +ncvhw_reset(struct resource *res, struct ncv_hw *hw) { - ncvhw_select_register_0(iot, ioh, hw); + ncvhw_select_register_0(res, hw); /* dummy cmd twice */ - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + bus_write_1(res, cr0_cmd, CMD_NOP); + bus_write_1(res, cr0_cmd, CMD_NOP); /* chip reset */ - bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP); + bus_write_1(res, cr0_cmd, CMD_RSTCHIP); /* again dummy cmd twice */ - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + bus_write_1(res, cr0_cmd, CMD_NOP); + bus_write_1(res, cr0_cmd, CMD_NOP); } static void -ncvhw_init(iot, ioh, hw) - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct ncv_hw *hw; +ncvhw_init(struct resource *res, struct ncv_hw *hw) { - ncvhw_select_register_0(iot, ioh, hw); - bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk); - bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT); - bus_space_write_1(iot, ioh, cr0_period, 0); - bus_space_write_1(iot, ioh, cr0_offs, 0); + ncvhw_select_register_0(res, hw); + bus_write_1(res, cr0_clk, hw->hw_clk); + bus_write_1(res, cr0_srtout, SEL_TOUT); + bus_write_1(res, cr0_period, 0); + bus_write_1(res, cr0_offs, 0); - bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1); - bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2); - bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3); - bus_space_write_1(iot, ioh, cr0_tchsb, 0); + bus_write_1(res, cr0_cfg1, hw->hw_cfg1); + bus_write_1(res, cr0_cfg2, hw->hw_cfg2); + bus_write_1(res, cr0_cfg3, hw->hw_cfg3); + bus_write_1(res, cr0_tchsb, 0); - ncvhw_select_register_1(iot, ioh, hw); - bus_space_write_1(iot, ioh, cr1_fstat, 0x0); - bus_space_write_1(iot, ioh, cr1_pflag, 0x0); - bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); + ncvhw_select_register_1(res, hw); + bus_write_1(res, cr1_fstat, 0x0); + bus_write_1(res, cr1_pflag, 0x0); + bus_write_1(res, cr1_atacmd, ATACMD_ENGAGE); - ncvhw_select_register_0(iot, ioh, hw); + ncvhw_select_register_0(res, hw); } #ifdef NCV_POWER_CONTROL static int ncvhw_power(sc, flags) struct ncv_softc *sc; u_int flags; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; if (flags == SCSI_LOW_POWDOWN) { device_printf(slp->sl_dev, "power down\n"); - ncvhw_select_register_1(iot, ioh, &sc->sc_hw); - bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN); + ncvhw_select_register_1(res, &sc->sc_hw); + bus_write_1(res, cr1_atacmd, ATACMD_POWDOWN); } else { switch (sc->sc_rstep) { case 0: device_printf(slp->sl_dev, "resume step O\n"); - ncvhw_select_register_1(iot, ioh, &sc->sc_hw); - bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); + ncvhw_select_register_1(res, &sc->sc_hw); + bus_write_1(res, cr1_atacmd, ATACMD_ENGAGE); break; case 1: device_printf(slp->sl_dev, "resume step I\n"); - ncvhw_reset(iot, ioh, &sc->sc_hw); - ncvhw_init(iot, ioh, &sc->sc_hw); + ncvhw_reset(res, &sc->sc_hw); + ncvhw_init(res, &sc->sc_hw); break; } } return 0; } #endif /* NCV_POWER_CONTROL */ /************************************************************** * scsi low interface **************************************************************/ static void ncvhw_attention(sc) struct ncv_softc *sc; { - bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN); + bus_write_1(sc->port_res, cr0_cmd, CMD_SETATN); DELAY(10); } static void ncvhw_bus_reset(sc) struct ncv_softc *sc; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); + ncvhw_select_register_0(sc->port_res, &sc->sc_hw); + bus_write_1(sc->port_res, cr0_cmd, CMD_FLUSH); + bus_write_1(sc->port_res, cr0_cmd, CMD_RSTSCSI); + bus_write_1(sc->port_res, cr0_cmd, CMD_NOP | CMD_DMA); } static int ncvhw_start_selection(sc, cb) struct ncv_softc *sc; struct slccb *cb; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; struct targ_info *ti = cb->ti; - int s, len; + int len; u_int flags; u_int8_t cmd; sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; sc->sc_compseq = 0; if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0) { cmd = CMD_SELATN; sc->sc_selstop = 0; flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT; } else if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0) { cmd = CMD_SELATN3; sc->sc_selstop = 0; flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT; } else { cmd = CMD_SELATNS; sc->sc_selstop = 1; flags = SCSI_LOW_MSGOUT_INIT; } - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); - if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0) + ncvhw_select_register_0(res, &sc->sc_hw); + if ((bus_read_1(res, cr0_stat) & STAT_INT) != 0) return SCSI_LOW_START_FAIL; ncv_target_nexus_establish(sc); len = scsi_low_msgout(slp, ti, flags); if (sc->sc_selstop == 0) scsi_low_cmd(slp, ti); - s = splhigh(); - if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0) - { - splx(s); + if ((bus_read_1(res, cr0_stat) & STAT_INT) != 0) return SCSI_LOW_START_FAIL; - } - bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); + bus_write_1(res, cr0_dstid, ti->ti_id); + bus_write_1(res, cr0_cmd, CMD_FLUSH); + ncvhw_fpush(res, ti->ti_msgoutstr, len); if (sc->sc_selstop == 0) { - ncvhw_fpush(iot, ioh, + ncvhw_fpush(res, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); } - bus_space_write_1(iot, ioh, cr0_cmd, cmd); - splx(s); + bus_write_1(res, cr0_cmd, cmd); SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); return SCSI_LOW_START_OK; } static int ncv_world_start(sc, fdone) struct ncv_softc *sc; int fdone; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; u_int8_t stat; if ((slp->sl_cfgflags & CFG_NOPARITY) == 0) sc->sc_hw.hw_cfg1 |= C1_PARENB; else sc->sc_hw.hw_cfg1 &= ~C1_PARENB; - ncvhw_reset(iot, ioh, &sc->sc_hw); - ncvhw_init(iot, ioh, &sc->sc_hw); + ncvhw_reset(res, &sc->sc_hw); + ncvhw_init(res, &sc->sc_hw); scsi_low_bus_reset(slp); - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); - bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat); - stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat); + ncvhw_select_register_0(res, &sc->sc_hw); + bus_read_1(res, cr0_stat); + stat = bus_read_1(res, cr0_istat); DELAY(1000); if (((stat & INTR_SBR) == 0) || - (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR)) + (bus_read_1(res, cr0_istat) & INTR_SBR)) return ENODEV; return 0; } static int ncv_msg(sc, ti, msg) struct ncv_softc *sc; struct targ_info *ti; u_int msg; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; struct ncv_targ_info *nti = (void *) ti; u_int hwcycle, period; if ((msg & SCSI_LOW_MSG_WIDE) != 0) { if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; return EINVAL; } return 0; } if ((msg & SCSI_LOW_MSG_SYNCH) == 0) return 0; period = ti->ti_maxsynch.period; hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk); hwcycle = 1000 / hwcycle; if (period < 200 / 4 && period >= 100 / 4) nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi; else nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi; period = ((period * 40 / hwcycle) + 5) / 10; nti->nti_reg_period = period & 0x1f; nti->nti_reg_offset = ti->ti_maxsynch.offset; - bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period); - bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset); - bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3); + bus_write_1(res, cr0_period, nti->nti_reg_period); + bus_write_1(res, cr0_offs, nti->nti_reg_offset); + bus_write_1(res, cr0_cfg3, nti->nti_reg_cfg3); return 0; } static int ncv_targ_init(sc, ti, action) struct ncv_softc *sc; struct targ_info *ti; int action; { struct ncv_targ_info *nti = (void *) ti; if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod; ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset; nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3; nti->nti_reg_period = 0; nti->nti_reg_offset = 0; } return 0; } /************************************************************** * General probe attach **************************************************************/ static int ncv_setup_img(struct ncv_hw *, u_int, int); static int ncv_setup_img(hw, dvcfg, hostid) struct ncv_hw *hw; u_int dvcfg; int hostid; { if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F) { printf("ncv: invalid dvcfg flags\n"); return EINVAL; } if (NCV_C5IMG(dvcfg) != 0) { hw->hw_cfg5 = NCV_C5IMG(dvcfg); hw->hw_clk = NCV_CLKFACTOR(dvcfg); if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 && (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0) hw->hw_mperiod = 100 / 4; if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG) hw->hw_cfg3_fclk = 0x04; if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1) hw->hw_cfg2 &= ~C2_SCSI2; if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW) hw->hw_cfg1 |= C1_SLOW; } /* setup configuration image 3 */ if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F) hw->hw_cfg3 &= ~hw->hw_cfg3_fclk; else hw->hw_cfg3 |= hw->hw_cfg3_fclk; /* setup configuration image 1 */ hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid; return 0; } int -ncvprobesubr(iot, ioh, dvcfg, hsid) - bus_space_tag_t iot; - bus_space_handle_t ioh; - u_int dvcfg; - int hsid; +ncvprobesubr(struct resource *res, u_int dvcfg, int hsid) { struct ncv_hw hwtab; hwtab = ncv_template; if (ncv_setup_img(&hwtab, dvcfg, hsid)) return 0; - if (ncvhw_check(iot, ioh, &hwtab) != 0) + if (ncvhw_check(res, &hwtab) != 0) return 0; return 1; } void ncvattachsubr(sc) struct ncv_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; printf("\n"); sc->sc_hw = ncv_template; ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid); slp->sl_funcs = &ncv_funcs; slp->sl_flags |= HW_READ_PADDING; sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ (void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS, sizeof(struct ncv_targ_info), 0); } /************************************************************** * PDMA **************************************************************/ static __inline void ncv_setup_and_start_pio(sc, reqlen) struct ncv_softc *sc; u_int reqlen; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); - ncvhw_set_count(iot, ioh, reqlen); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); + ncvhw_select_register_0(res, &sc->sc_hw); + ncvhw_set_count(res, reqlen); + bus_write_1(res, cr0_cmd, CMD_TRANS | CMD_DMA); - ncvhw_select_register_1(iot, ioh, &sc->sc_hw); - bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); + ncvhw_select_register_1(res, &sc->sc_hw); + bus_write_1(res, cr1_fstat, FIFO_EN); } static void ncv_pdma_end(sc, ti) struct ncv_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; int len; slp->sl_flags &= ~HW_PDMASTART; if (slp->sl_Qnexus == NULL) { slp->sl_error |= PDMAERR; goto out; } if (ti->ti_phase == PH_DATA) { - len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh); + len = ncvhw_get_count(res); if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) - len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh, + len += (bus_read_1(res, cr0_sffl) & CR0_SFFLR_BMASK); if ((u_int) len <= (u_int) sc->sc_sdatalen) { if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) && sc->sc_tdatalen != len) goto bad; len = sc->sc_sdatalen - len; if ((u_int) len > (u_int) slp->sl_scp.scp_datalen) goto bad; slp->sl_scp.scp_data += len; slp->sl_scp.scp_datalen -= len; } else { bad: if ((slp->sl_error & PDMAERR) == 0) { device_printf(slp->sl_dev, "strange cnt hw 0x%x soft 0x%x\n", len, slp->sl_scp.scp_datalen); } slp->sl_error |= PDMAERR; } scsi_low_data_finish(slp); } else { device_printf(slp->sl_dev, "data phase miss\n"); slp->sl_error |= PDMAERR; } out: - ncvhw_select_register_1(iot, ioh, &sc->sc_hw); - bus_space_write_1(iot, ioh, cr1_fstat, 0); - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + ncvhw_select_register_1(res, &sc->sc_hw); + bus_write_1(res, cr1_fstat, 0); + ncvhw_select_register_0(res, &sc->sc_hw); } static void ncv_pio_read(sc, buf, reqlen) struct ncv_softc *sc; u_int8_t *buf; u_int reqlen; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; int tout; register u_int8_t fstat; ncv_setup_and_start_pio(sc, reqlen); slp->sl_flags |= HW_PDMASTART; sc->sc_sdatalen = reqlen; tout = sc->sc_tmaxcnt; while (reqlen >= FIFO_F_SZ && tout -- > 0) { - fstat = bus_space_read_1(iot, ioh, cr1_fstat); + fstat = bus_read_1(res, cr1_fstat); if (fstat == (u_int8_t) -1) goto out; if (fstat & FIFO_F) { #define NCV_FAST32_ACCESS #ifdef NCV_FAST32_ACCESS - bus_space_read_multi_4(iot, ioh, cr1_fdata, + bus_read_multi_4(res, cr1_fdata, (u_int32_t *) buf, FIFO_F_SZ / 4); #else /* !NCV_FAST32_ACCESS */ - bus_space_read_multi_2(iot, ioh, cr1_fdata, + bus_read_multi_2(res, cr1_fdata, (u_int16_t *) buf, FIFO_F_SZ / 2); #endif /* !NCV_FAST32_ACCESS */ buf += FIFO_F_SZ; reqlen -= FIFO_F_SZ; } else { if (fstat & FIFO_BRK) break; DELAY(1); } } while (reqlen > 0 && tout -- > 0) { - fstat = bus_space_read_1(iot, ioh, cr1_fstat); + fstat = bus_read_1(res, cr1_fstat); if ((fstat & FIFO_E) == 0) { - *buf++ = bus_space_read_1(iot, ioh, cr1_fdata); + *buf++ = bus_read_1(res, cr1_fdata); reqlen --; } else { if (fstat & FIFO_BRK) break; DELAY(1); } } out: - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + ncvhw_select_register_0(res, &sc->sc_hw); sc->sc_tdatalen = reqlen; } static void ncv_pio_write(sc, buf, reqlen) struct ncv_softc *sc; u_int8_t *buf; u_int reqlen; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; int tout; register u_int8_t fstat; ncv_setup_and_start_pio(sc, reqlen); sc->sc_sdatalen = reqlen; tout = sc->sc_tmaxcnt; slp->sl_flags |= HW_PDMASTART; while (reqlen >= FIFO_F_SZ && tout -- > 0) { - fstat = bus_space_read_1(iot, ioh, cr1_fstat); + fstat = bus_read_1(res, cr1_fstat); if (fstat & FIFO_BRK) goto done; if ((fstat & FIFO_E) != 0) { #ifdef NCV_FAST32_ACCESS - bus_space_write_multi_4(iot, ioh, cr1_fdata, + bus_write_multi_4(res, cr1_fdata, (u_int32_t *) buf, FIFO_F_SZ / 4); #else /* !NCV_FAST32_ACCESS */ - bus_space_write_multi_2(iot, ioh, cr1_fdata, + bus_write_multi_2(res, cr1_fdata, (u_int16_t *) buf, FIFO_F_SZ / 2); #endif /* !NCV_FAST32_ACCESS */ buf += FIFO_F_SZ; reqlen -= FIFO_F_SZ; } else { DELAY(1); } } while (reqlen > 0 && tout -- > 0) { - fstat = bus_space_read_1(iot, ioh, cr1_fstat); + fstat = bus_read_1(res, cr1_fstat); if (fstat & FIFO_BRK) break; if ((fstat & FIFO_F) == 0) /* fifo not full */ { - bus_space_write_1(iot, ioh, cr1_fdata, *buf++); + bus_write_1(res, cr1_fdata, *buf++); reqlen --; } else { DELAY(1); } } done: - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + ncvhw_select_register_0(res, &sc->sc_hw); } /************************************************************** * disconnect & reselect (HW low) **************************************************************/ static int ncv_reselected(sc) struct ncv_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; struct targ_info *ti; u_int sid; - if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2) + if ((bus_read_1(res, cr0_sffl) & CR0_SFFLR_BMASK) != 2) { device_printf(slp->sl_dev, "illegal fifo bytes\n"); scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused"); return EJUSTRETURN; } - sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo); + sid = (u_int) bus_read_1(res, cr0_sfifo); sid &= ~(1 << slp->sl_hostid); sid = ffs(sid) - 1; ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid); if (ti == NULL) return EJUSTRETURN; #ifdef NCV_STATICS ncv_statics.reselect ++; #endif /* NCV_STATICS */ - bus_space_write_1(iot, ioh, cr0_dstid, sid); + bus_write_1(res, cr0_dstid, sid); return 0; } static int ncv_disconnected(sc, ti) struct ncv_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL); + bus_write_1(res, cr0_cmd, CMD_FLUSH); + bus_write_1(res, cr0_cmd, CMD_ENSEL); #ifdef NCV_STATICS ncv_statics.disconnect ++; #endif /* NCV_STATICS */ scsi_low_disconnected(slp, ti); return 1; } /************************************************************** * SEQUENCER **************************************************************/ static int ncv_target_nexus_establish(sc) struct ncv_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; struct targ_info *ti = slp->sl_Tnexus; struct ncv_targ_info *nti = (void *) ti; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; - bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period); - bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset); - bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3); + bus_write_1(res, cr0_period, nti->nti_reg_period); + bus_write_1(res, cr0_offs, nti->nti_reg_offset); + bus_write_1(res, cr0_cfg3, nti->nti_reg_cfg3); return 0; } static int ncv_lun_nexus_establish(sc) struct ncv_softc *sc; { return 0; } static int ncv_ccb_nexus_establish(sc) struct ncv_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; struct slccb *cb = slp->sl_Qnexus; sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; return 0; } static int ncv_catch_intr(sc) struct ncv_softc *sc; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; int wc; register u_int8_t status; for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++) { - status = bus_space_read_1(iot, ioh, cr0_stat); + status = bus_read_1(res, cr0_stat); if ((status & STAT_INT) != 0) return 0; DELAY(NCV_DELAY_INTERVAL); } return EJUSTRETURN; } int ncvintr(arg) void *arg; { struct ncv_softc *sc = arg; struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct resource *res = sc->port_res; struct targ_info *ti; struct buf *bp; u_int derror, flags; int len; u_int8_t regv, status, ireason; again: if (slp->sl_flags & HW_INACTIVE) return 0; /******************************************** * Status ********************************************/ - ncvhw_select_register_0(iot, ioh, &sc->sc_hw); - status = bus_space_read_1(iot, ioh, cr0_stat); + ncvhw_select_register_0(res, &sc->sc_hw); + status = bus_read_1(res, cr0_stat); if ((status & STAT_INT) == 0 || status == (u_int8_t) -1) return 0; - ireason = bus_space_read_1(iot, ioh, cr0_istat); + ireason = bus_read_1(res, cr0_istat); if ((ireason & INTR_SBR) != 0) { u_int8_t val; /* avoid power off hangup */ - val = bus_space_read_1(iot, ioh, cr0_cfg1); - bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR); + val = bus_read_1(res, cr0_cfg1); + bus_write_1(res, cr0_cfg1, val | C1_SRR); /* status init */ scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, "bus reset (power off?)"); return 1; } /******************************************** * Debug section ********************************************/ #ifdef NCV_DEBUG if (ncv_debug) { scsi_low_print(slp, NULL); device_printf(slp->sl_dev, "st %x ist %x\n\n", status, ireason); #ifdef KDB if (ncv_debug > 1) kdb_enter(KDB_WHY_CAM, "ncv"); #endif /* KDB */ } #endif /* NCV_DEBUG */ /******************************************** * Reselect or Disconnect or Nexus check ********************************************/ /* (I) reselect */ if (ireason == INTR_RESELECT) { if (ncv_reselected(sc) == EJUSTRETURN) return 1; } /* (II) nexus */ if ((ti = slp->sl_Tnexus) == NULL) return 0; derror = 0; if ((status & (STAT_PE | STAT_GE)) != 0) { slp->sl_error |= PARITYERR; if ((status & PHASE_MASK) == MESSAGE_IN_PHASE) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); else scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); derror = SCSI_LOW_DATA_PE; } if ((ireason & (INTR_DIS | INTR_ILL)) != 0) { if ((ireason & INTR_ILL) == 0) return ncv_disconnected(sc, ti); slp->sl_error |= FATALIO; scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd"); return 1; } /******************************************** * Internal scsi phase ********************************************/ switch (ti->ti_phase) { case PH_SELSTART: scsi_low_arbit_win(slp); SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); if (sc->sc_selstop == 0) { /* XXX: * Here scsi phases expected are * DATA PHASE: * MSGIN : target wants to disconnect the host. * STATUSIN : immediate command completed. * CMD PHASE : command out failed * MSGOUT : identify command failed. */ if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) break; } else { if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) break; if ((ireason & INTR_FC) != 0) { SCSI_LOW_ASSERT_ATN(slp); } } SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); break; case PH_RESEL: ncv_target_nexus_establish(sc); if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) { device_printf(slp->sl_dev, "unexpected phase after reselect\n"); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); return 1; } break; default: if ((slp->sl_flags & HW_PDMASTART) != 0) { ncv_pdma_end(sc, ti); } break; } /******************************************** * Scsi phase sequencer ********************************************/ switch (status & PHASE_MASK) { case DATA_OUT_PHASE: /* data out */ SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) { scsi_low_attention(slp); } if (slp->sl_scp.scp_datalen <= 0) { if ((ireason & INTR_BS) == 0) break; if ((slp->sl_error & PDMAERR) == 0) device_printf(slp->sl_dev, "data underrun\n"); slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_WRITE_PADDING) != 0) { u_int8_t padding[NCV_PADDING_SIZE]; bzero(padding, sizeof(padding)); ncv_pio_write(sc, padding, sizeof(padding)); } else { device_printf(slp->sl_dev, "write padding required\n"); } } else { len = slp->sl_scp.scp_datalen; if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0) { if (len > ncv_data_write_bytes) len = ncv_data_write_bytes; } ncv_pio_write(sc, slp->sl_scp.scp_data, len); } break; case DATA_IN_PHASE: /* data in */ SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) { scsi_low_attention(slp); } if (slp->sl_scp.scp_datalen <= 0) { if ((ireason & INTR_BS) == 0) break; if ((slp->sl_error & PDMAERR) == 0) device_printf(slp->sl_dev, "data overrun\n"); slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_READ_PADDING) != 0) { u_int8_t padding[NCV_PADDING_SIZE]; ncv_pio_read(sc, padding, sizeof(padding)); } else { device_printf(slp->sl_dev, "read padding required\n"); break; } } else { len = slp->sl_scp.scp_datalen; if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0) { if (len > ncv_data_read_bytes) len = ncv_data_read_bytes; } ncv_pio_read(sc, slp->sl_scp.scp_data, len); } break; case COMMAND_PHASE: /* cmd out */ SCSI_LOW_SETUP_PHASE(ti, PH_CMD); if (scsi_low_cmd(slp, ti) != 0) { scsi_low_attention(slp); } - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - ncvhw_fpush(iot, ioh, + bus_write_1(res, cr0_cmd, CMD_FLUSH); + ncvhw_fpush(res, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + bus_write_1(res, cr0_cmd, CMD_TRANS); break; case STATUS_PHASE: /* status in */ SCSI_LOW_SETUP_PHASE(ti, PH_STAT); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS); + bus_write_1(res, cr0_cmd, CMD_FLUSH); + bus_write_1(res, cr0_cmd, CMD_ICCS); sc->sc_compseq = 1; break; default: break; case MESSAGE_OUT_PHASE: /* msg out */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_write_1(res, cr0_cmd, CMD_FLUSH); flags = SCSI_LOW_MSGOUT_UNIFY; if (ti->ti_ophase != ti->ti_phase) flags |= SCSI_LOW_MSGOUT_INIT; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { scsi_low_attention(slp); } - ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + ncvhw_fpush(res, ti->ti_msgoutstr, len); + bus_write_1(res, cr0_cmd, CMD_TRANS); SCSI_LOW_DEASSERT_ATN(slp); break; case MESSAGE_IN_PHASE: /* msg in */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); - len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK; + len = bus_read_1(res, cr0_sffl) & CR0_SFFLR_BMASK; if (sc->sc_compseq != 0) { sc->sc_compseq = 0; if ((ireason & INTR_FC) && len == 2) { - regv = bus_space_read_1(iot, ioh, cr0_sfifo); + regv = bus_read_1(res, cr0_sfifo); scsi_low_statusin(slp, ti, regv | derror); len --; } else { slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); - bus_space_write_1(sc->sc_iot, sc->sc_ioh, - cr0_cmd, CMD_MSGOK); + bus_write_1(res, cr0_cmd, CMD_MSGOK); break; } } else if (ireason & INTR_BS) { - bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); - bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + bus_write_1(res, cr0_cmd, CMD_FLUSH); + bus_write_1(res, cr0_cmd, CMD_TRANS); if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0) { if (ncv_catch_intr(sc) == 0) goto again; } break; } if ((ireason & INTR_FC) && len == 1) { - regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, - cr0_sfifo); + regv = bus_read_1(res, cr0_sfifo); if (scsi_low_msgin(slp, ti, regv | derror) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { scsi_low_attention(slp); } } - bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, - CMD_MSGOK); + bus_write_1(res, cr0_cmd, CMD_MSGOK); if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0) { /* XXX: * clear a pending interrupt and sync with * a next interrupt! */ ncv_catch_intr(sc); } } else { slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); - bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, - CMD_MSGOK); + bus_write_1(res, cr0_cmd, CMD_MSGOK); } break; } return 1; } diff --git a/sys/dev/ncv/ncr53c500_pccard.c b/sys/dev/ncv/ncr53c500_pccard.c index 72df5868fcdf..23c207a1a556 100644 --- a/sys/dev/ncv/ncr53c500_pccard.c +++ b/sys/dev/ncv/ncr53c500_pccard.c @@ -1,347 +1,336 @@ /* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KME_KXLC004_01 0x100 #define OFFSET_KME_KXLC004_01 0x10 #include "pccarddevs.h" static int ncvprobe(device_t devi); static int ncvattach(device_t devi); static void ncv_card_unload(device_t); static const struct ncv_product { struct pccard_product prod; int flags; } ncv_products[] = { { PCMCIA_CARD(EPSON, SC200), 0}, { PCMCIA_CARD(PANASONIC, KXLC002), 0xb4d00000 }, { PCMCIA_CARD(PANASONIC, KXLC003), 0xb4d00000 }, /* untested */ { PCMCIA_CARD(PANASONIC, KXLC004), 0xb4d00100 }, { PCMCIA_CARD(MACNICA, MPS100), 0xb6250000 }, { PCMCIA_CARD(MACNICA, MPS110), 0 }, { PCMCIA_CARD(NEC, PC9801N_J03R), 0 }, { PCMCIA_CARD(NEWMEDIA, BASICS_SCSI), 0 }, { PCMCIA_CARD(QLOGIC, PC05), 0x84d00000 }, #define FLAGS_REX5572 0x84d00000 { PCMCIA_CARD(RATOC, REX5572), FLAGS_REX5572 }, { PCMCIA_CARD(RATOC, REX9530), 0x84d00000 }, { { NULL }, 0 } }; /* * Additional code for FreeBSD new-bus PCCard frontend */ static void ncv_pccard_intr(void * arg) { + struct ncv_softc *sc; + + sc = arg; + SCSI_LOW_LOCK(&sc->sc_sclow); ncvintr(arg); + SCSI_LOW_UNLOCK(&sc->sc_sclow); } static void ncv_release_resource(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); if (sc->ncv_intrhand) { bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); } if (sc->port_res) { bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); } if (sc->port_res_dmy) { bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid_dmy, sc->port_res_dmy); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); } if (sc->mem_res) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); } + mtx_destroy(&sc->sc_sclow.sl_lock); } static int ncv_alloc_resource(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); u_int32_t flags = device_get_flags(dev); u_long ioaddr, iosize, maddr, msize; int error; bus_addr_t offset = 0; if(flags & KME_KXLC004_01) offset = OFFSET_KME_KXLC004_01; error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); if (error || (iosize < (offset + NCVIOSZ))) { return(ENOMEM); } + mtx_init(&sc->sc_sclow.sl_lock, "ncv", NULL, MTX_DEF); sc->port_rid = 0; sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, ioaddr+offset, ioaddr+iosize-offset, iosize-offset, RF_ACTIVE); if (sc->port_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } if (offset != 0) { sc->port_rid_dmy = 0; sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid_dmy, ioaddr, ioaddr+offset, offset, RF_ACTIVE); if (sc->port_res_dmy == NULL) { printf("Warning: cannot allocate IOPORT partially.\n"); } } else { sc->port_rid_dmy = 0; sc->port_res_dmy = NULL; } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); if (error) { return(0); /* XXX */ } /* no need to allocate memory if not configured */ if (maddr == 0 || msize == 0) { return(0); } sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } return(0); } static int ncv_pccard_probe(device_t dev) { const struct ncv_product *pp; const char *vendorstr; const char *prodstr; if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, (const struct pccard_product *) ncv_products, sizeof(ncv_products[0]), NULL)) != NULL) { if (pp->prod.pp_name != NULL) device_set_desc(dev, pp->prod.pp_name); device_set_flags(dev, pp->flags); return(0); } if (pccard_get_vendor_str(dev, &vendorstr)) return(EIO); if (pccard_get_product_str(dev, &prodstr)) return(EIO); if (strcmp(vendorstr, "RATOC System Inc.") == 0 && strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) { device_set_desc(dev, "RATOC REX-5572"); device_set_flags(dev, FLAGS_REX5572); - return (0); + return (BUS_PROBE_DEFAULT); } return(EIO); } static int ncv_pccard_attach(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); int error; - bzero(sc, sizeof(struct ncv_softc)); - error = ncv_alloc_resource(dev); if (error) { return(error); } if (ncvprobe(dev) == 0) { ncv_release_resource(dev); return(ENXIO); } - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, - NULL, ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | + INTR_MPSAFE, NULL, ncv_pccard_intr, sc, &sc->ncv_intrhand); if (error) { ncv_release_resource(dev); return(error); } if (ncvattach(dev) == 0) { ncv_release_resource(dev); return(ENXIO); } return(0); } static int ncv_pccard_detach(device_t dev) { ncv_card_unload(dev); ncv_release_resource(dev); return (0); } static device_method_t ncv_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ncv_pccard_probe), DEVMETHOD(device_attach, ncv_pccard_attach), DEVMETHOD(device_detach, ncv_pccard_detach), { 0, 0 } }; static driver_t ncv_pccard_driver = { "ncv", ncv_pccard_methods, sizeof(struct ncv_softc), }; static devclass_t ncv_devclass; MODULE_DEPEND(ncv, scsi_low, 1, 1, 1); DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); static void ncv_card_unload(device_t devi) { struct ncv_softc *sc = device_get_softc(devi); - intrmask_t s; - s = splcam(); - scsi_low_deactivate((struct scsi_low_softc *)sc); - scsi_low_dettach(&sc->sc_sclow); - splx(s); + scsi_low_deactivate(&sc->sc_sclow); + scsi_low_detach(&sc->sc_sclow); } static int ncvprobe(device_t devi) { int rv; struct ncv_softc *sc = device_get_softc(devi); u_int32_t flags = device_get_flags(devi); - rv = ncvprobesubr(rman_get_bustag(sc->port_res), - rman_get_bushandle(sc->port_res), + rv = ncvprobesubr(sc->port_res, flags, NCV_HOSTID); return rv; } static int ncvattach(device_t devi) { struct ncv_softc *sc; struct scsi_low_softc *slp; u_int32_t flags = device_get_flags(devi); - intrmask_t s; - char dvname[16]; /* SCSI_LOW_DVNAME_LEN */ - - strcpy(dvname, "ncv"); sc = device_get_softc(devi); - if (sc == NULL) { - return(0); - } slp = &sc->sc_sclow; slp->sl_dev = devi; - sc->sc_iot = rman_get_bustag(sc->port_res); - sc->sc_ioh = rman_get_bushandle(sc->port_res); - slp->sl_hostid = NCV_HOSTID; slp->sl_cfgflags = flags; - s = splcam(); ncvattachsubr(sc); - splx(s); return(NCVIOSZ); } diff --git a/sys/dev/ncv/ncr53c500var.h b/sys/dev/ncv/ncr53c500var.h index 85e3330dacde..d92702fac1e7 100644 --- a/sys/dev/ncv/ncr53c500var.h +++ b/sys/dev/ncv/ncr53c500var.h @@ -1,87 +1,83 @@ /* $FreeBSD$ */ /* $NecBSD: ncr53c500var.h,v 1.11.18.1 2001/06/08 06:27:45 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _NCR53C500VAR_H_ #define _NCR53C500VAR_H_ /***************************************************************** * Host adapter structure *****************************************************************/ struct ncv_softc { struct scsi_low_softc sc_sclow; /* generic data */ - bus_space_tag_t sc_iot; - bus_space_tag_t sc_memt; - bus_space_handle_t sc_ioh; - int port_rid; int port_rid_dmy; int irq_rid; int mem_rid; struct resource *port_res; struct resource *port_res_dmy; struct resource *irq_res; struct resource *mem_res; void *ncv_intrhand; int sc_tmaxcnt; int sc_selstop; /* sel atn stop asserted */ int sc_compseq; /* completion seq cmd asserted */ int sc_sdatalen; /* start datalen */ int sc_tdatalen; /* temp xfer data len */ struct ncv_hw sc_hw; /* hardware register images */ }; /***************************************************************** * Lun information *****************************************************************/ struct ncv_targ_info { struct targ_info nti_ti; u_int8_t nti_reg_cfg3; /* cfg3 images per lun */ u_int8_t nti_reg_offset; /* synch offset register per lun */ u_int8_t nti_reg_period; /* synch period register per lun */ }; /***************************************************************** * Proto *****************************************************************/ -int ncvprobesubr(bus_space_tag_t, bus_space_handle_t ioh, u_int, int); +int ncvprobesubr(struct resource *, u_int, int); void ncvattachsubr(struct ncv_softc *); int ncvintr(void *); #endif /* !_NCR53C500VAR_H_ */ diff --git a/sys/dev/nsp/nsp.c b/sys/dev/nsp/nsp.c index dae2bd6403ac..5cda44e5328f 100644 --- a/sys/dev/nsp/nsp.c +++ b/sys/dev/nsp/nsp.c @@ -1,1878 +1,1815 @@ /* $NecBSD: nsp.c,v 1.21.12.6 2001/06/29 06:27:52 honda Exp $ */ /* $NetBSD$ */ #define NSP_DEBUG #define NSP_STATICS #define NSP_IO_CONTROL_FLAGS \ (NSP_READ_SUSPEND_IO | NSP_WRITE_SUSPEND_IO | \ NSP_READ_FIFO_INTERRUPTS | NSP_WRITE_FIFO_INTERRUPTS | \ NSP_USE_MEMIO | NSP_WAIT_FOR_SELECT) /*- * Copyright (c) 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * * Copyright (c) 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include +#include #include #include #include #include #include /*************************************************** * USER SETTINGS ***************************************************/ /* DEVICE CONFIGURATION FLAGS (MINOR) * * 0x01 DISCONNECT OFF * 0x02 PARITY LINE OFF * 0x04 IDENTIFY MSG OFF ( = single lun) * 0x08 SYNC TRANSFER OFF */ /*************************************************** * PARAMS ***************************************************/ #define NSP_NTARGETS 8 #define NSP_NLUNS 8 #define NSP_MAX_DATA_SIZE (64 * 1024) #define NSP_SELTIMEOUT (200) #define NSP_DELAY_MAX (2 * 1000 * 1000) #define NSP_DELAY_INTERVAL (1) #define NSP_TIMER_1MS (1000 / 51) /*************************************************** * DEBUG ***************************************************/ #ifdef NSP_DEBUG int nsp_debug; #endif /* NSP_DEBUG */ #ifdef NSP_STATICS struct nsp_statics { int arbit_conflict_1; int arbit_conflict_2; int device_data_write; int device_busy; int disconnect; int reselect; int data_phase_bypass; } nsp_statics; #endif /* NSP_STATICS */ /*************************************************** * IO control ***************************************************/ #define NSP_READ_SUSPEND_IO 0x0001 #define NSP_WRITE_SUSPEND_IO 0x0002 #define NSP_USE_MEMIO 0x0004 #define NSP_READ_FIFO_INTERRUPTS 0x0010 #define NSP_WRITE_FIFO_INTERRUPTS 0x0020 #define NSP_WAIT_FOR_SELECT 0x0100 u_int nsp_io_control = NSP_IO_CONTROL_FLAGS; int nsp_read_suspend_bytes = DEV_BSIZE; int nsp_write_suspend_bytes = DEV_BSIZE; int nsp_read_interrupt_bytes = 4096; int nsp_write_interrupt_bytes = 4096; /*************************************************** * DEVICE STRUCTURE ***************************************************/ extern struct cfdriver nsp_cd; /************************************************************** * DECLARE **************************************************************/ #define NSP_FIFO_ON 1 #define NSP_FIFO_OFF 0 static void nsp_pio_read(struct nsp_softc *, int); static void nsp_pio_write(struct nsp_softc *, int); static int nsp_xfer(struct nsp_softc *, u_int8_t *, int, int, int); static int nsp_msg(struct nsp_softc *, struct targ_info *, u_int); static int nsp_reselected(struct nsp_softc *); static int nsp_disconnected(struct nsp_softc *, struct targ_info *); static void nsp_pdma_end(struct nsp_softc *, struct targ_info *); static void nsphw_init(struct nsp_softc *); static int nsp_target_nexus_establish(struct nsp_softc *); static int nsp_lun_nexus_establish(struct nsp_softc *); static int nsp_ccb_nexus_establish(struct nsp_softc *); static int nsp_world_start(struct nsp_softc *, int); static int nsphw_start_selection(struct nsp_softc *sc, struct slccb *); static void nsphw_bus_reset(struct nsp_softc *); static void nsphw_attention(struct nsp_softc *); static u_int nsp_fifo_count(struct nsp_softc *); static u_int nsp_request_count(struct nsp_softc *); static int nsp_negate_signal(struct nsp_softc *, u_int8_t, u_char *); static int nsp_expect_signal(struct nsp_softc *, u_int8_t, u_int8_t); static void nsp_start_timer(struct nsp_softc *, int); static void nsp_setup_fifo(struct nsp_softc *, int, int, int); static int nsp_targ_init(struct nsp_softc *, struct targ_info *, int); static void nsphw_selection_done_and_expect_msgout(struct nsp_softc *); static void nsp_data_padding(struct nsp_softc *, int, u_int); static int nsp_timeout(struct nsp_softc *); static int nsp_read_fifo(struct nsp_softc *, int); static int nsp_write_fifo(struct nsp_softc *, int); static int nsp_phase_match(struct nsp_softc *, u_int8_t, u_int8_t); static int nsp_wait_interrupt(struct nsp_softc *); struct scsi_low_funcs nspfuncs = { SC_LOW_INIT_T nsp_world_start, SC_LOW_BUSRST_T nsphw_bus_reset, SC_LOW_TARG_INIT_T nsp_targ_init, SC_LOW_LUN_INIT_T NULL, SC_LOW_SELECT_T nsphw_start_selection, SC_LOW_NEXUS_T nsp_lun_nexus_establish, SC_LOW_NEXUS_T nsp_ccb_nexus_establish, SC_LOW_ATTEN_T nsphw_attention, SC_LOW_MSG_T nsp_msg, SC_LOW_TIMEOUT_T nsp_timeout, SC_LOW_POLL_T nspintr, NULL, }; /**************************************************** * hwfuncs ****************************************************/ -static __inline u_int8_t nsp_cr_read_1(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs); -static __inline void nsp_cr_write_1(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs, u_int8_t va); - -static __inline u_int8_t -nsp_cr_read_1(bst, bsh, ofs) - bus_space_tag_t bst; - bus_space_handle_t bsh; - bus_addr_t ofs; +static __inline uint8_t +nsp_cr_read_1(struct resource *res, bus_addr_t ofs) { - - bus_space_write_1(bst, bsh, nsp_idxr, ofs); - return bus_space_read_1(bst, bsh, nsp_datar); + + bus_write_1(res, nsp_idxr, ofs); + return bus_read_1(res, nsp_datar); } static __inline void -nsp_cr_write_1(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs, - u_int8_t va) +nsp_cr_write_1(struct resource *res, bus_addr_t ofs, uint8_t va) { - bus_space_write_1(bst, bsh, nsp_idxr, ofs); - bus_space_write_1(bst, bsh, nsp_datar, va); + bus_write_1(res, nsp_idxr, ofs); + bus_write_1(res, nsp_datar, va); } static int nsp_expect_signal(struct nsp_softc *sc, u_int8_t curphase, u_int8_t mask) { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t ph, isrc; for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++) { - ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if (ph == (u_int8_t) -1) return -1; - isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + isrc = bus_read_1(sc->port_res, nsp_irqsr); if (isrc & IRQSR_SCSI) return 0; if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase) return 1; DELAY(NSP_DELAY_INTERVAL); } device_printf(slp->sl_dev, "nsp_expect_signal timeout\n"); return -1; } static void nsphw_init(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; /* block all interrupts */ - bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_ALLMASK); /* setup SCSI interface */ - bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_IFSEL); + bus_write_1(sc->port_res, nsp_ifselr, IFSELR_IFSEL); - nsp_cr_write_1(bst, bsh, NSPR_SCIENR, 0); + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, 0); - nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8); - nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_iclkdiv); + nsp_cr_write_1(sc->port_res, NSPR_XFERMR, XFERMR_IO8); + nsp_cr_write_1(sc->port_res, NSPR_CLKDIVR, sc->sc_iclkdiv); - nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr); - nsp_cr_write_1(bst, bsh, NSPR_PARITYR, sc->sc_parr); - nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); + nsp_cr_write_1(sc->port_res, NSPR_PARITYR, sc->sc_parr); + nsp_cr_write_1(sc->port_res, NSPR_PTCLRR, PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST | PTCLRR_RSS); /* setup fifo asic */ - bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_REGSEL); - nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, 0); - if ((nsp_cr_read_1(bst, bsh, NSPR_OCR) & OCR_TERMPWRS) == 0) - nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, TERMPWRC_POWON); + bus_write_1(sc->port_res, nsp_ifselr, IFSELR_REGSEL); + nsp_cr_write_1(sc->port_res, NSPR_TERMPWRC, 0); + if ((nsp_cr_read_1(sc->port_res, NSPR_OCR) & OCR_TERMPWRS) == 0) + nsp_cr_write_1(sc->port_res, NSPR_TERMPWRC, TERMPWRC_POWON); - nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8); - nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_clkdiv); - nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); - nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + nsp_cr_write_1(sc->port_res, NSPR_XFERMR, XFERMR_IO8); + nsp_cr_write_1(sc->port_res, NSPR_CLKDIVR, sc->sc_clkdiv); + nsp_cr_write_1(sc->port_res, NSPR_TIMERCNT, 0); + nsp_cr_write_1(sc->port_res, NSPR_TIMERCNT, 0); - nsp_cr_write_1(bst, bsh, NSPR_SYNCR, 0); - nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0); + nsp_cr_write_1(sc->port_res, NSPR_SYNCR, 0); + nsp_cr_write_1(sc->port_res, NSPR_ACKWIDTH, 0); /* enable interrupts and ack them */ - nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr); - bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); + bus_write_1(sc->port_res, nsp_irqcr, IRQSR_MASK); nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0); } /**************************************************** * scsi low interface ****************************************************/ static void nsphw_attention(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int8_t cr; - cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR)/* & ~SCBUSCR_ACK */; - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ATN); + cr = nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR)/* & ~SCBUSCR_ACK */; + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr | SCBUSCR_ATN); DELAY(10); } static void nsphw_bus_reset(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int i; - bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_ALLMASK); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, SCBUSCR_RST); DELAY(100 * 1000); /* 100ms */ - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, 0); for (i = 0; i < 5; i ++) - (void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS); + (void) nsp_cr_read_1(sc->port_res, NSPR_IRQPHS); - bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); + bus_write_1(sc->port_res, nsp_irqcr, IRQSR_MASK); } static void nsphw_selection_done_and_expect_msgout(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; /* clear ack counter */ sc->sc_cnt = 0; - nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | + nsp_cr_write_1(sc->port_res, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST); /* deassert sel and assert atten */ sc->sc_seltout = 0; - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, sc->sc_busc); DELAY(1); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN); SCSI_LOW_ASSERT_ATN(slp); } static int nsphw_start_selection(sc, cb) struct nsp_softc *sc; struct slccb *cb; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; struct targ_info *ti = cb->ti; register u_int8_t arbs, ph; - int s, wc; + int wc; wc = sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; sc->sc_dataout_timeout = 0; /* check bus free */ - s = splhigh(); - ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if (ph != SCBUSMON_FREE) { - splx(s); #ifdef NSP_STATICS nsp_statics.arbit_conflict_1 ++; #endif /* NSP_STATICS */ return SCSI_LOW_START_FAIL; } /* start arbitration */ - nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC); - splx(s); + nsp_cr_write_1(sc->port_res, NSPR_ARBITS, ARBITS_EXEC); SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART); do { /* XXX: what a stupid chip! */ - arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS); + arbs = nsp_cr_read_1(sc->port_res, NSPR_ARBITS); DELAY(1); } while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && wc -- > 0); if ((arbs & ARBITS_WIN) == 0) { - nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + nsp_cr_write_1(sc->port_res, NSPR_ARBITS, ARBITS_CLR); #ifdef NSP_STATICS nsp_statics.arbit_conflict_2 ++; #endif /* NSP_STATICS */ return SCSI_LOW_START_FAIL; } /* assert select line */ SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); scsi_low_arbit_win(slp); - s = splhigh(); DELAY(3); - nsp_cr_write_1(bst, bsh, NSPR_DATA, + nsp_cr_write_1(sc->port_res, NSPR_DATA, sc->sc_idbit | (1 << ti->ti_id)); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc); DELAY(3); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL | + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, SCBUSCR_SEL | SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc); - nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + nsp_cr_write_1(sc->port_res, NSPR_ARBITS, ARBITS_CLR); DELAY(3); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc); DELAY(1); if ((nsp_io_control & NSP_WAIT_FOR_SELECT) != 0) { #define NSP_FIRST_SEL_WAIT 300 #define NSP_SEL_CHECK_INTERVAL 10 /* wait for a selection response */ for (wc = 0; wc < NSP_FIRST_SEL_WAIT / NSP_SEL_CHECK_INTERVAL; wc ++) { - ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((ph & SCBUSMON_BSY) == 0) { DELAY(NSP_SEL_CHECK_INTERVAL); continue; } DELAY(1); - ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((ph & SCBUSMON_BSY) != 0) { nsphw_selection_done_and_expect_msgout(sc); - splx(s); SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); return SCSI_LOW_START_OK; } } } - splx(s); /* check a selection timeout */ nsp_start_timer(sc, NSP_TIMER_1MS); sc->sc_seltout = 1; return SCSI_LOW_START_OK; } static int nsp_world_start(sc, fdone) struct nsp_softc *sc; int fdone; { struct scsi_low_softc *slp = &sc->sc_sclow; sc->sc_cnt = 0; sc->sc_seltout = 0; if ((slp->sl_cfgflags & CFG_NOATTEN) == 0) sc->sc_busc = SCBUSCR_ATN; else sc->sc_busc = 0; if ((slp->sl_cfgflags & CFG_NOPARITY) == 0) sc->sc_parr = PARITYR_ENABLE | PARITYR_CLEAR; else sc->sc_parr = 0; sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST); nsphw_init(sc); scsi_low_bus_reset(slp); return 0; } struct ncp_synch_data { u_int min_period; u_int max_period; u_int chip_period; u_int ack_width; }; static struct ncp_synch_data ncp_sync_data_40M[] = { {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ {0x19,0x19,0x3,1}, /* 10MB 100ns*/ {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ {0x26,0x32,0x7,3}, /* 5MB 200ns*/ {0x0, 0, 0, 0} }; static struct ncp_synch_data ncp_sync_data_20M[] = { {0x19,0x19,0x1,0}, /* 10MB 100ns*/ {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ {0x26,0x32,0x3,1}, /* 5MB 200ns*/ {0x0, 0, 0, 0} }; static int nsp_msg(sc, ti, msg) struct nsp_softc *sc; struct targ_info *ti; u_int msg; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; struct ncp_synch_data *sdp; struct nsp_targ_info *nti = (void *) ti; u_int period, offset; int i, error; if ((msg & SCSI_LOW_MSG_WIDE) != 0) { if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; return EINVAL; } return 0; } if ((msg & SCSI_LOW_MSG_SYNCH) == 0) return 0; period = ti->ti_maxsynch.period; offset = ti->ti_maxsynch.offset; if (sc->sc_iclkdiv == CLKDIVR_20M) sdp = &ncp_sync_data_20M[0]; else sdp = &ncp_sync_data_40M[0]; for (i = 0; sdp->max_period != 0; i ++, sdp ++) { if (period >= sdp->min_period && period <= sdp->max_period) break; } if (period != 0 && sdp->max_period == 0) { /* * NO proper period/offset found, * Retry neg with the target. */ ti->ti_maxsynch.period = 0; ti->ti_maxsynch.offset = 0; nti->nti_reg_syncr = 0; nti->nti_reg_ackwidth = 0; error = EINVAL; } else { nti->nti_reg_syncr = (sdp->chip_period << SYNCR_PERS) | (offset & SYNCR_OFFM); nti->nti_reg_ackwidth = sdp->ack_width; error = 0; } - nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr); - nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth); + nsp_cr_write_1(sc->port_res, NSPR_SYNCR, nti->nti_reg_syncr); + nsp_cr_write_1(sc->port_res, NSPR_ACKWIDTH, nti->nti_reg_ackwidth); return error; } static int nsp_targ_init(sc, ti, action) struct nsp_softc *sc; struct targ_info *ti; int action; { struct nsp_targ_info *nti = (void *) ti; if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; ti->ti_maxsynch.period = 100 / 4; ti->ti_maxsynch.offset = 15; nti->nti_reg_syncr = 0; nti->nti_reg_ackwidth = 0; } return 0; } static void nsp_start_timer(sc, time) struct nsp_softc *sc; int time; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; sc->sc_timer = time; - nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time); + nsp_cr_write_1(sc->port_res, NSPR_TIMERCNT, time); } /************************************************************** * General probe attach **************************************************************/ int -nspprobesubr(iot, ioh, dvcfg) - bus_space_tag_t iot; - bus_space_handle_t ioh; - u_int dvcfg; +nspprobesubr(struct resource *res, u_int dvcfg) { u_int8_t regv; - regv = bus_space_read_1(iot, ioh, nsp_fifosr); + regv = bus_read_1(res, nsp_fifosr); if (regv < 0x11 || regv >= 0x20) return 0; return 1; } void nspattachsubr(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - printf("\n"); - sc->sc_idbit = (1 << slp->sl_hostid); slp->sl_flags |= HW_READ_PADDING; slp->sl_funcs = &nspfuncs; sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ (void) scsi_low_attach(slp, 0, NSP_NTARGETS, NSP_NLUNS, sizeof(struct nsp_targ_info), 0); } /************************************************************** * PDMA functions **************************************************************/ static u_int nsp_fifo_count(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int count; - nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_ACK | PTCLRR_PT); - count = bus_space_read_1(bst, bsh, nsp_datar); - count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8); - count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16); + nsp_cr_write_1(sc->port_res, NSPR_PTCLRR, PTCLRR_RSS_ACK | PTCLRR_PT); + count = bus_read_1(sc->port_res, nsp_datar); + count += (((u_int) bus_read_1(sc->port_res, nsp_datar)) << 8); + count += (((u_int) bus_read_1(sc->port_res, nsp_datar)) << 16); return count; } static u_int nsp_request_count(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int count; - nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_REQ | PTCLRR_PT); - count = bus_space_read_1(bst, bsh, nsp_datar); - count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8); - count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16); + nsp_cr_write_1(sc->port_res, NSPR_PTCLRR, PTCLRR_RSS_REQ | PTCLRR_PT); + count = bus_read_1(sc->port_res, nsp_datar); + count += (((u_int) bus_read_1(sc->port_res, nsp_datar)) << 8); + count += (((u_int) bus_read_1(sc->port_res, nsp_datar)) << 16); return count; } static void nsp_setup_fifo(sc, on, direction, datalen) struct nsp_softc *sc; int on; int direction; int datalen; { u_int8_t xfermode; sc->sc_suspendio = 0; if (on == NSP_FIFO_OFF) { xfermode = XFERMR_IO8; goto out; } /* check if suspend io OK ? */ if (datalen > 0) { if (direction == SCSI_LOW_READ) { if ((nsp_io_control & NSP_READ_SUSPEND_IO) != 0 && (datalen % nsp_read_suspend_bytes) == 0) sc->sc_suspendio = nsp_read_suspend_bytes; } else { if ((nsp_io_control & NSP_WRITE_SUSPEND_IO) != 0 && (datalen % nsp_write_suspend_bytes) == 0) sc->sc_suspendio = nsp_write_suspend_bytes; } } /* determine a transfer type */ if (datalen < DEV_BSIZE || (datalen & 3) != 0) { - if (sc->sc_memh != 0 && + if (sc->mem_res != NULL && (nsp_io_control & NSP_USE_MEMIO) != 0) xfermode = XFERMR_XEN | XFERMR_MEM8; else xfermode = XFERMR_XEN | XFERMR_IO8; } else { - if (sc->sc_memh != 0 && + if (sc->mem_res != NULL && (nsp_io_control & NSP_USE_MEMIO) != 0) xfermode = XFERMR_XEN | XFERMR_MEM32; else xfermode = XFERMR_XEN | XFERMR_IO32; if (sc->sc_suspendio > 0) xfermode |= XFERMR_FIFOEN; } out: sc->sc_xfermr = xfermode; - nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_XFERMR, sc->sc_xfermr); + nsp_cr_write_1(sc->port_res, NSPR_XFERMR, sc->sc_xfermr); } static void nsp_pdma_end(sc, ti) struct nsp_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; struct slccb *cb = slp->sl_Qnexus; u_int len = 0, cnt; sc->sc_dataout_timeout = 0; slp->sl_flags &= ~HW_PDMASTART; nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0); if ((sc->sc_icr & SCIENR_FIFO) != 0) { sc->sc_icr &= ~SCIENR_FIFO; - nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_SCIENR, sc->sc_icr); + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); } if (cb == NULL) { slp->sl_error |= PDMAERR; return; } if (ti->ti_phase == PH_DATA) { cnt = nsp_fifo_count(sc); if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) { len = sc->sc_cnt - cnt; if (sc->sc_cnt >= cnt && slp->sl_scp.scp_datalen + len <= cb->ccb_scp.scp_datalen) { slp->sl_scp.scp_data -= len; slp->sl_scp.scp_datalen += len; } else { slp->sl_error |= PDMAERR; device_printf(slp->sl_dev, "len %x >= datalen %x\n", len, slp->sl_scp.scp_datalen); } } else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) { if (sc->sc_cnt != cnt || sc->sc_cnt > cb->ccb_scp.scp_datalen) { slp->sl_error |= PDMAERR; device_printf(slp->sl_dev, "data read count error %x != %x (%x)\n", sc->sc_cnt, cnt, cb->ccb_scp.scp_datalen); } } sc->sc_cnt = cnt; scsi_low_data_finish(slp); } else { device_printf(slp->sl_dev, "data phase miss\n"); slp->sl_error |= PDMAERR; } } #define RFIFO_CRIT 64 #define WFIFO_CRIT 32 static void nsp_data_padding(sc, direction, count) struct nsp_softc *sc; int direction; u_int count; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; if (count > NSP_MAX_DATA_SIZE) count = NSP_MAX_DATA_SIZE; - nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_XEN | XFERMR_IO8); + nsp_cr_write_1(sc->port_res, NSPR_XFERMR, XFERMR_XEN | XFERMR_IO8); if (direction == SCSI_LOW_READ) { while (count -- > 0) - (void) bus_space_read_1(bst, bsh, nsp_fifodr); + (void) bus_read_1(sc->port_res, nsp_fifodr); } else { while (count -- > 0) - (void) bus_space_write_1(bst, bsh, nsp_fifodr, 0); + (void) bus_write_1(sc->port_res, nsp_fifodr, 0); } - nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr); + nsp_cr_write_1(sc->port_res, NSPR_XFERMR, sc->sc_xfermr); } static int nsp_read_fifo(sc, suspendio) struct nsp_softc *sc; int suspendio; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int res; res = nsp_fifo_count(sc); if (res == sc->sc_cnt) return 0; #ifdef NSP_DEBUG if (res < sc->sc_cnt || res == (u_int) -1) { device_printf(slp->sl_dev, "strange fifo ack count 0x%x < 0x%x\n", res, sc->sc_cnt); return 0; } #endif /* NSP_DEBUG */ res = res - sc->sc_cnt; if (res > slp->sl_scp.scp_datalen) { if ((slp->sl_error & PDMAERR) == 0) { device_printf(slp->sl_dev, "data overrun 0x%x > 0x%x\n", res, slp->sl_scp.scp_datalen); } slp->sl_error |= PDMAERR; slp->sl_scp.scp_datalen = 0; if ((slp->sl_flags & HW_READ_PADDING) == 0) { device_printf(slp->sl_dev, "read padding required\n"); return 0; } nsp_data_padding(sc, SCSI_LOW_READ, res); sc->sc_cnt += res; return 1; /* padding start */ } if (suspendio > 0 && slp->sl_scp.scp_datalen >= suspendio) res = suspendio; if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0) { if ((sc->sc_xfermr & XFERMR_MEM32) != 0) { res &= ~3; - bus_space_read_region_4(sc->sc_memt, sc->sc_memh, 0, + bus_read_region_4(sc->mem_res, 0, (u_int32_t *) slp->sl_scp.scp_data, res >> 2); } else { - bus_space_read_region_1(sc->sc_memt, sc->sc_memh, 0, + bus_read_region_1(sc->mem_res, 0, (u_int8_t *) slp->sl_scp.scp_data, res); } } else { if ((sc->sc_xfermr & XFERMR_IO32) != 0) { res &= ~3; - bus_space_read_multi_4(bst, bsh, nsp_fifodr, + bus_read_multi_4(sc->port_res, nsp_fifodr, (u_int32_t *) slp->sl_scp.scp_data, res >> 2); } else { - bus_space_read_multi_1(bst, bsh, nsp_fifodr, + bus_read_multi_1(sc->port_res, nsp_fifodr, (u_int8_t *) slp->sl_scp.scp_data, res); } } - if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE) + if (nsp_cr_read_1(sc->port_res, NSPR_PARITYR) & PARITYR_PE) { - nsp_cr_write_1(bst, bsh, NSPR_PARITYR, + nsp_cr_write_1(sc->port_res, NSPR_PARITYR, PARITYR_ENABLE | PARITYR_CLEAR); scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_ERROR, 1); } slp->sl_scp.scp_data += res; slp->sl_scp.scp_datalen -= res; sc->sc_cnt += res; return 0; } static int nsp_write_fifo(sc, suspendio) struct nsp_softc *sc; int suspendio; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int res; register u_int8_t stat; if (suspendio > 0) { #ifdef NSP_DEBUG if ((slp->sl_scp.scp_datalen % WFIFO_CRIT) != 0) { device_printf(slp->sl_dev, "strange write length 0x%x\n", slp->sl_scp.scp_datalen); } #endif /* NSP_DEBUG */ res = slp->sl_scp.scp_datalen % suspendio; if (res == 0) { res = suspendio; } } else { res = WFIFO_CRIT; } if (res > slp->sl_scp.scp_datalen) res = slp->sl_scp.scp_datalen; /* XXX: reconfirm! */ - stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK; + stat = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON) & SCBUSMON_PHMASK; if (stat != PHASE_DATAOUT) return 0; if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0) { if ((sc->sc_xfermr & XFERMR_MEM32) != 0) { - bus_space_write_region_4(sc->sc_memt, sc->sc_memh, 0, + bus_write_region_4(sc->mem_res, 0, (u_int32_t *) slp->sl_scp.scp_data, res >> 2); } else { - bus_space_write_region_1(sc->sc_memt, sc->sc_memh, 0, + bus_write_region_1(sc->mem_res, 0, (u_int8_t *) slp->sl_scp.scp_data, res); } } else { if ((sc->sc_xfermr & XFERMR_IO32) != 0) { - bus_space_write_multi_4(bst, bsh, nsp_fifodr, + bus_write_multi_4(sc->port_res, nsp_fifodr, (u_int32_t *) slp->sl_scp.scp_data, res >> 2); } else { - bus_space_write_multi_1(bst, bsh, nsp_fifodr, + bus_write_multi_1(sc->port_res, nsp_fifodr, (u_int8_t *) slp->sl_scp.scp_data, res); } } slp->sl_scp.scp_datalen -= res; slp->sl_scp.scp_data += res; sc->sc_cnt += res; return 0; } static int nsp_wait_interrupt(sc) struct nsp_softc *sc; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int tout; register u_int8_t isrc; for (tout = 0; tout < DEV_BSIZE / 10; tout ++) { - isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + isrc = bus_read_1(sc->port_res, nsp_irqsr); if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) != 0) { if ((isrc & IRQSR_FIFO) != 0) { - bus_space_write_1(bst, bsh, + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_FIFOCL); } return 1; } DELAY(1); } return 0; } static void nsp_pio_read(sc, suspendio) struct nsp_softc *sc; int suspendio; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int tout, padding, datalen; register u_int8_t stat, fstat; padding = 0; tout = sc->sc_tmaxcnt; slp->sl_flags |= HW_PDMASTART; datalen = slp->sl_scp.scp_datalen; ReadLoop: while (1) { - stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + stat = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if (stat == (u_int8_t) -1) return; /* out of data phase */ if ((stat & SCBUSMON_PHMASK) != PHASE_DATAIN) { nsp_read_fifo(sc, 0); return; } /* data phase */ - fstat = bus_space_read_1(bst, bsh, nsp_fifosr); + fstat = bus_read_1(sc->port_res, nsp_fifosr); if ((fstat & FIFOSR_FULLEMP) != 0) { if ((sc->sc_icr & SCIENR_FIFO) != 0) { - bus_space_write_1(bst, bsh, nsp_irqcr, + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_FIFOCL); } if (suspendio > 0) { padding |= nsp_read_fifo(sc, suspendio); } else { padding |= nsp_read_fifo(sc, 0); } if ((sc->sc_icr & SCIENR_FIFO) != 0) break; } else { if (padding == 0 && slp->sl_scp.scp_datalen <= 0) return; if ((sc->sc_icr & SCIENR_FIFO) != 0) break; DELAY(1); } if ((-- tout) <= 0) { device_printf(slp->sl_dev, "nsp_pio_read: timeout\n"); return; } } if (slp->sl_scp.scp_datalen > 0 && slp->sl_scp.scp_datalen > datalen - nsp_read_interrupt_bytes) { if (nsp_wait_interrupt(sc) != 0) goto ReadLoop; } } static void nsp_pio_write(sc, suspendio) struct nsp_softc *sc; int suspendio; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; u_int rcount, acount; int tout, datalen; register u_int8_t stat, fstat; tout = sc->sc_tmaxcnt; slp->sl_flags |= HW_PDMASTART; datalen = slp->sl_scp.scp_datalen; WriteLoop: while (1) { - stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK; + stat = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON) & SCBUSMON_PHMASK; if (stat != PHASE_DATAOUT) return; if (slp->sl_scp.scp_datalen <= 0) { if (sc->sc_dataout_timeout == 0) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; return; } - fstat = bus_space_read_1(bst, bsh, nsp_fifosr); + fstat = bus_read_1(sc->port_res, nsp_fifosr); if ((fstat & FIFOSR_FULLEMP) != 0) { if ((sc->sc_icr & SCIENR_FIFO) != 0) { - bus_space_write_1(bst, bsh, nsp_irqcr, + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_FIFOCL); } if (suspendio > 0) { /* XXX:IMPORTANT: * To avoid timeout of pcmcia bus * (not scsi bus!), we should check * the scsi device sends us request * signals, which means the scsi device * is ready to recieve data without * heavy delays. */ if ((slp->sl_scp.scp_datalen % suspendio) == 0) { /* Step I: * fill the nsp fifo, and waiting for * the fifo empty. */ nsp_write_fifo(sc, 0); } else { /* Step II: * check the request singals. */ acount = nsp_fifo_count(sc); rcount = nsp_request_count(sc); if (rcount <= acount) { nsp_write_fifo(sc, 0); #ifdef NSP_STATICS nsp_statics.device_busy ++; #endif /* NSP_STATICS */ } else { nsp_write_fifo(sc, suspendio); #ifdef NSP_STATICS nsp_statics.device_data_write ++; #endif /* NSP_STATICS */ } } } else { nsp_write_fifo(sc, 0); } if ((sc->sc_icr & SCIENR_FIFO) != 0) break; } else { if ((sc->sc_icr & SCIENR_FIFO) != 0) break; DELAY(1); } if ((-- tout) <= 0) { device_printf(slp->sl_dev, "nsp_pio_write: timeout\n"); return; } } if (slp->sl_scp.scp_datalen > 0 && slp->sl_scp.scp_datalen > datalen - nsp_write_interrupt_bytes) { if (nsp_wait_interrupt(sc) != 0) goto WriteLoop; } } static int nsp_negate_signal(struct nsp_softc *sc, u_int8_t mask, u_char *s) { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t regv; for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++) { - regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + regv = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if (regv == (u_int8_t) -1) return -1; if ((regv & mask) == 0) return 1; DELAY(NSP_DELAY_INTERVAL); } device_printf(slp->sl_dev, "%s nsp_negate_signal timeout\n", s); return -1; } static int nsp_xfer(sc, buf, len, phase, clear_atn) struct nsp_softc *sc; u_int8_t *buf; int len; int phase; int clear_atn; { - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int ptr, rv; for (ptr = 0; len > 0; len --, ptr ++) { rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ); if (rv <= 0) goto out; if (len == 1 && clear_atn != 0) { - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, SCBUSCR_ADIR | SCBUSCR_ACKEN); SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow); } if (phase & SCBUSMON_IO) { - buf[ptr] = nsp_cr_read_1(bst, bsh, NSPR_DATAACK); + buf[ptr] = nsp_cr_read_1(sc->port_res, NSPR_DATAACK); } else { - nsp_cr_write_1(bst, bsh, NSPR_DATAACK, buf[ptr]); + nsp_cr_write_1(sc->port_res, NSPR_DATAACK, buf[ptr]); } nsp_negate_signal(sc, SCBUSMON_ACK, "xfer"); } out: return len; } /************************************************************** * disconnect & reselect (HW low) **************************************************************/ static int nsp_reselected(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; struct targ_info *ti; u_int sid; u_int8_t cr; - sid = (u_int) nsp_cr_read_1(bst, bsh, NSPR_RESELR); + sid = (u_int) nsp_cr_read_1(sc->port_res, NSPR_RESELR); sid &= ~sc->sc_idbit; sid = ffs(sid) - 1; if ((ti = scsi_low_reselected(slp, sid)) == NULL) return EJUSTRETURN; nsp_negate_signal(sc, SCBUSMON_SEL, "reselect"); - cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); + cr = nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR); cr &= ~(SCBUSCR_BSY | SCBUSCR_ATN); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); cr |= SCBUSCR_ADIR | SCBUSCR_ACKEN; - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); #ifdef NSP_STATICS nsp_statics.reselect ++; #endif /* NSP_STATCIS */ return EJUSTRETURN; } static int nsp_disconnected(sc, ti) struct nsp_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; - nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | + nsp_cr_write_1(sc->port_res, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST); if ((sc->sc_icr & SCIENR_FIFO) != 0) { sc->sc_icr &= ~SCIENR_FIFO; - nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr); + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); } sc->sc_cnt = 0; sc->sc_dataout_timeout = 0; #ifdef NSP_STATICS nsp_statics.disconnect ++; #endif /* NSP_STATICS */ scsi_low_disconnected(slp, ti); return 1; } /************************************************************** * SEQUENCER **************************************************************/ static void nsp_error(struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t); static void nsp_error(struct nsp_softc * sc, u_char *s, u_int8_t isrc, u_int8_t ph, u_int8_t irqphs) { struct scsi_low_softc *slp = &sc->sc_sclow; device_printf(slp->sl_dev, "%s\n", s); device_printf(slp->sl_dev, "isrc 0x%x scmon 0x%x irqphs 0x%x\n", (u_int) isrc, (u_int) ph, (u_int) irqphs); } static int nsp_target_nexus_establish(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; struct targ_info *ti = slp->sl_Tnexus; struct nsp_targ_info *nti = (void *) ti; /* setup synch transfer registers */ - nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr); - nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth); + nsp_cr_write_1(sc->port_res, NSPR_SYNCR, nti->nti_reg_syncr); + nsp_cr_write_1(sc->port_res, NSPR_ACKWIDTH, nti->nti_reg_ackwidth); /* setup pdma fifo (minimum) */ nsp_setup_fifo(sc, NSP_FIFO_ON, SCSI_LOW_READ, 0); return 0; } static int nsp_lun_nexus_establish(sc) struct nsp_softc *sc; { return 0; } static int nsp_ccb_nexus_establish(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; struct slccb *cb = slp->sl_Qnexus; sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; /* setup pdma fifo */ nsp_setup_fifo(sc, NSP_FIFO_ON, slp->sl_scp.scp_direction, slp->sl_scp.scp_datalen); if (slp->sl_scp.scp_direction == SCSI_LOW_READ) { if (sc->sc_suspendio > 0 && (nsp_io_control & NSP_READ_FIFO_INTERRUPTS) != 0) { sc->sc_icr |= SCIENR_FIFO; - nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); } } else { if (sc->sc_suspendio > 0 && (nsp_io_control & NSP_WRITE_FIFO_INTERRUPTS) != 0) { sc->sc_icr |= SCIENR_FIFO; - nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, + nsp_cr_write_1(sc->port_res, NSPR_SCIENR, sc->sc_icr); } } return 0; } static int nsp_phase_match(struct nsp_softc *sc, u_int8_t phase, u_int8_t stat) { struct scsi_low_softc *slp = &sc->sc_sclow; if ((stat & SCBUSMON_PHMASK) != phase) { device_printf(slp->sl_dev, "phase mismatch 0x%x != 0x%x\n", (u_int) phase, (u_int) stat); return EINVAL; } if ((stat & SCBUSMON_REQ) == 0) return EINVAL; return 0; } int nspintr(arg) void *arg; { struct nsp_softc *sc = arg; struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; struct targ_info *ti; struct buf *bp; u_int derror, flags; int len, rv; u_int8_t isrc, ph, irqphs, cr, regv; /******************************************* * interrupt check *******************************************/ if (slp->sl_flags & HW_INACTIVE) return 0; - bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_IRQDIS); - isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_IRQDIS); + isrc = bus_read_1(sc->port_res, nsp_irqsr); if (isrc == (u_int8_t) -1 || (isrc & IRQSR_MASK) == 0) { - bus_space_write_1(bst, bsh, nsp_irqcr, 0); + bus_write_1(sc->port_res, nsp_irqcr, 0); return 0; } /* XXX: IMPORTANT * Do not read an irqphs register if no scsi phase interrupt. * Unless, you should lose a scsi phase interrupt. */ - ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((isrc & IRQSR_SCSI) != 0) { - irqphs = nsp_cr_read_1(bst, bsh, NSPR_IRQPHS); + irqphs = nsp_cr_read_1(sc->port_res, NSPR_IRQPHS); } else irqphs = 0; /* * timer interrupt handler (scsi vs timer interrupts) */ if (sc->sc_timer != 0) { - nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); - nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + nsp_cr_write_1(sc->port_res, NSPR_TIMERCNT, 0); + nsp_cr_write_1(sc->port_res, NSPR_TIMERCNT, 0); sc->sc_timer = 0; } /* check a timer interrupt */ regv = 0; if ((isrc & IRQSR_TIMER) != 0) { if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0) { - bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_TIMERCL); return 1; } regv |= IRQCR_TIMERCL; } /* check a fifo interrupt */ if ((isrc & IRQSR_FIFO) != 0) { regv |= IRQCR_FIFOCL; } /* OK. enable all interrupts */ - bus_space_write_1(bst, bsh, nsp_irqcr, regv); + bus_write_1(sc->port_res, nsp_irqcr, regv); /******************************************* * debug section *******************************************/ #ifdef NSP_DEBUG if (nsp_debug) { nsp_error(sc, "current status", isrc, ph, irqphs); scsi_low_print(slp, NULL); #ifdef KDB if (nsp_debug > 1) kdb_enter(KDB_WHY_CAM, "nsp"); #endif /* KDB */ } #endif /* NSP_DEBUG */ /******************************************* * Parse hardware SCSI irq reasons register *******************************************/ if ((isrc & IRQSR_SCSI) != 0) { if ((irqphs & IRQPHS_RST) != 0) { scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, "bus reset (power off?)"); return 1; } if ((irqphs & IRQPHS_RSEL) != 0) { - bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_RESCL); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_RESCL); if (nsp_reselected(sc) == EJUSTRETURN) return 1; } if ((irqphs & (IRQPHS_PCHG | IRQPHS_LBF)) == 0) return 1; } /******************************************* * nexus check *******************************************/ if ((ti = slp->sl_Tnexus) == NULL) { /* unknown scsi phase changes */ nsp_error(sc, "unknown scsi phase changes", isrc, ph, irqphs); return 0; } /******************************************* * aribitration & selection *******************************************/ switch (ti->ti_phase) { case PH_SELSTART: if ((ph & SCBUSMON_BSY) == 0) { if (sc->sc_seltout >= NSP_SELTIMEOUT) { sc->sc_seltout = 0; - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, 0); return nsp_disconnected(sc, ti); } sc->sc_seltout ++; nsp_start_timer(sc, NSP_TIMER_1MS); return 1; } SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); nsphw_selection_done_and_expect_msgout(sc); return 1; case PH_SELECTED: if ((isrc & IRQSR_SCSI) == 0) return 1; nsp_target_nexus_establish(sc); break; case PH_RESEL: if ((isrc & IRQSR_SCSI) == 0) return 1; nsp_target_nexus_establish(sc); if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN) { device_printf(slp->sl_dev, "unexpected phase after reselect\n"); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); return 1; } break; case PH_DATA: if ((isrc & IRQSR_SCSI) != 0) break; if ((isrc & IRQSR_FIFO) != 0) { if (NSP_IS_PHASE_DATA(ph) == 0) return 1; irqphs = (ph & IRQPHS_PHMASK); break; } return 1; default: if ((isrc & IRQSR_SCSI) == 0) return 1; break; } /******************************************* * data phase control *******************************************/ if (slp->sl_flags & HW_PDMASTART) { if ((isrc & IRQSR_SCSI) != 0 && NSP_IS_IRQPHS_DATA(irqphs) == 0) { if (slp->sl_scp.scp_direction == SCSI_LOW_READ) nsp_pio_read(sc, 0); nsp_pdma_end(sc, ti); } } /******************************************* * scsi seq *******************************************/ if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0) return nsp_disconnected(sc, ti); /* check unexpected bus free state */ if (ph == 0) { nsp_error(sc, "unexpected bus free", isrc, ph, irqphs); return nsp_disconnected(sc, ti); } /* check normal scsi phase */ switch (irqphs & IRQPHS_PHMASK) { case IRQPHS_CMD: if (nsp_phase_match(sc, PHASE_CMD, ph) != 0) return 1; SCSI_LOW_SETUP_PHASE(ti, PH_CMD); if (scsi_low_cmd(slp, ti) != 0) { scsi_low_attention(slp); } - nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR); + nsp_cr_write_1(sc->port_res, NSPR_CMDCR, CMDCR_PTCLR); for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++) - nsp_cr_write_1(bst, bsh, NSPR_CMDDR, + nsp_cr_write_1(sc->port_res, NSPR_CMDDR, slp->sl_scp.scp_cmd[len]); - nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC); + nsp_cr_write_1(sc->port_res, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC); break; case IRQPHS_DATAOUT: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) { scsi_low_attention(slp); } nsp_pio_write(sc, sc->sc_suspendio); break; case IRQPHS_DATAIN: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) { scsi_low_attention(slp); } nsp_pio_read(sc, sc->sc_suspendio); break; case IRQPHS_STATUS: if (nsp_phase_match(sc, PHASE_STATUS, ph) != 0) return 1; SCSI_LOW_SETUP_PHASE(ti, PH_STAT); - regv = nsp_cr_read_1(bst, bsh, NSPR_DATA); - if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE) + regv = nsp_cr_read_1(sc->port_res, NSPR_DATA); + if (nsp_cr_read_1(sc->port_res, NSPR_PARITYR) & PARITYR_PE) { - nsp_cr_write_1(bst, bsh, NSPR_PARITYR, + nsp_cr_write_1(sc->port_res, NSPR_PARITYR, PARITYR_ENABLE | PARITYR_CLEAR); derror = SCSI_LOW_DATA_PE; } else derror = 0; /* assert ACK */ - cr = SCBUSCR_ACK | nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + cr = SCBUSCR_ACK | nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); if (scsi_low_statusin(slp, ti, derror | regv) != 0) { scsi_low_attention(slp); } /* check REQ nagated */ nsp_negate_signal(sc, SCBUSMON_REQ, "statin"); /* deassert ACK */ - cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + cr = nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR) & (~SCBUSCR_ACK); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); break; case IRQPHS_MSGOUT: if (nsp_phase_match(sc, PHASE_MSGOUT, ph) != 0) return 1; #ifdef NSP_MSGOUT_SERIALIZE /* * XXX: NSP QUIRK * NSP invoke interrupts only in the case of scsi phase changes, * therefore we should poll the scsi phase here to catch * the next "msg out" if exists (no scsi phase changes). */ rv = len = 16; do { SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); flags = (ti->ti_ophase != ti->ti_phase) ? SCSI_LOW_MSGOUT_INIT : 0; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { scsi_low_attention(slp); } if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT, slp->sl_clear_atten) != 0) { slp->sl_error |= FATALIO; nsp_error(sc, "MSGOUT: xfer short", isrc, ph, irqphs); } /* catch a next signal */ rv = nsp_expect_signal(sc, PHASE_MSGOUT, SCBUSMON_REQ); } while (rv > 0 && len -- > 0); #else /* !NSP_MSGOUT_SERIALIZE */ SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); flags = SCSI_LOW_MSGOUT_UNIFY; if (ti->ti_ophase != ti->ti_phase) flags |= SCSI_LOW_MSGOUT_INIT; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { scsi_low_attention(slp); } if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT, slp->sl_clear_atten) != 0) { nsp_error(sc, "MSGOUT: xfer short", isrc, ph, irqphs); } #endif /* !NSP_MSGOUT_SERIALIZE */ break; case IRQPHS_MSGIN: if (nsp_phase_match(sc, PHASE_MSGIN, ph) != 0) return 1; /* * XXX: NSP QUIRK * NSP invoke interrupts only in the case of scsi phase changes, * therefore we should poll the scsi phase here to catch * the next "msg in" if exists (no scsi phase changes). */ rv = len = 16; do { SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); /* read a data */ - regv = nsp_cr_read_1(bst, bsh, NSPR_DATA); - if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE) + regv = nsp_cr_read_1(sc->port_res, NSPR_DATA); + if (nsp_cr_read_1(sc->port_res, NSPR_PARITYR) & PARITYR_PE) { - nsp_cr_write_1(bst, bsh, + nsp_cr_write_1(sc->port_res, NSPR_PARITYR, PARITYR_ENABLE | PARITYR_CLEAR); derror = SCSI_LOW_DATA_PE; } else { derror = 0; } /* assert ack */ - cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) | SCBUSCR_ACK; - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + cr = nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR) | SCBUSCR_ACK; + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); if (scsi_low_msgin(slp, ti, regv | derror) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { scsi_low_attention(slp); } } /* check REQ nagated */ nsp_negate_signal(sc, SCBUSMON_REQ, "msgin"); /* deassert ack */ - cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK); - nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + cr = nsp_cr_read_1(sc->port_res, NSPR_SCBUSCR) & (~SCBUSCR_ACK); + nsp_cr_write_1(sc->port_res, NSPR_SCBUSCR, cr); /* catch a next signal */ rv = nsp_expect_signal(sc, PHASE_MSGIN, SCBUSMON_REQ); } while (rv > 0 && len -- > 0); break; default: slp->sl_error |= FATALIO; nsp_error(sc, "unknown scsi phase", isrc, ph, irqphs); break; } return 1; #if 0 timerout: nsp_start_timer(sc, NSP_TIMER_1MS); return 0; #endif } static int nsp_timeout(sc) struct nsp_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; int tout; u_int8_t ph, regv; if (slp->sl_Tnexus == NULL) return 0; - ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); switch (ph & SCBUSMON_PHMASK) { case PHASE_DATAOUT: if (sc->sc_dataout_timeout == 0) break; /* check a fifo empty */ - regv = bus_space_read_1(iot, ioh, nsp_fifosr); + regv = bus_read_1(sc->port_res, nsp_fifosr); if ((regv & FIFOSR_FULLEMP) == 0) break; - bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_FIFOCL); /* check still requested */ - ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((ph & SCBUSMON_REQ) == 0) break; /* check timeout */ if ((-- sc->sc_dataout_timeout) > 0) break; slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_WRITE_PADDING) == 0) { device_printf(slp->sl_dev, "write padding required\n"); break; } tout = NSP_DELAY_MAX; while (tout -- > 0) { - ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((ph & SCBUSMON_PHMASK) != PHASE_DATAOUT) break; - regv = bus_space_read_1(iot, ioh, nsp_fifosr); + regv = bus_read_1(sc->port_res, nsp_fifosr); if ((regv & FIFOSR_FULLEMP) == 0) { DELAY(1); continue; } - bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL); + bus_write_1(sc->port_res, nsp_irqcr, IRQCR_FIFOCL); nsp_data_padding(sc, SCSI_LOW_WRITE, 32); } - ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON); + ph = nsp_cr_read_1(sc->port_res, NSPR_SCBUSMON); if ((ph & SCBUSMON_PHMASK) == PHASE_DATAOUT) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; break; default: break; } return 0; } diff --git a/sys/dev/nsp/nsp_pccard.c b/sys/dev/nsp/nsp_pccard.c index 08ed66f5fd10..a235c22fde04 100644 --- a/sys/dev/nsp/nsp_pccard.c +++ b/sys/dev/nsp/nsp_pccard.c @@ -1,304 +1,291 @@ /* $NecBSD: nsp_pisa.c,v 1.4 1999/04/15 01:35:54 kmatsuda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1998 * NetBSD/pc98 porting staff. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NSP_HOSTID 7 #include "pccarddevs.h" #define PIO_MODE 0x100 /* pd_flags */ static int nspprobe(device_t devi); static int nspattach(device_t devi); static void nsp_card_unload (device_t); const struct pccard_product nsp_products[] = { PCMCIA_CARD(IODATA3, CBSC16), PCMCIA_CARD(PANASONIC, KME), PCMCIA_CARD(WORKBIT2, NINJA_SCSI3), PCMCIA_CARD(WORKBIT, ULTRA_NINJA_16), { NULL } }; /* * Additional code for FreeBSD new-bus PC Card frontend */ static void nsp_pccard_intr(void * arg) { - nspintr(arg); + struct nsp_softc *sc; + + sc = arg; + SCSI_LOW_LOCK(&sc->sc_sclow); + nspintr(sc); + SCSI_LOW_UNLOCK(&sc->sc_sclow); } static void nsp_release_resource(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); if (sc->nsp_intrhand) bus_teardown_intr(dev, sc->irq_res, sc->nsp_intrhand); if (sc->port_res) bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); + mtx_destroy(&sc->sc_sclow.sl_lock); } static int nsp_alloc_resource(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); u_long ioaddr, iosize, maddr, msize; int error; error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); if (error || iosize < NSP_IOSIZE) return(ENOMEM); + mtx_init(&sc->sc_sclow.sl_lock, "nsp", NULL, MTX_DEF); sc->port_rid = 0; sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 0, ~0, NSP_IOSIZE, RF_ACTIVE); if (sc->port_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); if (error) return(0); /* XXX */ /* No need to allocate memory if not configured and it's in PIO mode */ if (maddr == 0 || msize == 0) { if ((device_get_flags(dev) & PIO_MODE) == 0) { printf("Memory window was not configured. Configure or use in PIO mode."); nsp_release_resource(dev); return(ENOMEM); } /* no need to allocate memory if PIO mode */ return(0); } sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } return(0); } static int nsp_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, nsp_products, sizeof(nsp_products[0]), NULL)) != NULL) { if (pp->pp_name) device_set_desc(dev, pp->pp_name); - return(0); + return (BUS_PROBE_DEFAULT); } return(EIO); } static int nsp_pccard_attach(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); int error; error = nsp_alloc_resource(dev); if (error) return(error); if (nspprobe(dev) == 0) { nsp_release_resource(dev); return(ENXIO); } - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, - NULL, nsp_pccard_intr, (void *)sc, &sc->nsp_intrhand); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | + INTR_MPSAFE, NULL, nsp_pccard_intr, sc, &sc->nsp_intrhand); if (error) { nsp_release_resource(dev); return(error); } if (nspattach(dev) == 0) { nsp_release_resource(dev); return(ENXIO); } return(0); } static int nsp_pccard_detach(device_t dev) { nsp_card_unload(dev); nsp_release_resource(dev); return (0); } static device_method_t nsp_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nsp_pccard_probe), DEVMETHOD(device_attach, nsp_pccard_attach), DEVMETHOD(device_detach, nsp_pccard_detach), { 0, 0 } }; static driver_t nsp_pccard_driver = { "nsp", nsp_pccard_methods, sizeof(struct nsp_softc), }; static devclass_t nsp_devclass; MODULE_DEPEND(nsp, scsi_low, 1, 1, 1); DRIVER_MODULE(nsp, pccard, nsp_pccard_driver, nsp_devclass, 0, 0); static void nsp_card_unload(device_t devi) { struct nsp_softc *sc = device_get_softc(devi); - intrmask_t s; - s = splcam(); - scsi_low_deactivate((struct scsi_low_softc *)sc); - scsi_low_dettach(&sc->sc_sclow); - splx(s); + scsi_low_deactivate(&sc->sc_sclow); + scsi_low_detach(&sc->sc_sclow); } static int nspprobe(device_t devi) { int rv; struct nsp_softc *sc = device_get_softc(devi); - rv = nspprobesubr(rman_get_bustag(sc->port_res), - rman_get_bushandle(sc->port_res), + rv = nspprobesubr(sc->port_res, device_get_flags(devi)); return rv; } static int nspattach(device_t devi) { struct nsp_softc *sc; struct scsi_low_softc *slp; u_int32_t flags = device_get_flags(devi); u_int iobase = bus_get_resource_start(devi, SYS_RES_IOPORT, 0); - intrmask_t s; - char dvname[16]; - - strcpy(dvname,"nsp"); if (iobase == 0) { - printf("%s: no ioaddr is given\n", dvname); - return (0); + device_printf(devi, "no ioaddr is given\n"); + return (ENXIO); } sc = device_get_softc(devi); - if (sc == NULL) - return (0); - slp = &sc->sc_sclow; slp->sl_dev = devi; - sc->sc_iot = rman_get_bustag(sc->port_res); - sc->sc_ioh = rman_get_bushandle(sc->port_res); if (sc->mem_res == NULL) { - printf("WARNING: CANNOT GET Memory RESOURCE going PIO mode"); + device_printf(devi, + "WARNING: CANNOT GET Memory RESOURCE going PIO mode\n"); flags |= PIO_MODE; } - if ((flags & PIO_MODE) == 0) { - sc->sc_memt = rman_get_bustag(sc->mem_res); - sc->sc_memh = rman_get_bushandle(sc->mem_res); - } else { - sc->sc_memh = 0; - } /* slp->sl_irq = devi->pd_irq; */ sc->sc_iclkdiv = CLKDIVR_20M; sc->sc_clkdiv = CLKDIVR_40M; slp->sl_hostid = NSP_HOSTID; slp->sl_cfgflags = flags; - s = splcam(); nspattachsubr(sc); - splx(s); return(NSP_IOSIZE); } diff --git a/sys/dev/nsp/nspvar.h b/sys/dev/nsp/nspvar.h index ec4fd4424f14..ed8a981d158e 100644 --- a/sys/dev/nsp/nspvar.h +++ b/sys/dev/nsp/nspvar.h @@ -1,96 +1,91 @@ /* $FreeBSD$ */ /* $NecBSD: nspvar.h,v 1.7.14.5 2001/06/29 06:27:54 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * * Copyright (c) 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _NSPVAR_H_ #define _NSPVAR_H_ /***************************************************************** * Host adapter structure *****************************************************************/ struct nsp_softc { struct scsi_low_softc sc_sclow; /* generic data */ - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; - bus_space_tag_t sc_memt; - bus_space_handle_t sc_memh; - int port_rid; int irq_rid; int mem_rid; struct resource *port_res; struct resource *irq_res; struct resource *mem_res; void *nsp_intrhand; int sc_tmaxcnt; /* timeout count */ int sc_seltout; /* selection timeout counter */ int sc_timer; /* timer start */ int sc_suspendio; /* SMIT: data suspendio bytes */ u_int8_t sc_xfermr; /* SMIT: fifo control reg */ int sc_dataout_timeout; /* data out timeout counter */ u_int sc_idbit; /* host id bit pattern */ u_int sc_cnt; /* fifo R/W count (host) */ u_int8_t sc_iclkdiv; /* scsi chip clock divisor */ u_int8_t sc_clkdiv; /* asic chip clock divisor */ u_int8_t sc_icr; /* interrupt control reg */ u_int8_t sc_busc; /* busc registers */ u_int8_t sc_parr; /* parity control register */ }; /***************************************************************** * Lun information *****************************************************************/ struct nsp_targ_info { struct targ_info nti_ti; /* generic lun info */ u_int8_t nti_reg_syncr; /* sync registers per devices */ u_int8_t nti_reg_ackwidth; /* ackwidth per devices */ }; /***************************************************************** * Proto *****************************************************************/ -int nspprobesubr(bus_space_tag_t, bus_space_handle_t, u_int); +int nspprobesubr(struct resource *, u_int); void nspattachsubr(struct nsp_softc *); int nspintr(void *); #endif /* !_NSPVAR_H_ */ diff --git a/sys/dev/stg/tmc18c30.c b/sys/dev/stg/tmc18c30.c index 26e6a20d79be..4479fa29de5b 100644 --- a/sys/dev/stg/tmc18c30.c +++ b/sys/dev/stg/tmc18c30.c @@ -1,1377 +1,1327 @@ /* $NecBSD: tmc18c30.c,v 1.28.12.3 2001/06/19 04:35:48 honda Exp $ */ /* $NetBSD$ */ #define STG_DEBUG #define STG_STATICS #define STG_IO_CONTROL_FLAGS (STG_FIFO_INTERRUPTS | STG_WAIT_FOR_SELECT) /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998, 1999 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include +#include #include #include #include #include #include /*************************************************** * USER SETTINGS ***************************************************/ /* DEVICE CONFIGURATION FLAGS (MINOR) * * 0x01 DISCONNECT OFF * 0x02 PARITY LINE OFF * 0x04 IDENTIFY MSG OFF ( = single lun) * 0x08 SYNC TRANSFER OFF */ /* #define STG_SYNC_SUPPORT */ /* NOT YET but easy */ /* For the 512 fifo type: change below */ #define TMC18C30_FIFOSZ 0x800 #define TMC18C30_FCBSZ 0x200 #define TMC18C50_FIFOSZ 0x2000 #define TMC18C50_FCBSZ 0x400 #define STG_MAX_DATA_SIZE (64 * 1024) #define STG_DELAY_MAX (2 * 1000 * 1000) #define STG_DELAY_INTERVAL (1) #define STG_DELAY_SELECT_POLLING_MAX (5 * 1000 * 1000) /*************************************************** * PARAMS ***************************************************/ #define STG_NTARGETS 8 #define STG_NLUNS 8 /*************************************************** * DEBUG ***************************************************/ #ifdef STG_DEBUG static int stg_debug; #endif /* STG_DEBUG */ #ifdef STG_STATICS static struct stg_statics { int arbit_fail_0; int arbit_fail_1; int disconnect; int reselect; } stg_statics; #endif /* STG_STATICS */ /*************************************************** * IO control flags ***************************************************/ #define STG_FIFO_INTERRUPTS 0x0001 #define STG_WAIT_FOR_SELECT 0x0100 int stg_io_control = STG_IO_CONTROL_FLAGS; /*************************************************** * DEVICE STRUCTURE ***************************************************/ extern struct cfdriver stg_cd; /************************************************************** * DECLARE **************************************************************/ /* static */ static void stg_pio_read(struct stg_softc *, struct targ_info *, u_int); static void stg_pio_write(struct stg_softc *, struct targ_info *, u_int); static int stg_xfer(struct stg_softc *, u_int8_t *, int, int, int); static int stg_msg(struct stg_softc *, struct targ_info *, u_int); static int stg_reselected(struct stg_softc *); static int stg_disconnected(struct stg_softc *, struct targ_info *); static __inline void stg_pdma_end(struct stg_softc *, struct targ_info *); static int stghw_select_targ_wait(struct stg_softc *, int); static int stghw_check(struct stg_softc *); static void stghw_init(struct stg_softc *); static int stg_negate_signal(struct stg_softc *, u_int8_t, u_char *); static int stg_expect_signal(struct stg_softc *, u_int8_t, u_int8_t); static int stg_world_start(struct stg_softc *, int); static int stghw_start_selection(struct stg_softc *sc, struct slccb *); static void stghw_bus_reset(struct stg_softc *); static void stghw_attention(struct stg_softc *); static int stg_target_nexus_establish(struct stg_softc *); static int stg_lun_nexus_establish(struct stg_softc *); static int stg_ccb_nexus_establish(struct stg_softc *); static int stg_targ_init(struct stg_softc *, struct targ_info *, int); static __inline void stghw_bcr_write_1(struct stg_softc *, u_int8_t); static int stg_timeout(struct stg_softc *); static void stg_selection_done_and_expect_msgout(struct stg_softc *); struct scsi_low_funcs stgfuncs = { SC_LOW_INIT_T stg_world_start, SC_LOW_BUSRST_T stghw_bus_reset, SC_LOW_TARG_INIT_T stg_targ_init, SC_LOW_LUN_INIT_T NULL, SC_LOW_SELECT_T stghw_start_selection, SC_LOW_NEXUS_T stg_lun_nexus_establish, SC_LOW_NEXUS_T stg_ccb_nexus_establish, SC_LOW_ATTEN_T stghw_attention, SC_LOW_MSG_T stg_msg, SC_LOW_TIMEOUT_T stg_timeout, SC_LOW_POLL_T stgintr, NULL, }; /**************************************************** * hwfuncs ****************************************************/ static __inline void stghw_bcr_write_1(struct stg_softc *sc, u_int8_t bcv) { - bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, bcv); + bus_write_1(sc->port_res, tmc_bctl, bcv); sc->sc_busimg = bcv; } static int stghw_check(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; u_int fcbsize, fcb; u_int16_t lsb, msb; - lsb = bus_space_read_1(iot, ioh, tmc_idlsb); - msb = bus_space_read_1(iot, ioh, tmc_idmsb); + lsb = bus_read_1(sc->port_res, tmc_idlsb); + msb = bus_read_1(sc->port_res, tmc_idmsb); switch (msb << 8 | lsb) { case 0x6127: /* TMCCHIP_1800 not supported. (it's my policy) */ sc->sc_chip = TMCCHIP_1800; return EINVAL; case 0x60e9: - if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02) + if (bus_read_1(sc->port_res, tmc_cfg2) & 0x02) { sc->sc_chip = TMCCHIP_18C30; sc->sc_fsz = TMC18C30_FIFOSZ; fcbsize = TMC18C30_FCBSZ; } else { sc->sc_chip = TMCCHIP_18C50; sc->sc_fsz = TMC18C50_FIFOSZ; fcbsize = TMC18C50_FCBSZ; } break; default: sc->sc_chip = TMCCHIP_UNK; return ENODEV; } sc->sc_fcRinit = FCTL_INTEN; sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN; if (slp->sl_cfgflags & CFG_NOATTEN) sc->sc_imsg = 0; else sc->sc_imsg = BCTL_ATN; sc->sc_busc = BCTL_BUSEN; sc->sc_wthold = fcbsize + 256; sc->sc_rthold = fcbsize - 256; sc->sc_maxwsize = sc->sc_fsz; fcb = fcbsize / (sc->sc_fsz / 16); sc->sc_icinit = ICTL_CD | ICTL_SEL | ICTL_ARBIT | fcb; return 0; } static void stghw_init(sc) struct stg_softc *sc; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - bus_space_write_1(iot, ioh, tmc_ictl, 0); + bus_write_1(sc->port_res, tmc_ictl, 0); stghw_bcr_write_1(sc, BCTL_BUSFREE); - bus_space_write_1(iot, ioh, tmc_fctl, + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); - bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); - bus_space_write_1(iot, ioh, tmc_ssctl, 0); + bus_write_1(sc->port_res, tmc_ssctl, 0); } static int stg_targ_init(sc, ti, action) struct stg_softc *sc; struct targ_info *ti; int action; { struct stg_targ_info *sti = (void *) ti; if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; ti->ti_maxsynch.period = 0; ti->ti_maxsynch.offset = 0; sti->sti_reg_synch = 0; } return 0; } /**************************************************** * scsi low interface ****************************************************/ static void stghw_attention(sc) struct stg_softc *sc; { sc->sc_busc |= BCTL_ATN; sc->sc_busimg |= BCTL_ATN; - bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg); + bus_write_1(sc->port_res, tmc_bctl, sc->sc_busimg); DELAY(10); } static void stghw_bus_reset(sc) struct stg_softc *sc; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - bus_space_write_1(iot, ioh, tmc_ictl, 0); - bus_space_write_1(iot, ioh, tmc_fctl, 0); + bus_write_1(sc->port_res, tmc_ictl, 0); + bus_write_1(sc->port_res, tmc_fctl, 0); stghw_bcr_write_1(sc, BCTL_RST); DELAY(100000); stghw_bcr_write_1(sc, BCTL_BUSFREE); } static int stghw_start_selection(sc, cb) struct stg_softc *sc; struct slccb *cb; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct targ_info *ti = cb->ti; register u_int8_t stat; - int s; sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; sc->sc_dataout_timeout = 0; sc->sc_ubf_timeout = 0; stghw_bcr_write_1(sc, BCTL_BUSFREE); - bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); - s = splhigh(); - stat = bus_space_read_1(iot, ioh, tmc_astat); + stat = bus_read_1(sc->port_res, tmc_astat); if ((stat & ASTAT_INT) != 0) { - splx(s); return SCSI_LOW_START_FAIL; } - bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_ARBIT); - splx(s); + bus_write_1(sc->port_res, tmc_scsiid, sc->sc_idbit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_ARBIT); SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART); return SCSI_LOW_START_OK; } static int stg_world_start(sc, fdone) struct stg_softc *sc; int fdone; { struct scsi_low_softc *slp = &sc->sc_sclow; int error; if ((slp->sl_cfgflags & CFG_NOPARITY) == 0) sc->sc_fcRinit |= FCTL_PARENB; else sc->sc_fcRinit &= ~FCTL_PARENB; if ((error = stghw_check(sc)) != 0) return error; stghw_init(sc); scsi_low_bus_reset(slp); stghw_init(sc); return 0; } static int stg_msg(sc, ti, msg) struct stg_softc *sc; struct targ_info *ti; u_int msg; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct stg_targ_info *sti = (void *) ti; u_int period, offset; if ((msg & SCSI_LOW_MSG_WIDE) != 0) { if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) { ti->ti_width = SCSI_LOW_BUS_WIDTH_8; return EINVAL; } return 0; } if ((msg & SCSI_LOW_MSG_SYNCH) == 0) return 0; period = ti->ti_maxsynch.period; offset = ti->ti_maxsynch.offset; period = period << 2; if (period >= 200) { sti->sti_reg_synch = (period - 200) / 50; if (period % 50) sti->sti_reg_synch ++; sti->sti_reg_synch |= SSCTL_SYNCHEN; } else if (period >= 100) { sti->sti_reg_synch = (period - 100) / 50; if (period % 50) sti->sti_reg_synch ++; sti->sti_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN; } - bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch); + bus_write_1(sc->port_res, tmc_ssctl, sti->sti_reg_synch); return 0; } /************************************************************** * General probe attach **************************************************************/ int -stgprobesubr(iot, ioh, dvcfg) - bus_space_tag_t iot; - bus_space_handle_t ioh; - u_int dvcfg; +stgprobesubr(struct resource *res, u_int dvcfg) { u_int16_t lsb, msb; - lsb = bus_space_read_1(iot, ioh, tmc_idlsb); - msb = bus_space_read_1(iot, ioh, tmc_idmsb); + lsb = bus_read_1(res, tmc_idlsb); + msb = bus_read_1(res, tmc_idmsb); switch (msb << 8 | lsb) { default: return 0; case 0x6127: /* not support! */ return 0; case 0x60e9: return 1; } return 0; } void stgattachsubr(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; printf("\n"); sc->sc_idbit = (1 << slp->sl_hostid); slp->sl_funcs = &stgfuncs; sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ slp->sl_flags |= HW_READ_PADDING; slp->sl_cfgflags |= CFG_ASYNC; /* XXX */ (void) scsi_low_attach(slp, 0, STG_NTARGETS, STG_NLUNS, sizeof(struct stg_targ_info), 0); } /************************************************************** * PDMA functions **************************************************************/ static __inline void stg_pdma_end(sc, ti) struct stg_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct slccb *cb = slp->sl_Qnexus; u_int len, tres; slp->sl_flags &= ~HW_PDMASTART; sc->sc_icinit &= ~ICTL_FIFO; sc->sc_dataout_timeout = 0; if (cb == NULL) { slp->sl_error |= PDMAERR; goto out; } if (ti->ti_phase == PH_DATA) { - len = bus_space_read_2(iot, ioh, tmc_fdcnt); + len = bus_read_2(sc->port_res, tmc_fdcnt); if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) { if (len != 0) { tres = len + slp->sl_scp.scp_datalen; if (tres <= (u_int) cb->ccb_scp.scp_datalen) { slp->sl_scp.scp_data -= len; slp->sl_scp.scp_datalen = tres; } else { slp->sl_error |= PDMAERR; device_printf(slp->sl_dev, "len %x >= datalen %x\n", len, slp->sl_scp.scp_datalen); } } } else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) { if (len != 0) { slp->sl_error |= PDMAERR; device_printf(slp->sl_dev, "len %x left in fifo\n", len); } } scsi_low_data_finish(slp); } else { device_printf(slp->sl_dev, "data phase miss\n"); slp->sl_error |= PDMAERR; } out: - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); } static void stg_pio_read(sc, ti, thold) struct stg_softc *sc; struct targ_info *ti; u_int thold; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct sc_p *sp = &slp->sl_scp; - int s, tout; + int tout; u_int res; u_int8_t stat; if ((slp->sl_flags & HW_PDMASTART) == 0) { - bus_space_write_1(iot, ioh, tmc_fctl, + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN); slp->sl_flags |= HW_PDMASTART; } tout = sc->sc_tmaxcnt; while (tout -- > 0) { if (thold > 0) { - s = splhigh(); - res = bus_space_read_2(iot, ioh, tmc_fdcnt); + res = bus_read_2(sc->port_res, tmc_fdcnt); if (res < thold) { - bus_space_write_1(iot, ioh, tmc_ictl, + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); - splx(s); break; } - splx(s); } else { - stat = bus_space_read_1(iot, ioh, tmc_bstat); - res = bus_space_read_2(iot, ioh, tmc_fdcnt); + stat = bus_read_1(sc->port_res, tmc_bstat); + res = bus_read_2(sc->port_res, tmc_fdcnt); if (res == 0) { if ((stat & PHASE_MASK) != DATA_IN_PHASE) break; if (sp->scp_datalen <= 0) break; DELAY(1); continue; } } /* The assumtion res != 0 is valid here */ if (res > sp->scp_datalen) { if (res == (u_int) -1) break; slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_READ_PADDING) == 0) { device_printf(slp->sl_dev, "read padding required\n"); break; } sp->scp_datalen = 0; if (res > STG_MAX_DATA_SIZE) res = STG_MAX_DATA_SIZE; while (res -- > 0) { - (void) bus_space_read_1(iot, ioh, tmc_rfifo); + (void) bus_read_1(sc->port_res, tmc_rfifo); } continue; } sp->scp_datalen -= res; if (res & 1) { - *sp->scp_data = bus_space_read_1(iot, ioh, tmc_rfifo); + *sp->scp_data = bus_read_1(sc->port_res, tmc_rfifo); sp->scp_data ++; res --; } - bus_space_read_multi_2(iot, ioh, tmc_rfifo, + bus_read_multi_2(sc->port_res, tmc_rfifo, (u_int16_t *) sp->scp_data, res >> 1); sp->scp_data += res; } if (tout <= 0) device_printf(slp->sl_dev, "pio read timeout\n"); } static void stg_pio_write(sc, ti, thold) struct stg_softc *sc; struct targ_info *ti; u_int thold; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct sc_p *sp = &slp->sl_scp; u_int res; - int s, tout; + int tout; register u_int8_t stat; if ((slp->sl_flags & HW_PDMASTART) == 0) { stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW; - bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO); - bus_space_write_1(iot, ioh, tmc_fctl, stat); + bus_write_1(sc->port_res, tmc_fctl, stat | FCTL_CLRFIFO); + bus_write_1(sc->port_res, tmc_fctl, stat); slp->sl_flags |= HW_PDMASTART; } tout = sc->sc_tmaxcnt; while (tout -- > 0) { - stat = bus_space_read_1(iot, ioh, tmc_bstat); + stat = bus_read_1(sc->port_res, tmc_bstat); if ((stat & PHASE_MASK) != DATA_OUT_PHASE) break; if (sp->scp_datalen <= 0) { if (sc->sc_dataout_timeout == 0) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; break; } if (thold > 0) { - s = splhigh(); - res = bus_space_read_2(iot, ioh, tmc_fdcnt); + res = bus_read_2(sc->port_res, tmc_fdcnt); if (res > thold) { - bus_space_write_1(iot, ioh, tmc_ictl, + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); - splx(s); break; } - splx(s); } else { - res = bus_space_read_2(iot, ioh, tmc_fdcnt); + res = bus_read_2(sc->port_res, tmc_fdcnt); if (res > sc->sc_maxwsize / 2) { DELAY(1); continue; } } if (res == (u_int) -1) break; res = sc->sc_maxwsize - res; if (res > sp->scp_datalen) res = sp->scp_datalen; sp->scp_datalen -= res; if ((res & 0x1) != 0) { - bus_space_write_1(iot, ioh, tmc_wfifo, *sp->scp_data); + bus_write_1(sc->port_res, tmc_wfifo, *sp->scp_data); sp->scp_data ++; res --; } - bus_space_write_multi_2(iot, ioh, tmc_wfifo, + bus_write_multi_2(sc->port_res, tmc_wfifo, (u_int16_t *) sp->scp_data, res >> 1); sp->scp_data += res; } if (tout <= 0) device_printf(slp->sl_dev, "pio write timeout\n"); } static int stg_negate_signal(struct stg_softc *sc, u_int8_t mask, u_char *s) { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t regv; for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++) { - regv = bus_space_read_1(bst, bsh, tmc_bstat); + regv = bus_read_1(sc->port_res, tmc_bstat); if (regv == (u_int8_t) -1) return -1; if ((regv & mask) == 0) return 1; DELAY(STG_DELAY_INTERVAL); } device_printf(slp->sl_dev, "%s stg_negate_signal timeout\n", s); return -1; } static int stg_expect_signal(struct stg_softc *sc, u_int8_t phase, u_int8_t mask) { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t bst = sc->sc_iot; - bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t ph; phase &= PHASE_MASK; for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++) { - ph = bus_space_read_1(bst, bsh, tmc_bstat); + ph = bus_read_1(sc->port_res, tmc_bstat); if (ph == (u_int8_t) -1) return -1; if ((ph & PHASE_MASK) != phase) return 0; if ((ph & mask) != 0) return 1; DELAY(STG_DELAY_INTERVAL); } device_printf(slp->sl_dev, "stg_expect_signal timeout\n"); return -1; } static int stg_xfer(sc, buf, len, phase, clear_atn) struct stg_softc *sc; u_int8_t *buf; int len; int phase; int clear_atn; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; int rv, ptr; if (phase & BSTAT_IO) - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); else - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcWinit); for (ptr = 0; len > 0; len --) { rv = stg_expect_signal(sc, phase, BSTAT_REQ); if (rv <= 0) goto bad; if (len == 1 && clear_atn != 0) { sc->sc_busc &= ~BCTL_ATN; stghw_bcr_write_1(sc, sc->sc_busc); SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow); } if (phase & BSTAT_IO) { - buf[ptr ++] = bus_space_read_1(iot, ioh, tmc_rdata); + buf[ptr ++] = bus_read_1(sc->port_res, tmc_rdata); } else { - bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]); + bus_write_1(sc->port_res, tmc_wdata, buf[ptr ++]); } stg_negate_signal(sc, BSTAT_ACK, "xfer"); } bad: - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); return len; } /************************************************************** * disconnect & reselect (HW low) **************************************************************/ static int stg_reselected(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; int tout; u_int sid; u_int8_t regv; if (slp->sl_selid != NULL) { /* XXX: * Selection vs Reselection conflicts. */ - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, BCTL_BUSFREE); } else if (slp->sl_Tnexus != NULL) { device_printf(slp->sl_dev, "unexpected termination\n"); stg_disconnected(sc, slp->sl_Tnexus); } /* XXX: * We should ack the reselection as soon as possible, * because the target would abort the current reselection seq * due to reselection timeout. */ tout = STG_DELAY_SELECT_POLLING_MAX; while (tout -- > 0) { - regv = bus_space_read_1(iot, ioh, tmc_bstat); + regv = bus_read_1(sc->port_res, tmc_bstat); if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) == (BSTAT_IO | BSTAT_SEL)) { DELAY(1); - regv = bus_space_read_1(iot, ioh, tmc_bstat); + regv = bus_read_1(sc->port_res, tmc_bstat); if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) == (BSTAT_IO | BSTAT_SEL)) goto reselect_start; } DELAY(1); } device_printf(slp->sl_dev, "reselction timeout I\n"); return EJUSTRETURN; reselect_start: - sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid); + sid = (u_int) bus_read_1(sc->port_res, tmc_scsiid); if ((sid & sc->sc_idbit) == 0) { /* not us */ return EJUSTRETURN; } - bus_space_write_1(iot, ioh, tmc_fctl, + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY); while (tout -- > 0) { - regv = bus_space_read_1(iot, ioh, tmc_bstat); + regv = bus_read_1(sc->port_res, tmc_bstat); if ((regv & (BSTAT_SEL | BSTAT_BSY)) == BSTAT_BSY) goto reselected; DELAY(1); } device_printf(slp->sl_dev, "reselction timeout II\n"); return EJUSTRETURN; reselected: sid &= ~sc->sc_idbit; sid = ffs(sid) - 1; if (scsi_low_reselected(slp, sid) == NULL) return EJUSTRETURN; #ifdef STG_STATICS stg_statics.reselect ++; #endif /* STG_STATICS */ return EJUSTRETURN; } static int stg_disconnected(sc, ti) struct stg_softc *sc; struct targ_info *ti; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; /* clear bus status & fifo */ - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, BCTL_BUSFREE); sc->sc_icinit &= ~ICTL_FIFO; sc->sc_busc &= ~BCTL_ATN; sc->sc_dataout_timeout = 0; sc->sc_ubf_timeout = 0; #ifdef STG_STATICS stg_statics.disconnect ++; #endif /* STG_STATICS */ scsi_low_disconnected(slp, ti); return 1; } /************************************************************** * SEQUENCER **************************************************************/ static int stg_target_nexus_establish(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct targ_info *ti = slp->sl_Tnexus; struct stg_targ_info *sti = (void *) ti; - bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch); + bus_write_1(sc->port_res, tmc_ssctl, sti->sti_reg_synch); if ((stg_io_control & STG_FIFO_INTERRUPTS) != 0) { sc->sc_icinit |= ICTL_FIFO; } return 0; } static int stg_lun_nexus_establish(sc) struct stg_softc *sc; { return 0; } static int stg_ccb_nexus_establish(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; struct slccb *cb = slp->sl_Qnexus; sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; return 0; } #define STGHW_SELECT_INTERVAL 10 static int stghw_select_targ_wait(sc, mu) struct stg_softc *sc; int mu; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; mu = mu / STGHW_SELECT_INTERVAL; while (mu -- > 0) { - if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) == 0) + if ((bus_read_1(sc->port_res, tmc_bstat) & BSTAT_BSY) == 0) { DELAY(STGHW_SELECT_INTERVAL); continue; } DELAY(1); - if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) != 0) + if ((bus_read_1(sc->port_res, tmc_bstat) & BSTAT_BSY) != 0) { return 0; } } return ENXIO; } static void stg_selection_done_and_expect_msgout(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc); SCSI_LOW_ASSERT_ATN(slp); } int stgintr(arg) void *arg; { struct stg_softc *sc = arg; struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; struct targ_info *ti; struct buf *bp; u_int derror, flags; - int len, s; + int len; u_int8_t status, astatus, regv; /******************************************* * interrupt check *******************************************/ if (slp->sl_flags & HW_INACTIVE) return 0; - astatus = bus_space_read_1(iot, ioh, tmc_astat); - status = bus_space_read_1(iot, ioh, tmc_bstat); + astatus = bus_read_1(sc->port_res, tmc_astat); + status = bus_read_1(sc->port_res, tmc_bstat); if ((astatus & ASTAT_STATMASK) == 0 || astatus == (u_int8_t) -1) return 0; - bus_space_write_1(iot, ioh, tmc_ictl, 0); + bus_write_1(sc->port_res, tmc_ictl, 0); if (astatus & ASTAT_SCSIRST) { - bus_space_write_1(iot, ioh, tmc_fctl, + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); - bus_space_write_1(iot, ioh, tmc_ictl, 0); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_ictl, 0); scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, "bus reset (power off?)"); return 1; } /******************************************* * debug section *******************************************/ #ifdef STG_DEBUG if (stg_debug) { scsi_low_print(slp, NULL); device_printf(slp->sl_dev, "st %x ist %x\n\n", status, astatus); #ifdef KDB if (stg_debug > 1) kdb_enter(KDB_WHY_CAM, "stg"); #endif /* KDB */ } #endif /* STG_DEBUG */ /******************************************* * reselection & nexus *******************************************/ if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED) { if (stg_reselected(sc) == EJUSTRETURN) goto out; } if ((ti = slp->sl_Tnexus) == NULL) return 0; derror = 0; if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART && (sc->sc_fcRinit & FCTL_PARENB) != 0) { slp->sl_error |= PARITYERR; derror = SCSI_LOW_DATA_PE; if ((status & PHASE_MASK) == MESSAGE_IN_PHASE) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); else scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); } /******************************************* * aribitration & selection *******************************************/ switch (ti->ti_phase) { case PH_ARBSTART: if ((astatus & ASTAT_ARBIT) == 0) { #ifdef STG_STATICS stg_statics.arbit_fail_0 ++; #endif /* STG_STATICS */ goto arb_fail; } - status = bus_space_read_1(iot, ioh, tmc_bstat); + status = bus_read_1(sc->port_res, tmc_bstat); if ((status & BSTAT_IO) != 0) { /* XXX: * Selection vs Reselection conflicts. */ #ifdef STG_STATICS stg_statics.arbit_fail_1 ++; #endif /* STG_STATICS */ arb_fail: - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, BCTL_BUSFREE); scsi_low_arbit_fail(slp, slp->sl_Qnexus); goto out; } /* * selection assert start. */ SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); scsi_low_arbit_win(slp); - s = splhigh(); - bus_space_write_1(iot, ioh, tmc_scsiid, + bus_write_1(sc->port_res, tmc_scsiid, sc->sc_idbit | (1 << ti->ti_id)); stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcWinit); if ((stg_io_control & STG_WAIT_FOR_SELECT) != 0) { /* selection abort delay 200 + 100 micro sec */ if (stghw_select_targ_wait(sc, 300) == 0) { SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); stg_selection_done_and_expect_msgout(sc); } } - splx(s); goto out; case PH_SELSTART: if ((status & BSTAT_BSY) == 0) { /* selection timeout delay 250 ms */ if (stghw_select_targ_wait(sc, 250 * 1000) != 0) { stg_disconnected(sc, ti); goto out; } } SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); stg_selection_done_and_expect_msgout(sc); goto out; case PH_SELECTED: if ((status & BSTAT_REQ) == 0) goto out; stg_target_nexus_establish(sc); break; case PH_RESEL: if ((status & BSTAT_REQ) == 0) goto out; /* clear a busy line */ - bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_write_1(sc->port_res, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, sc->sc_busc); stg_target_nexus_establish(sc); if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) { device_printf(slp->sl_dev, "unexpected phase after reselect\n"); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); goto out; } break; } /******************************************* * data phase *******************************************/ if ((slp->sl_flags & HW_PDMASTART) && STG_IS_PHASE_DATA(status) == 0) { if (slp->sl_scp.scp_direction == SCSI_LOW_READ) stg_pio_read(sc, ti, 0); stg_pdma_end(sc, ti); } /******************************************* * scsi seq *******************************************/ switch (status & PHASE_MASK) { case COMMAND_PHASE: if (stg_expect_signal(sc, COMMAND_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_CMD); if (scsi_low_cmd(slp, ti) != 0) { scsi_low_attention(slp); } if (stg_xfer(sc, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen, COMMAND_PHASE, 0) != 0) { device_printf(slp->sl_dev, "CMDOUT short\n"); } break; case DATA_OUT_PHASE: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) { scsi_low_attention(slp); } if ((sc->sc_icinit & ICTL_FIFO) != 0) stg_pio_write(sc, ti, sc->sc_wthold); else stg_pio_write(sc, ti, 0); break; case DATA_IN_PHASE: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) { scsi_low_attention(slp); } if ((sc->sc_icinit & ICTL_FIFO) != 0) stg_pio_read(sc, ti, sc->sc_rthold); else stg_pio_read(sc, ti, 0); break; case STATUS_PHASE: regv = stg_expect_signal(sc, STATUS_PHASE, BSTAT_REQ); if (regv <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_STAT); - regv = bus_space_read_1(iot, ioh, tmc_sdna); + regv = bus_read_1(sc->port_res, tmc_sdna); if (scsi_low_statusin(slp, ti, regv | derror) != 0) { scsi_low_attention(slp); } - if (regv != bus_space_read_1(iot, ioh, tmc_rdata)) + if (regv != bus_read_1(sc->port_res, tmc_rdata)) { device_printf(slp->sl_dev, "STATIN: data mismatch\n"); } stg_negate_signal(sc, BSTAT_ACK, "statin"); break; case MESSAGE_OUT_PHASE: if (stg_expect_signal(sc, MESSAGE_OUT_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); flags = (ti->ti_ophase != ti->ti_phase) ? SCSI_LOW_MSGOUT_INIT : 0; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { scsi_low_attention(slp); } if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE, slp->sl_clear_atten) != 0) { device_printf(slp->sl_dev, "MSGOUT short\n"); } else { if (slp->sl_msgphase >= MSGPH_ABORT) { stg_disconnected(sc, ti); } } break; case MESSAGE_IN_PHASE: /* confirm phase and req signal */ if (stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); /* read data with NOACK */ - regv = bus_space_read_1(iot, ioh, tmc_sdna); + regv = bus_read_1(sc->port_res, tmc_sdna); if (scsi_low_msgin(slp, ti, derror | regv) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { scsi_low_attention(slp); } } /* read data with ACK */ - if (regv != bus_space_read_1(iot, ioh, tmc_rdata)) + if (regv != bus_read_1(sc->port_res, tmc_rdata)) { device_printf(slp->sl_dev, "MSGIN: data mismatch\n"); } /* wait for the ack negated */ stg_negate_signal(sc, BSTAT_ACK, "msgin"); if (slp->sl_msgphase != 0 && slp->sl_msgphase < MSGPH_ABORT) { stg_disconnected(sc, ti); } break; case BUSFREE_PHASE: device_printf(slp->sl_dev, "unexpected disconnect\n"); stg_disconnected(sc, ti); break; default: slp->sl_error |= FATALIO; device_printf(slp->sl_dev, "unknown phase bus %x intr %x\n", status, astatus); break; } out: - bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); return 1; } static int stg_timeout(sc) struct stg_softc *sc; { struct scsi_low_softc *slp = &sc->sc_sclow; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; int tout, count; u_int8_t status; if (slp->sl_Tnexus == NULL) return 0; - status = bus_space_read_1(iot, ioh, tmc_bstat); + status = bus_read_1(sc->port_res, tmc_bstat); if ((status & PHASE_MASK) == 0) { if (sc->sc_ubf_timeout ++ == 0) return 0; device_printf(slp->sl_dev, "unexpected bus free detected\n"); slp->sl_error |= FATALIO; scsi_low_print(slp, slp->sl_Tnexus); stg_disconnected(sc, slp->sl_Tnexus); return 0; } switch (status & PHASE_MASK) { case DATA_OUT_PHASE: if (sc->sc_dataout_timeout == 0) break; if ((status & BSTAT_REQ) == 0) break; - if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0) + if (bus_read_2(sc->port_res, tmc_fdcnt) != 0) break; if ((-- sc->sc_dataout_timeout) > 0) break; slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_WRITE_PADDING) == 0) { device_printf(slp->sl_dev, "write padding required\n"); break; } - bus_space_write_1(iot, ioh, tmc_ictl, 0); + bus_write_1(sc->port_res, tmc_ictl, 0); tout = STG_DELAY_MAX; while (tout --) { - status = bus_space_read_1(iot, ioh, tmc_bstat); + status = bus_read_1(sc->port_res, tmc_bstat); if ((status & PHASE_MASK) != DATA_OUT_PHASE) break; - if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0) + if (bus_read_2(sc->port_res, tmc_fdcnt) != 0) { DELAY(1); continue; } for (count = sc->sc_maxwsize; count > 0; count --) - bus_space_write_1(iot, ioh, tmc_wfifo, 0); + bus_write_1(sc->port_res, tmc_wfifo, 0); } - status = bus_space_read_1(iot, ioh, tmc_bstat); + status = bus_read_1(sc->port_res, tmc_bstat); if ((status & PHASE_MASK) == DATA_OUT_PHASE) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; - bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + bus_write_1(sc->port_res, tmc_ictl, sc->sc_icinit); break; default: break; } return 0; } diff --git a/sys/dev/stg/tmc18c30_isa.c b/sys/dev/stg/tmc18c30_isa.c index af61cfe54d50..e44a8b0e4df0 100644 --- a/sys/dev/stg/tmc18c30_isa.c +++ b/sys/dev/stg/tmc18c30_isa.c @@ -1,129 +1,129 @@ /* $NecBSD: tmc18c30_pisa.c,v 1.22 1998/11/26 01:59:21 honda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int stg_isa_probe(device_t dev) { struct stg_softc *sc = device_get_softc(dev); int error; sc->port_rid = 0; sc->irq_rid = 0; error = stg_alloc_resource(dev); if (error) { return(error); } if (stg_probe(dev) == 0) { stg_release_resource(dev); return(ENXIO); } stg_release_resource(dev); - return(0); + return (BUS_PROBE_DEFAULT); } static int stg_isa_attach(device_t dev) { struct stg_softc *sc = device_get_softc(dev); int error; sc->port_rid = 0; sc->irq_rid = 0; error = stg_alloc_resource(dev); if (error) { return(error); } - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, - NULL, stg_intr, (void *)sc, &sc->stg_intrhand); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | + INTR_MPSAFE, NULL, stg_intr, sc, &sc->stg_intrhand); if (error) { stg_release_resource(dev); return(error); } if (stg_attach(dev) == 0) { stg_release_resource(dev); return(ENXIO); } return(0); } static device_method_t stg_isa_methods[] = { /* Device interface */ DEVMETHOD(device_probe, stg_isa_probe), DEVMETHOD(device_attach, stg_isa_attach), DEVMETHOD(device_detach, stg_detach), { 0, 0 } }; static driver_t stg_isa_driver = { "stg", stg_isa_methods, sizeof(struct stg_softc), }; DRIVER_MODULE(stg, isa, stg_isa_driver, stg_devclass, 0, 0); MODULE_DEPEND(stg, scsi_low, 1, 1, 1); diff --git a/sys/dev/stg/tmc18c30_pccard.c b/sys/dev/stg/tmc18c30_pccard.c index bca458fb3774..a10c001b07ec 100644 --- a/sys/dev/stg/tmc18c30_pccard.c +++ b/sys/dev/stg/tmc18c30_pccard.c @@ -1,138 +1,138 @@ /* $NecBSD: tmc18c30_pisa.c,v 1.22 1998/11/26 01:59:21 honda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product stg_products[] = { PCMCIA_CARD(FUTUREDOMAIN, SCSI2GO), PCMCIA_CARD(IBM, SCSICARD), PCMCIA_CARD(RATOC, REX5536), PCMCIA_CARD(RATOC, REX5536AM), PCMCIA_CARD(RATOC, REX5536M), { NULL } }; /* * Additional code for FreeBSD new-bus PC Card frontend */ static int stg_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, stg_products, sizeof(stg_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); - return(0); + return (BUS_PROBE_DEFAULT); } return(EIO); } static int stg_pccard_attach(device_t dev) { struct stg_softc *sc = device_get_softc(dev); int error; sc->port_rid = 0; sc->irq_rid = 0; error = stg_alloc_resource(dev); if (error) { return(error); } if (stg_probe(dev) == 0) { stg_release_resource(dev); return(ENXIO); } - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, - NULL, stg_intr, (void *)sc, &sc->stg_intrhand); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | + INTR_MPSAFE, NULL, stg_intr, sc, &sc->stg_intrhand); if (error) { stg_release_resource(dev); return(error); } if (stg_attach(dev) == 0) { stg_release_resource(dev); return(ENXIO); } return(0); } static device_method_t stg_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, stg_pccard_probe), DEVMETHOD(device_attach, stg_pccard_attach), DEVMETHOD(device_detach, stg_detach), { 0, 0 } }; static driver_t stg_pccard_driver = { "stg", stg_pccard_methods, sizeof(struct stg_softc), }; DRIVER_MODULE(stg, pccard, stg_pccard_driver, stg_devclass, 0, 0); MODULE_DEPEND(stg, scsi_low, 1, 1, 1); diff --git a/sys/dev/stg/tmc18c30_pci.c b/sys/dev/stg/tmc18c30_pci.c index 4c8fb4c5910a..0ff2e62212a2 100644 --- a/sys/dev/stg/tmc18c30_pci.c +++ b/sys/dev/stg/tmc18c30_pci.c @@ -1,134 +1,134 @@ /*- * Copyright (c) 2003 Bob Bishop * All rights reserved. * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct _pcsid { u_int32_t type; const char *desc; } pci_ids[] = { { 0x00001036, "Adaptec AHA-2920/A,Future Domain TMC-18XX/3260" }, { 0x00000000, NULL } }; static int stg_pci_probe(device_t dev) { u_int32_t type = pci_get_devid(dev); struct _pcsid *stg = pci_ids; while (stg->type && stg->type != type) ++stg; if (stg->desc) { device_set_desc(dev, stg->desc); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int stg_pci_attach(device_t dev) { struct stg_softc *sc = device_get_softc(dev); int error; sc->port_rid = PCIR_BAR(0); sc->irq_rid = 0; error = stg_alloc_resource(dev); if (error) { return(error); } /* XXXX remove INTR_ENTROPY below for MFC */ - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, - NULL, stg_intr, (void *)sc, &sc->stg_intrhand); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | + INTR_MPSAFE, NULL, stg_intr, sc, &sc->stg_intrhand); if (error) { stg_release_resource(dev); return(error); } if (stg_attach(dev) == 0) { stg_release_resource(dev); return(ENXIO); } return(0); } static device_method_t stg_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, stg_pci_probe), DEVMETHOD(device_attach, stg_pci_attach), DEVMETHOD(device_detach, stg_detach), { 0, 0 } }; static driver_t stg_pci_driver = { "stg", stg_pci_methods, sizeof(struct stg_softc), }; DRIVER_MODULE(stg, pci, stg_pci_driver, stg_devclass, 0, 0); MODULE_DEPEND(stg, scsi_low, 1, 1, 1); MODULE_DEPEND(stg, pci, 1, 1, 1); diff --git a/sys/dev/stg/tmc18c30_subr.c b/sys/dev/stg/tmc18c30_subr.c index 5c88ecdaa59e..8c686d673563 100644 --- a/sys/dev/stg/tmc18c30_subr.c +++ b/sys/dev/stg/tmc18c30_subr.c @@ -1,183 +1,176 @@ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #define STG_HOSTID 7 devclass_t stg_devclass; int stg_alloc_resource(device_t dev) { struct stg_softc * sc = device_get_softc(dev); u_long maddr, msize; int error; + mtx_init(&sc->sc_sclow.sl_lock, "stg", NULL, MTX_DEF); sc->port_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->port_rid, RF_ACTIVE); if (sc->port_res == NULL) { stg_release_resource(dev); return(ENOMEM); } sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq_res == NULL) { stg_release_resource(dev); return(ENOMEM); } error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); if (error) { return(0); /* XXX */ } /* no need to allocate memory if not configured */ if (maddr == 0 || msize == 0) { return(0); } sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { stg_release_resource(dev); return(ENOMEM); } return(0); } void stg_release_resource(device_t dev) { struct stg_softc *sc = device_get_softc(dev); if (sc->stg_intrhand) bus_teardown_intr(dev, sc->irq_res, sc->stg_intrhand); if (sc->port_res) bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - return; + mtx_destroy(&sc->sc_sclow.sl_lock); } int stg_probe(device_t dev) { int rv; struct stg_softc *sc = device_get_softc(dev); - rv = stgprobesubr(rman_get_bustag(sc->port_res), - rman_get_bushandle(sc->port_res), + rv = stgprobesubr(sc->port_res, device_get_flags(dev)); return rv; } int stg_attach(device_t dev) { struct stg_softc *sc; struct scsi_low_softc *slp; u_int32_t flags = device_get_flags(dev); - intrmask_t s; - char dvname[16]; sc = device_get_softc(dev); - strcpy(dvname,"stg"); - slp = &sc->sc_sclow; slp->sl_dev = dev; - sc->sc_iot = rman_get_bustag(sc->port_res); - sc->sc_ioh = rman_get_bushandle(sc->port_res); slp->sl_hostid = STG_HOSTID; slp->sl_cfgflags = flags; - s = splcam(); stgattachsubr(sc); - splx(s); return(STGIOSZ); } int -stg_detach (device_t dev) +stg_detach(device_t dev) { struct stg_softc *sc = device_get_softc(dev); - intrmask_t s; - s = splcam(); - scsi_low_deactivate((struct scsi_low_softc *)sc); - scsi_low_dettach(&sc->sc_sclow); - splx(s); + scsi_low_deactivate(&sc->sc_sclow); + scsi_low_detach(&sc->sc_sclow); stg_release_resource(dev); return (0); } void -stg_intr (void *arg) +stg_intr(void *arg) { - stgintr(arg); - return; + struct stg_softc *sc; + + sc = arg; + SCSI_LOW_LOCK(&sc->sc_sclow); + stgintr(sc); + SCSI_LOW_UNLOCK(&sc->sc_sclow); } diff --git a/sys/dev/stg/tmc18c30var.h b/sys/dev/stg/tmc18c30var.h index 9ad698faf89f..06a454b8e776 100644 --- a/sys/dev/stg/tmc18c30var.h +++ b/sys/dev/stg/tmc18c30var.h @@ -1,95 +1,91 @@ /* $FreeBSD$ */ /* $NecBSD: tmc18c30var.h,v 1.12.18.2 2001/06/13 05:51:23 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _TMC18C30VAR_H_ #define _TMC18C30VAR_H_ /***************************************************************** * Host adapter structure *****************************************************************/ struct stg_softc { struct scsi_low_softc sc_sclow; /* generic data */ - bus_space_tag_t sc_iot; - bus_space_tag_t sc_memt; - bus_space_handle_t sc_ioh; - int port_rid; int irq_rid; int mem_rid; struct resource *port_res; struct resource *irq_res; struct resource *mem_res; void *stg_intrhand; int sc_tmaxcnt; u_int sc_chip; /* chip type */ u_int sc_fsz; /* fifo size */ u_int sc_idbit; /* host id bit */ u_int sc_wthold; /* write thread */ u_int sc_rthold; /* read thread */ u_int sc_maxwsize; /* max write size */ int sc_dataout_timeout; /* data out timeout counter */ int sc_ubf_timeout; /* unexpected bus free timeout */ u_int8_t sc_fcWinit; /* write flags */ u_int8_t sc_fcRinit; /* read flags */ u_int8_t sc_icinit; /* interrupt masks */ u_int8_t sc_busc; /* default bus control register */ u_int8_t sc_imsg; /* identify msg required */ u_int8_t sc_busimg; /* bus control register image */ }; /***************************************************************** * Lun information *****************************************************************/ struct stg_targ_info { struct targ_info sti_ti; /* generic data */ u_int8_t sti_reg_synch; /* synch register per lun */ }; /***************************************************************** * Proto *****************************************************************/ -int stgprobesubr(bus_space_tag_t, bus_space_handle_t, u_int); +int stgprobesubr(struct resource *, u_int); void stgattachsubr(struct stg_softc *); int stgintr(void *); #endif /* !_TMC18C30VAR_H_ */