Index: stable/4/lib/libisc/Makefile =================================================================== --- stable/4/lib/libisc/Makefile (nonexistent) +++ stable/4/lib/libisc/Makefile (revision 67524) @@ -0,0 +1,135 @@ +# $FreeBSD$ + +BIND_DIR= ${.CURDIR}/../../contrib/bind + +LIB= isc +SHLIB_MAJOR= 1 +SHLIB_MINOR= 0 + +.PATH: ${BIND_DIR}/lib/isc +SRCS= assertions.c ev_connects.c ev_files.c ev_streams.c \ + ev_timers.c ev_waits.c eventlib.c heap.c tree.c \ + logging.c memcluster.c bitncmp.c + +# contrib/bind/include/* must not override any real system includes +CFLAGS+= -I${BIND_DIR}/port/freebsd/include -I${BIND_DIR}/include +CFLAGS+= -Wall -Wmissing-prototypes + +INCS= ${BIND_DIR}/include/isc/assertions.h \ + ${BIND_DIR}/include/isc/eventlib.h \ + ${BIND_DIR}/include/isc/heap.h \ + ${BIND_DIR}/include/isc/logging.h \ + ${BIND_DIR}/include/isc/memcluster.h \ + ${BIND_DIR}/include/isc/misc.h \ + ${BIND_DIR}/include/isc/tree.h +INCDIR= /usr/include/isc + +MAN3= assertions.3 bitncmp.3 eventlib.3 heap.3 \ + logging.3 memcluster.3 tree.3 +CLEANFILES+= ${MAN3} + +MLINKS+= assertions.3 ENSURE.3 \ + assertions.3 ENSURE_ERR.3 \ + assertions.3 INSIST.3 \ + assertions.3 INSIST_ERR.3 \ + assertions.3 INVARIANT.3 \ + assertions.3 INVARIANT_ERR.3 \ + assertions.3 REQUIRE.3 \ + assertions.3 REQUIRE_ERR.3 \ + assertions.3 assertion_type_to_text.3 \ + assertions.3 set_assertion_failure_callback.3 \ + eventlib.3 evAddTime.3 \ + eventlib.3 evCancelConn.3 \ + eventlib.3 evCancelRW.3 \ + eventlib.3 evClearIdleTimer.3 \ + eventlib.3 evClearTimer.3 \ + eventlib.3 evCmpTime.3 \ + eventlib.3 evConnFunc.3 \ + eventlib.3 evConnect.3 \ + eventlib.3 evConsIovec.3 \ + eventlib.3 evConsTime.3 \ + eventlib.3 evCreate.3 \ + eventlib.3 evDefer.3 \ + eventlib.3 evDeselectFD.3 \ + eventlib.3 evDestroy.3 \ + eventlib.3 evDispatch.3 \ + eventlib.3 evDo.3 \ + eventlib.3 evDrop.3 \ + eventlib.3 evFileFunc.3 \ + eventlib.3 evGetNext.3 \ + eventlib.3 evHold.3 \ + eventlib.3 evInitID.3 \ + eventlib.3 evLastEventTime.3 \ + eventlib.3 evListen.3 \ + eventlib.3 evMainLoop.3 \ + eventlib.3 evNowTime.3 \ + eventlib.3 evPrintf.3 \ + eventlib.3 evRead.3 \ + eventlib.3 evResetTimer.3 \ + eventlib.3 evSelectFD.3 \ + eventlib.3 evSetDebug.3 \ + eventlib.3 evSetIdleTimer.3 \ + eventlib.3 evSetTimer.3 \ + eventlib.3 evStreamFunc.3 \ + eventlib.3 evSubTime.3 \ + eventlib.3 evTestID.3 \ + eventlib.3 evTimeRW.3 \ + eventlib.3 evTimeSpec.3 \ + eventlib.3 evTimeVal.3 \ + eventlib.3 evTimerFunc.3 \ + eventlib.3 evTouchIdleTimer.3 \ + eventlib.3 evTryAccept.3 \ + eventlib.3 evUnhold.3 \ + eventlib.3 evUntimeRW.3 \ + eventlib.3 evUnwait.3 \ + eventlib.3 evWaitFor.3 \ + eventlib.3 evWaitFunc.3 \ + eventlib.3 evWrite.3 \ + heap.3 heap_decreased.3 \ + heap.3 heap_delete.3 \ + heap.3 heap_element.3 \ + heap.3 heap_for_each.3 \ + heap.3 heap_free.3 \ + heap.3 heap_increased.3 \ + heap.3 heap_insert.3 \ + heap.3 heap_new.3 \ + logging.3 log_add_channel.3 \ + logging.3 log_category_is_active.3 \ + logging.3 log_close_stream.3 \ + logging.3 log_dec_references.3 \ + logging.3 log_free_channel.3 \ + logging.3 log_free_context.3 \ + logging.3 log_get_filename.3 \ + logging.3 log_get_stream.3 \ + logging.3 log_inc_references.3 \ + logging.3 log_new_context.3 \ + logging.3 log_new_file_channel.3 \ + logging.3 log_new_null_channel.3 \ + logging.3 log_new_syslog_channel.3 \ + logging.3 log_open_stream.3 \ + logging.3 log_option.3 \ + logging.3 log_remove_channel.3 \ + logging.3 log_set_file_owner.3 \ + logging.3 log_vwrite.3 \ + logging.3 log_write.3 \ + memcluster.3 memget.3 \ + memcluster.3 memput.3 \ + memcluster.3 memstats.3 \ + tree.3 tree_add.3 \ + tree.3 tree_delete.3 \ + tree.3 tree_init.3 \ + tree.3 tree_mung.3 \ + tree.3 tree_srch.3 \ + tree.3 tree_trav.3 + +.include + +# This has to come after the .include . Not sure why. + +.SUFFIXES: .mdoc .3 +.mdoc.3: + sed -e 's/@INDOT@//g' \ + -e 's/@SYSCALL_EXT@/2/g' \ + -e 's/@SYS_OPS_EXT@/8/g' \ + < ${.ALLSRC} > ${.TARGET} + Property changes on: stable/4/lib/libisc/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/cam/scsi/scsi_dvcfg.h =================================================================== --- stable/4/sys/cam/scsi/scsi_dvcfg.h (nonexistent) +++ stable/4/sys/cam/scsi/scsi_dvcfg.h (revision 67524) @@ -0,0 +1,58 @@ +/* $FreeBSD$ */ +/* $NecBSD: scsi_dvcfg.h,v 1.4 1998/03/14 07:05:06 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1994, 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. + */ + +#ifndef _SCSI_DVCFG_H_ +#define _SCSI_DVCFG_H_ + +/* common dvcfg flags defitions for bs, ncv, stg */ + +#define DVF_SCSI_SYNC 0x01 +#define DVF_SCSI_DISC 0x02 +#define DVF_SCSI_WAIT 0x04 +#define DVF_SCSI_LINK 0x08 +#define DVF_SCSI_QTAG 0x10 +#define DVF_SCSI_SP0 0x100 +#define DVF_SCSI_NOPARITY 0x200 +#define DVF_SCSI_SAVESP 0x400 +#define DVF_SCSI_SP1 0x800 +#define DVF_SCSI_PERIOD(XXX) (((XXX) >> 24) & 0xff) +#define DVF_SCSI_OFFSET(XXX) (((XXX) >> 16) & 0xff) +#define DVF_SCSI_SYNCMASK 0xffff0000 + +#define DVF_SCSI_DEFCFG (DVF_SCSI_SYNC | DVF_SCSI_NOPARITY | DVF_SCSI_SYNCMASK) + +#define DVF_SCSI_BITS "\020\13fssp\12noparity\11nosat\005qtag\004cmdlnk\003wait\002disc\001sync" + +#endif /* !_SCSI_DVCFG_H_ */ Property changes on: stable/4/sys/cam/scsi/scsi_dvcfg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/cam/scsi/scsi_low.c =================================================================== --- stable/4/sys/cam/scsi/scsi_low.c (nonexistent) +++ stable/4/sys/cam/scsi/scsi_low.c (revision 67524) @@ -0,0 +1,2590 @@ +/* $FreeBSD$ */ +/* $NecBSD: scsi_low.c,v 1.24 1999/07/26 06:27:01 honda Exp $ */ +/* $NetBSD$ */ + +#define SCSI_LOW_STATICS +#define SCSI_LOW_WARNINGS +#ifdef __NetBSD__ +#define SCSI_LOW_TARGET_OPEN +#define SCSI_LOW_INFORM +#endif +#ifdef __FreeBSD__ +#define CAM +#endif + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * 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. + */ + +/* + * 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_nexus) + * 2) Identify msgin => lun nexus (ti->ti_li) + * 3) Qtag msg => slccb nexus (ti->ti_nexus) + */ +#include "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#include +#ifdef __NetBSD__ +#include +#endif +#include + +#ifdef __NetBSD__ +#include + +#include +#include +#include +#include +#include + +#include +#endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined(__FreeBSD__) || __FreeBSD_version < 400001 +#include +#else +#include +#endif +#include +#define delay(time) DELAY(time) + +/* from sys/dev/usb/usb_port.h + XXX Change this when FreeBSD has memset + */ +#define memset(d, v, s) \ + do{ \ + if ((v) == 0) \ + bzero((d), (s)); \ + else \ + panic("Non zero filler for memset, cannot handle!"); \ + } while (0) +#endif + +#define SCSI_LOW_DONE_COMPLETE 0 +#define SCSI_LOW_DONE_RETRY 1 + +static void scsi_low_engage __P((void *)); +static void scsi_low_info __P((struct scsi_low_softc *, struct targ_info *, u_char *)); +static void scsi_low_init_msgsys __P((struct scsi_low_softc *, struct targ_info *)); +static struct slccb *scsi_low_establish_ccb __P((struct targ_info *, struct lun_info *, scsi_low_tag_t)); +static int scsi_low_done __P((struct scsi_low_softc *, struct slccb *)); +static void scsi_low_twiddle_wait __P((void)); +static struct lun_info *scsi_low_alloc_li __P((struct targ_info *, int, int)); +static struct targ_info *scsi_low_alloc_ti __P((struct scsi_low_softc *, int)); +static void scsi_low_calcf __P((struct targ_info *, struct lun_info *)); +static struct lun_info *scsi_low_establish_lun __P((struct targ_info *, int)); +#ifndef CAM +static void scsi_low_scsi_minphys __P((struct buf *)); +#endif +#ifdef SCSI_LOW_TARGET_OPEN +static int scsi_low_target_open __P((struct scsipi_link *, struct cfdata *)); +#endif /* SCSI_LOW_TARGET_OPEN */ +#ifdef CAM +void scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb); +static void scsi_low_poll (struct cam_sim *sim); +#else +static int scsi_low_scsi_cmd __P((struct scsipi_xfer *)); +#endif +static void scsi_low_reset_nexus __P((struct scsi_low_softc *, int)); +static int scsi_low_init __P((struct scsi_low_softc *, u_int)); +static void scsi_low_start __P((struct scsi_low_softc *)); +static void scsi_low_free_ti __P((struct scsi_low_softc *)); +static void scsi_low_clear_ccb __P((struct slccb *)); + +#ifdef SCSI_LOW_STATICS +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 */ +/************************************************************** + * power control + **************************************************************/ +static void +scsi_low_engage(arg) + void *arg; +{ + struct scsi_low_softc *slp = arg; + int s = splbio(); + + switch (slp->sl_rstep) + { + case 0: + slp->sl_rstep ++; + (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); +#ifdef __FreeBSD__ + slp->engage_ch = +#endif + timeout(scsi_low_engage, slp, 1); + 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; +{ + + if ((slp->sl_flags & HW_POWERCTRL) != 0) + { +#ifdef __FreeBSD__ + untimeout(scsi_low_engage, slp, slp->engage_ch); +#else /* NetBSD */ + untimeout(scsi_low_engage, slp); +#endif + 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) + return EBUSY; + + if (flags == SCSI_LOW_RESTART_SOFT) + return 0; + + return ((*slp->sl_funcs->scsi_low_init) (slp, flags)); +} + +/************************************************************** + * 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 = malloc(ti->ti_lunsize, M_DEVBUF, M_NOWAIT); + if (li == NULL) + panic("no lun info mem\n"); + + memset(li, 0, ti->ti_lunsize); + li->li_lun = lun; + li->li_ti = ti; +#if defined(SDEV_NOPARITY) && defined(SDEV_NODISC) + li->li_quirks = SDEV_NOPARITY | SDEV_NODISC; +#endif /* SDEV_NOPARITY && SDEV_NODISC */ + li->li_cfgflags = 0xffff0000 | SCSI_LOW_SYNC; + + LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); + + /* host specific structure initialization per lun */ + (void) ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, 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 (slp->sl_titab.tqh_first == NULL) + TAILQ_INIT(&slp->sl_titab); + + ti = malloc(sizeof(struct targ_info), M_DEVBUF, M_NOWAIT); + if (ti == NULL) + panic("%s short of memory\n", slp->sl_xname); + + memset(ti, 0, sizeof(struct targ_info)); + ti->ti_id = targ; + ti->ti_sc = slp; + + slp->sl_ti[targ] = ti; + TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); + TAILQ_INIT(&ti->ti_discq); + LIST_INIT(&ti->ti_litab); + + 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 = slp->sl_titab.tqh_first; ti; ti = tib) + { + tib = ti->ti_chain.tqe_next; + for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) + { + nli = LIST_NEXT(li, lun_chain); + free(li, M_DEVBUF); + } + free(ti, M_DEVBUF); + } +} + +/************************************************************** + * timeout + **************************************************************/ +void +scsi_low_timeout(arg) + void *arg; +{ + struct scsi_low_softc *slp = arg; + struct targ_info *ti; + struct slccb *cb = NULL; /* XXX */ + int s = splbio(); + + /* check */ + if ((ti = slp->sl_nexus) != NULL && (cb = ti->ti_nexus) != NULL) + { + cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; + if (cb->ccb_tc < 0) + goto bus_reset; + } + else if (slp->sl_disc > 0) + { + struct targ_info *ti; + + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + { + for (cb = ti->ti_discq.tqh_first; cb != NULL; + cb = cb->ccb_chain.tqe_next) + { + cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; + if (cb->ccb_tc < 0) + goto bus_reset; + } + } + } + else + { + cb = slp->sl_start.tqh_first; + if (cb != NULL) + { + 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) + goto out; + + if (slp->sl_active != 0) + { + slp->sl_powc = SCSI_LOW_POWDOWN_TC; + slp->sl_active = 0; + goto out; + } + + 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); + } + } + } + +out: +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); + + splx(s); + return; + +bus_reset: + cb->ccb_error |= TIMEOUTIO; + scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); + scsi_low_init(slp, SCSI_LOW_RESTART_HARD); + scsi_low_start(slp); +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); + + splx(s); +} + +/************************************************************** + * CCB + **************************************************************/ +GENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) +GENERIC_CCB(scsi_low, slccb, ccb_chain) + +/************************************************************** + * SCSI INTERFACE (XS) + **************************************************************/ +#define SCSI_LOW_MINPHYS 0x10000 + +#ifdef __NetBSD__ +struct scsipi_device scsi_low_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ +}; +#endif + +#ifdef CAM +static void +scsi_low_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) +{ + xpt_free_path(ccb->ccb_h.path); + free(ccb, M_DEVBUF); +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 + free(periph, M_DEVBUF); +#endif +} + +static void +scsi_low_rescan_bus(struct scsi_low_softc *slp) +{ + struct cam_path *path; + union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK); +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 + struct cam_periph *xpt_periph = malloc(sizeof(struct cam_periph), + M_DEVBUF, M_WAITOK); +#endif + cam_status status; + + bzero(ccb, sizeof(union ccb)); + + status = xpt_create_path(&path, xpt_periph, + cam_sim_path(slp->sim), -1, 0); + if (status != CAM_REQ_CMP) + return; + + xpt_setup_ccb(&ccb->ccb_h, path, 5); + ccb->ccb_h.func_code = XPT_SCAN_BUS; + ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; + ccb->crcn.flags = CAM_FLAG_NONE; + xpt_action(ccb); +} +#endif + +int +scsi_low_attach(slp, openings, ntargs, nluns, lunsize) + struct scsi_low_softc *slp; + int openings, ntargs, nluns, lunsize; +{ + struct targ_info *ti; + struct lun_info *li; +#ifdef CAM + struct cam_devq *devq; +#else + struct scsipi_adapter *sap; +#endif + int i, nccb; + +#ifdef CAM + OS_DEPEND(sprintf(slp->sl_xname, "%s%d", + DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev))); +#else + OS_DEPEND(strncpy(slp->sl_xname, DEVPORT_DEVNAME(slp->sl_dev), 16)); +#endif + if (ntargs > SCSI_LOW_NTARGETS) + { + printf("scsi_low: %d targets are too large\n", ntargs); + printf("change kernel options SCSI_LOW_NTARGETS"); + } + + if (lunsize < sizeof(struct lun_info)) + lunsize = sizeof(struct lun_info); + + 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); + } + +#ifndef CAM + sap = malloc(sizeof(*sap), M_DEVBUF, M_NOWAIT); + if (sap == NULL) + return ENOMEM; + + memset(sap, 0, sizeof(*sap)); + sap->scsipi_cmd = scsi_low_scsi_cmd; + sap->scsipi_minphys = scsi_low_scsi_minphys; +#ifdef SCSI_LOW_TARGET_OPEN + sap->open_target_lu = scsi_low_target_open; +#endif /* SCSI_LOW_TARGET_OPEN */ +#endif + + if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) + return EINVAL; + + /* initialize queue */ + nccb = openings * (ntargs - 1); + if (nccb >= SCSI_LOW_NCCB || nccb <= 0) + nccb = SCSI_LOW_NCCB; + scsi_low_init_ccbque(nccb); + TAILQ_INIT(&slp->sl_start); + + slp->sl_openings = openings; + slp->sl_ntargs = ntargs; + slp->sl_nluns = nluns; + +#ifdef CAM + /* + * Prepare the scsibus_data area for the upperlevel + * scsi code. + */ + devq = cam_simq_alloc(256/*MAX_START*/); + if (devq == NULL) + return (0); + /* scbus->adapter_link = &slp->sc_link; */ + /* + * ask the adapter what subunits are present + */ + + slp->sim = cam_sim_alloc(scsi_low_scsi_action, scsi_low_poll, + DEVPORT_DEVNAME(slp->sl_dev), slp, + DEVPORT_DEVUNIT(slp->sl_dev), 1, 32/*MAX_TAGS*/, devq); + if (slp->sim == NULL) { + cam_simq_free(devq); + return 0; + } + + if (xpt_bus_register(slp->sim, 0) != CAM_SUCCESS) { + free(slp->sim, M_DEVBUF); + return 0; + } + + if (xpt_create_path(&slp->path, /*periph*/NULL, + cam_sim_path(slp->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(slp->sim)); + cam_sim_free(slp->sim, /*free_simq*/TRUE); + free(slp->sim, M_DEVBUF); + return 0; + } +#else /* !CAM */ + slp->sl_link.adapter_softc = slp; + slp->sl_link.scsipi_scsi.adapter_target = slp->sl_hostid; + slp->sl_link.scsipi_scsi.max_target = ntargs - 1; + slp->sl_link.scsipi_scsi.max_lun = nluns - 1; + slp->sl_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; + slp->sl_link.openings = openings; + slp->sl_link.type = BUS_SCSI; + slp->sl_link.adapter_softc = slp; + slp->sl_link.adapter = sap; + slp->sl_link.device = &scsi_low_dev; +#endif + + /* start watch dog */ + slp->sl_max_retry = SCSI_LOW_MAX_RETRY; +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); +#ifdef CAM + if (!cold) + scsi_low_rescan_bus(slp); +#endif + + return 0; +} + +#ifndef CAM +static void +scsi_low_scsi_minphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > SCSI_LOW_MINPHYS) + bp->b_bcount = SCSI_LOW_MINPHYS; + minphys(bp); +} +#endif + +int +scsi_low_dettach(slp) + struct scsi_low_softc *slp; +{ + + if (slp->sl_disc > 0 || slp->sl_start.tqh_first != NULL) + return EBUSY; + + /* + * scsipi does not have dettach bus fucntion. + * + scsipi_dettach_scsibus(&slp->sl_link); + */ + +#ifdef CAM + xpt_async(AC_LOST_DEVICE, slp->path, NULL); + xpt_free_path(slp->path); + xpt_bus_deregister(cam_sim_path(slp->sim)); + cam_sim_free(slp->sim, /* free_devq */ TRUE); +#endif + + scsi_low_free_ti(slp); + return 0; +} + +#ifdef CAM +static void +scsi_low_poll(struct cam_sim *sim) +{ + struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); + (*slp->sl_funcs->scsi_low_poll) (slp); +} + +void +scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb) +{ + struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); + int s, target = (u_int) (ccb->ccb_h.target_id); + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb; + +#if 0 + printf("scsi_low_scsi_action() func code %d Target: %d, LUN: %d\n", + ccb->ccb_h.func_code, target, ccb->ccb_h.target_lun); +#endif + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: /* Execute the requested I/O operation */ + if (((cb = scsi_low_get_ccb()) == NULL)) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + cb->ccb = ccb; + cb->ccb_tag = SCSI_LOW_UNKTAG; + cb->bp = (struct buf *)NULL; + cb->ti = ti = slp->sl_ti[target]; + cb->li = scsi_low_alloc_li(ti, ccb->ccb_h.target_lun, 1); + cb->ccb_flags = 0; + cb->ccb_rcnt = 0; + + s = splcam(); + + TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); + + if (slp->sl_nexus == NULL) { + scsi_low_start(slp); + } + + splx(s); + break; + case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ + 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*/ + case XPT_ABORT: /* Abort the specified CCB */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_SET_TRAN_SETTINGS: + /* XXX Implement */ + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + xpt_done(ccb); + break; + case XPT_GET_TRAN_SETTINGS: { + struct ccb_trans_settings *cts; + struct targ_info *ti; + int lun = ccb->ccb_h.target_lun; + /*int s;*/ + + cts = &ccb->cts; + ti = slp->sl_ti[ccb->ccb_h.target_id]; + li = LIST_FIRST(&ti->ti_litab); + if (li != NULL && li->li_lun != lun) + while ((li = LIST_NEXT(li, lun_chain)) != NULL) + if (li->li_lun == lun) + break; + s = splcam(); + if (li != NULL && (cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { + if (li->li_cfgflags & SCSI_LOW_DISC) + cts->flags = CCB_TRANS_DISC_ENB; + else + cts->flags = 0; + if (li->li_cfgflags & SCSI_LOW_QTAG) + cts->flags |= CCB_TRANS_TAG_ENB; + + cts->bus_width = 0;/*HN2*/ + + cts->valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID + | CCB_TRANS_BUS_WIDTH_VALID + | CCB_TRANS_DISC_VALID + | CCB_TRANS_TQ_VALID; + ccb->ccb_h.status = CAM_REQ_CMP; + } else + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + + splx(s); + xpt_done(ccb); + break; + } + case XPT_CALC_GEOMETRY: { /* not yet HN2 */ + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + int extended; + + extended = 1; + ccg = &ccb->ccg; + size_mb = ccg->volume_size + / ((1024L * 1024L) / ccg->block_size); + + if (size_mb > 1024 && extended) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_RESET_BUS: /* Reset the specified SCSI bus */ +#if 0 + scsi_low_bus_reset(slp); +#endif + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + case XPT_TERM_IO: /* Terminate the I/O process */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_PATH_INQ: { /* Path routing inquiry */ + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE; + cpi->target_sprt = 0; + cpi->hba_misc = 0; + cpi->hba_eng_cnt = 0; + cpi->max_target = SCSI_LOW_NTARGETS - 1; + cpi->max_lun = 7; + cpi->initiator_id = 7; /* HOST_SCSI_ID */ + cpi->bus_id = cam_sim_bus(sim); + cpi->base_transfer_speed = 3300; + 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; + } +} +#else /* !CAM */ +static int +scsi_low_scsi_cmd(xs) + struct scsipi_xfer *xs; +{ + struct scsi_low_softc *slp = xs->sc_link->adapter_softc; + struct targ_info *ti; + struct slccb *cb; + int s, lun, timeo; + + if (slp->sl_cfgflags & CFG_NOATTEN) + { + if (xs->sc_link->scsipi_scsi.lun > 0) + { + xs->error = XS_DRIVER_STUFFUP; + return COMPLETE; + } + } + + if ((cb = scsi_low_get_ccb(xs->flags & SCSI_NOSLEEP)) == NULL) + return TRY_AGAIN_LATER; + + lun = xs->sc_link->scsipi_scsi.lun; + cb->xs = xs; + cb->ccb_tag = SCSI_LOW_UNKTAG; + cb->ti = ti = slp->sl_ti[xs->sc_link->scsipi_scsi.target]; + cb->li = scsi_low_alloc_li(ti, lun, 1); + cb->ccb_flags = 0; + cb->ccb_rcnt = 0; + + s = splbio(); + + TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); + if (slp->sl_nexus == NULL) + scsi_low_start(slp); + + if ((xs->flags & SCSI_POLL) == 0) + { + splx(s); + return SUCCESSFULLY_QUEUED; + } + +#define SCSI_LOW_POLL_INTERVAL 1000 /* 1 ms */ + timeo = xs->timeout * (1000 / SCSI_LOW_POLL_INTERVAL); + + while ((xs->flags & ITSDONE) == 0 && timeo -- > 0) + { + delay(SCSI_LOW_POLL_INTERVAL); + (*slp->sl_funcs->scsi_low_poll) (slp); + } + + if ((xs->flags & ITSDONE) == 0) + { + cb->ccb_error |= (TIMEOUTIO | ABORTIO); + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); + scsi_low_disconnected(slp, ti); + scsi_low_init(slp, SCSI_LOW_RESTART_HARD); + } + + scsipi_done(xs); + splx(s); + return COMPLETE; +} +#endif + +/************************************************************** + * Start & Done + **************************************************************/ +#ifdef __NetBSD__ +static struct scsipi_start_stop ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; +static struct scsipi_test_unit_ready unit_ready_cmd; +#endif +#ifdef __FreeBSD__ +static struct scsi_start_stop_unit ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; +static struct scsi_test_unit_ready unit_ready_cmd; +#endif +static void scsi_low_unit_ready_cmd __P((struct slccb *)); + +static void +scsi_low_unit_ready_cmd(cb) + struct slccb *cb; +{ + + cb->ccb_scp.scp_cmd = (u_int8_t *) &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 void +scsi_low_start(slp) + struct scsi_low_softc *slp; +{ +#ifdef CAM + union ccb *ccb; +#else + struct scsipi_xfer *xs; +#endif + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb; + int rv; + + /* check hardware exists ? */ + if ((slp->sl_flags & HW_INACTIVE) != 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 (slp->sl_flags & HW_RESUME) + return; + 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); +#ifdef __FreeBSD__ + slp->engage_ch = +#endif + timeout(scsi_low_engage, slp, 1); + return; + } + } + } + + /* setup nexus */ +#ifdef SCSI_LOW_DIAGNOSTIC + ti = slp->sl_nexus; + if (ti != NULL) + { + scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); + panic("%s: inconsistent(target)\n", slp->sl_xname); + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + + for (cb = slp->sl_start.tqh_first; cb != NULL; + cb = cb->ccb_chain.tqe_next) + { + ti = cb->ti; + li = cb->li; + if (ti->ti_phase == PH_NULL) + goto scsi_low_cmd_start; + if (ti->ti_phase == PH_DISC && li->li_disc < li->li_maxnexus) + goto scsi_low_cmd_start; + } + return; + +scsi_low_cmd_start: +#ifdef CAM + ccb = cb->ccb; +#else + xs = cb->xs; +#endif +#ifdef SCSI_LOW_DIAGNOSTIC + if (ti->ti_nexus != NULL || ti->ti_li != NULL) + { + scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); + panic("%s: inconsistent(lun or ccb)\n", slp->sl_xname); + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + + /* clear all error flag bits (for restart) */ + cb->ccb_error = 0; + + /* setup nexus pointer */ + ti->ti_nexus = cb; + ti->ti_li = li; + slp->sl_nexus = ti; + + /* initialize msgsys */ + scsi_low_init_msgsys(slp, ti); + + /* target lun state check */ +#ifdef CAM + li->li_maxstate = UNIT_OK; +#else + if ((xs->flags & SCSI_POLL) != 0) + li->li_maxstate = UNIT_NEGSTART; + else + li->li_maxstate = UNIT_OK; +#endif + + /* exec cmds */ +scsi_low_cmd_exec: + if ((cb->ccb_flags & CCB_SENSE) != 0) + { + memset(&cb->ccb_sense, 0, sizeof(cb->ccb_sense)); +#ifdef CAM +#else + cb->ccb_sense_cmd.opcode = REQUEST_SENSE; + cb->ccb_sense_cmd.byte2 = (li->li_lun << 5); + cb->ccb_sense_cmd.length = sizeof(cb->ccb_sense); +#endif + cb->ccb_scp.scp_cmd = (u_int8_t *) &cb->ccb_sense_cmd; + cb->ccb_scp.scp_cmdlen = sizeof(cb->ccb_sense_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; + } + else if (li->li_state >= li->li_maxstate) + { +#ifdef CAM + 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 >> 10); +#else + cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; + cb->ccb_scp.scp_cmdlen = xs->cmdlen; + cb->ccb_scp.scp_data = xs->data; + cb->ccb_scp.scp_datalen = xs->datalen; + cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? + SCSI_LOW_WRITE : SCSI_LOW_READ; + cb->ccb_tcmax = (xs->timeout >> 10); +#endif + + } + else switch(li->li_state) + { + case UNIT_SLEEP: + scsi_low_unit_ready_cmd(cb); + break; + + case UNIT_START: + cb->ccb_scp.scp_cmd = (u_int8_t *) &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 UNIT_SYNCH: + if (li->li_maxsynch.offset > 0) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); + scsi_low_unit_ready_cmd(cb); + break; + } + li->li_state = UNIT_WIDE; + + case UNIT_WIDE: +#ifdef SCSI_LOW_SUPPORT_WIDE + if (li->li_width > 0) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); + scsi_low_unit_ready_cmd(cb); + break; + } +#endif /* SCSI_LOW_SUPPORT_WIDE */ + li->li_state = UNIT_OK; + + case UNIT_OK: + goto scsi_low_cmd_exec; + } + + /* 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; + + /* selection start */ + slp->sl_selid = ti; + 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; + } + +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_fail ++; +#endif /* SCSI_LOW_STATICS */ + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + scsi_low_clear_nexus(slp, ti); +} + +void +scsi_low_clear_nexus(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + /* clear all nexus pointer */ + ti->ti_nexus = NULL; + ti->ti_li = NULL; + slp->sl_nexus = NULL; + + /* clear selection assert */ + slp->sl_selid = NULL; + + /* clear nexus data */ + slp->sl_nexus_call = 0; + slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; +} + +static int +scsi_low_done(slp, cb) + struct scsi_low_softc *slp; + struct slccb *cb; +{ +#ifdef CAM + union ccb *ccb; +#else + struct scsipi_xfer *xs; +#endif + struct targ_info *ti; + struct lun_info *li; + + ti = cb->ti; + li = cb->li; +#ifdef CAM + ccb = cb->ccb; +#else + xs = cb->xs; +#endif + if (cb->ccb_error == 0) + { + if ((cb->ccb_flags & CCB_SENSE) != 0) + { + cb->ccb_flags &= ~CCB_SENSE; +#ifdef CAM + ccb->csio.sense_data = cb->ccb_sense; + /* ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; */ + ccb->ccb_h.status = CAM_REQ_CMP; + /* ccb->ccb_h.status = CAM_AUTOSNS_VALID|CAM_SCSI_STATUS_ERROR; */ +#else + xs->sense.scsi_sense = cb->ccb_sense; + xs->error = XS_SENSE; +#endif + } + else switch (ti->ti_status) + { + case ST_GOOD: + if (slp->sl_scp.scp_datalen == 0) + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP; +#else + xs->error = XS_NOERROR; +#endif + break; + } + +#define SCSIPI_SCSI_CD_COMPLETELY_BUGGY "YES" +#ifdef SCSIPI_SCSI_CD_COMPLETELY_BUGGY +#ifdef CAM + if (/* cb->bp == NULL && */ + slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) +#else + if (xs->bp == NULL && + slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) +#endif + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP; +#else + xs->error = XS_NOERROR; +#endif + break; + } +#endif /* SCSIPI_SCSI_CD_COMPLETELY_BUGGY */ + + cb->ccb_error |= PDMAERR; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + break; + + case ST_CHKCOND: + case ST_MET: + cb->ccb_flags |= CCB_SENSE; +#ifdef CAM + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; +#else + xs->error = XS_SENSE; +#endif + goto retry; + + case ST_BUSY: + cb->ccb_error |= BUSYERR; +#ifdef CAM + ccb->ccb_h.status = CAM_BUSY; /* SCSI_STATUS_ERROR; */ +#else + xs->error = XS_BUSY; +#endif + break; + + default: + cb->ccb_error |= FATALIO; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + break; + } + } + else + { + cb->ccb_flags &= ~CCB_SENSE; + if (ti->ti_phase == PH_SELSTART) + { +#ifdef CAM + ccb->ccb_h.status = CAM_CMD_TIMEOUT; +#else + xs->error = XS_TIMEOUT; +#endif + slp->sl_error |= SELTIMEOUTIO; + if (li->li_state == UNIT_SLEEP) + cb->ccb_error |= ABORTIO; + } + else + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + } + + if ((cb->ccb_error & ABORTIO) != 0) + { + cb->ccb_rcnt = slp->sl_max_retry; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_ABORTED; +#endif + } + } + + /* target state check */ + if (li->li_state < li->li_maxstate) + { + if (cb->ccb_rcnt < slp->sl_max_retry) + { + li->li_state ++; + cb->ccb_rcnt = 0; + goto retry; + } + } + + /* internal retry check */ +#ifdef CAM + if (ccb->ccb_h.status == CAM_REQ_CMP) + { + ccb->csio.resid = 0; + } + else + { +#if 0 + if (ccb->ccb_h.status != CAM_AUTOSENSE_FAIL && + cb->ccb_rcnt < slp->sl_max_retry) + goto retry; +#endif +#else + if (xs->error == XS_NOERROR) + { + xs->resid = 0; + } + else + { + if (xs->error != XS_SENSE && + cb->ccb_rcnt < slp->sl_max_retry) + goto retry; +#endif + +#ifndef CAM +#ifdef SCSI_LOW_WARNINGS + if (xs->bp != NULL) + { + scsi_low_print(slp, ti); + printf("%s: WARNING: File system IO abort\n", + slp->sl_xname); + } +#endif /* SCSI_LOW_WARNINGS */ +#endif + } + +#ifdef CAM + ccb->csio.scsi_status = ti->ti_status; + xpt_done(ccb); +#else + xs->flags |= ITSDONE; + if ((xs->flags & SCSI_POLL) == 0) + scsipi_done(xs); +#endif + + /* free our target */ + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + scsi_low_free_ccb(cb); + return SCSI_LOW_DONE_COMPLETE; + +retry: + cb->ccb_rcnt ++; + if (slp->sl_start.tqh_first != cb) + { + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + } + return SCSI_LOW_DONE_RETRY; +} + +/************************************************************** + * Reset + **************************************************************/ +static void +scsi_low_clear_ccb(cb) + struct slccb *cb; +{ + + cb->ccb_flags &= ~CCB_SENSE; + cb->ccb_tag = SCSI_LOW_UNKTAG; +} + +static void +scsi_low_reset_nexus(slp, fdone) + struct scsi_low_softc *slp; + int fdone; +{ + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb, *ncb; + + /* current nexus */ + ti = slp->sl_nexus; + if (ti != NULL && (cb = ti->ti_nexus) != NULL) + { + scsi_low_clear_ccb(cb); + if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) + { + cb->ccb_error |= FATALIO; + scsi_low_done(slp, cb); + } + } + + /* disconnected nexus */ + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + { + for (cb = ti->ti_discq.tqh_first; cb != NULL; cb = ncb) + { + ncb = cb->ccb_chain.tqe_next; + TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + scsi_low_clear_ccb(cb); + if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) + { + cb->ccb_error |= FATALIO; + scsi_low_done(slp, cb); + } + } + + for (li = LIST_FIRST(&ti->ti_litab); li != NULL; + li = LIST_NEXT(li, lun_chain)) + { + li->li_state = UNIT_SLEEP; + li->li_disc = 0; + ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li)); + scsi_low_calcf(ti, li); + } + + scsi_low_init_msgsys(slp, ti); + scsi_low_clear_nexus(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + } + + slp->sl_flags &= ~HW_PDMASTART; + slp->sl_disc = 0; +} + +/* misc */ +static int tw_pos; +static char tw_chars[] = "|/-\\"; + +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); + + printf("%s: try to reset scsi bus ", slp->sl_xname); + 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) + printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, 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 lun_info * +scsi_low_establish_lun(ti, lun) + struct targ_info *ti; + int lun; +{ + struct lun_info *li; + + li = scsi_low_alloc_li(ti, lun, 0); + if (li == NULL) + return li; + + ti->ti_li = li; + return li; +} + +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; + + /* + * Search ccb matching with lun and tag. + */ + cb = ti->ti_discq.tqh_first; + for ( ; cb != NULL; cb = cb->ccb_chain.tqe_next) + if (cb->li == li && cb->ccb_tag == tag) + goto found; + return cb; + + /* + * establish our ccb nexus + */ +found: + TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + ti->ti_nexus = cb; + + slp->sl_scp = cb->ccb_sscp; + slp->sl_error |= cb->ccb_error; + + slp->sl_disc --; + li->li_disc --; + + /* inform "ccb nexus established" to the host driver */ + slp->sl_nexus_call = 1; + (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); + return cb; +} + +struct targ_info * +scsi_low_reselected(slp, targ) + struct scsi_low_softc *slp; + u_int targ; +{ + struct targ_info *ti; + u_char *s; + + /* + * Check select vs reselected collision. + */ + + if ((ti = slp->sl_selid) != NULL) + { + scsi_low_clear_nexus(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_conflict ++; +#endif /* SCSI_LOW_STATICS */ + } + else if (slp->sl_nexus != 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) + { + s = "phase mismatch"; + goto world_restart; + } + + /* + * Setup lun and init msgsys + */ + slp->sl_error = 0; + scsi_low_init_msgsys(slp, ti); + + /* + * Establish our target nexus + * Remark: ccb and scsi pointer not yet restored + * if lun != SCSI_LOW_UNKLUN. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); + slp->sl_nexus = ti; +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_reselected ++; +#endif /* SCSI_LOW_STATICS */ + return ti; + +world_restart: + printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "reselect: scsi world confused"); + return NULL; +} + +int +scsi_low_disconnected(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct slccb *cb = ti->ti_nexus; + + /* check phase completion */ + switch (slp->sl_msgphase) + { + case MSGPH_DISC: + if (cb != NULL) + { + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + TAILQ_INSERT_TAIL(&ti->ti_discq, cb, ccb_chain); + cb->ccb_error |= slp->sl_error; + cb->li->li_disc ++; + slp->sl_disc ++; + } + SCSI_LOW_SETUP_PHASE(ti, PH_DISC); +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_disconnected ++; +#endif /* SCSI_LOW_STATICS */ + break; + + case MSGPH_NULL: + slp->sl_error |= FATALIO; + + case MSGPH_CMDC: + if (cb != NULL) + { + cb->ccb_error |= slp->sl_error; + scsi_low_done(slp, cb); + } + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + break; + } + + scsi_low_clear_nexus(slp, ti); + scsi_low_start(slp); + return 1; +} + +/************************************************************** + * cmd out pointer setup + **************************************************************/ +int +scsi_low_cmd(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct slccb *cb = ti->ti_nexus; + + if (cb == NULL) + { + /* + * no slccb, 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; + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + scsi_low_info(slp, ti, "CMDOUT: slccb nexus not found"); + } + else if (slp->sl_nexus_call == 0) + { + slp->sl_nexus_call = 1; + (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); + } + 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 = ti->ti_nexus; + + if (cb == NULL) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + scsi_low_info(slp, ti, "DATA PHASE: slccb nexus not found"); + return EINVAL; + } + + if (direction != cb->ccb_scp.scp_direction) + { + scsi_low_info(slp, ti, "DATA PHASE: xfer direction mismatch"); + return EINVAL; + } + +#ifdef CAM + *bp = NULL; /* (cb->ccb == NULL) ? NULL : cb->bp; */ +#else + *bp = (cb->xs == NULL) ? NULL : cb->xs->bp; +#endif + return 0; +} + +/************************************************************** + * 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_DATA_LAST 0x30 + +static int scsi_low_errfunc_synch __P((struct targ_info *, u_int)); +static int scsi_low_errfunc_wide __P((struct targ_info *, u_int)); +static int scsi_low_errfunc_identify __P((struct targ_info *, u_int)); + +static int scsi_low_msgfunc_synch __P((struct targ_info *)); +static int scsi_low_msgfunc_wide __P((struct targ_info *)); +static int scsi_low_msgfunc_identify __P((struct targ_info *)); +static int scsi_low_msgfunc_user __P((struct targ_info *)); +static int scsi_low_msgfunc_abort __P((struct targ_info *)); + +struct scsi_low_msgout_data { + u_int md_flags; + u_int8_t md_msg; + int (*md_msgfunc) __P((struct targ_info *)); + int (*md_errfunc) __P((struct targ_info *, u_int)); +}; + +struct scsi_low_msgout_data scsi_low_msgout_data[] = { +/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_abort, NULL}, +/* 1 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL}, +/* 2 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL}, +/* 3 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL}, +/* 4 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL}, +/* 5 */ {SCSI_LOW_MSG_IDENTIFY, 0, scsi_low_msgfunc_identify, scsi_low_errfunc_identify}, +/* 6 */ {SCSI_LOW_MSG_SYNCH, 0, scsi_low_msgfunc_synch, scsi_low_errfunc_synch}, +/* 7 */ {SCSI_LOW_MSG_WIDE, 0, scsi_low_msgfunc_wide, scsi_low_errfunc_wide}, +/* 8 */ {SCSI_LOW_MSG_USER, 0, scsi_low_msgfunc_user, NULL}, +/* 9 */ {SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL}, +/* 10 */ {SCSI_LOW_MSG_ALL, 0}, +}; + +static int scsi_low_msginfunc_ext __P((struct targ_info *)); +static int scsi_low_synch __P((struct targ_info *)); +static int scsi_low_msginfunc_msg_reject __P((struct targ_info *)); +static int scsi_low_msginfunc_rejop __P((struct targ_info *)); +static int scsi_low_msginfunc_rdp __P((struct targ_info *)); +static int scsi_low_msginfunc_sdp __P((struct targ_info *)); +static int scsi_low_msginfunc_disc __P((struct targ_info *)); +static int scsi_low_msginfunc_cc __P((struct targ_info *)); +static int scsi_low_msginfunc_parity __P((struct targ_info *)); +static int scsi_low_msginfunc_noop __P((struct targ_info *)); +static void scsi_low_retry_phase __P((struct targ_info *)); + +struct scsi_low_msgin_data { + u_int md_len; + int (*md_msgfunc) __P((struct targ_info *)); +}; + +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_rdp}, +/* 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_rejop}, +/* b */ {1, scsi_low_msginfunc_rejop}, +/* 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_rejop}, +/* 0x21 */ {2, scsi_low_msginfunc_rejop}, +/* 0x22 */ {2, scsi_low_msginfunc_rejop}, +/* 0x23 */ {2, scsi_low_msginfunc_rejop}, +/* 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 */ +}; + +static 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; + ti->ti_tflags &= ~TARG_ASSERT_ATN; + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); +} + +/************************************************************** + * msgout + **************************************************************/ +static int +scsi_low_msgfunc_synch(ti) + struct targ_info *ti; +{ + struct lun_info *li = ti->ti_li; + int ptr = ti->ti_msgoutlen; + + if (li == NULL) + { + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + return EINVAL; + } + + ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; + ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; + ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; + ti->ti_msgoutstr[ptr + 3] = li->li_maxsynch.period; + ti->ti_msgoutstr[ptr + 4] = li->li_maxsynch.offset; + return MSG_EXTEND_SYNCHLEN + 2; +} + +static int +scsi_low_msgfunc_wide(ti) + struct targ_info *ti; +{ + struct lun_info *li = ti->ti_li; + int ptr = ti->ti_msgoutlen; + + if (li == NULL) + { + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + return EINVAL; + } + + ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; + ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; + ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; + ti->ti_msgoutstr[ptr + 3] = li->li_width; + return MSG_EXTEND_WIDELEN + 2; +} + +static int +scsi_low_msgfunc_identify(ti) + struct targ_info *ti; +{ + int ptr = ti->ti_msgoutlen;; + + if (ti->ti_li == NULL) + { + ti->ti_msgoutstr[ptr + 0] = 0x80; + scsi_low_info(ti->ti_sc, ti, "MSGOUT: lun unknown"); + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + } + else + { + ti->ti_msgoutstr[ptr + 0] = ID_MSG_SETUP(ti); + } + return 1; +} + +static int +scsi_low_msgfunc_user(ti) + struct targ_info *ti; +{ +#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT + struct slccb *cb = ti->ti_nexus; + int ptr = ti->ti_msgoutlen;; + + if (ti->ti_nexus == NULL) + { + ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; + return 1; + } + else + { + bcopy(cb->msgout, ti->ti_msgoutstr + ptr, SCSI_LOW_MAX_MSGLEN); + return cb->msgoutlen; + } +#else /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ + return 0; +#endif /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ +} + +static int +scsi_low_msgfunc_abort(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + /* The target should releases bus */ + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); + slp->sl_error |= /* ABORTIO */ FATALIO; + return 1; +} + +/* + * The following functions are called when targets give unexpected + * responces in msgin (after msgout). + */ +static int +scsi_low_errfunc_identify(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + struct lun_info *li = ti->ti_li; + + li->li_flags &= ~SCSI_LOW_DISC; + return 0; +} + +static int +scsi_low_errfunc_synch(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + + /* XXX: + * illegal behavior, however + * there are buggy devices! + */ + MSGIN_PERIOD(ti) = 0; + MSGIN_OFFSET(ti) = 0; + scsi_low_synch(ti); + return 0; +} + +static int +scsi_low_errfunc_wide(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + struct lun_info *li = ti->ti_li; + + li->li_width = 0; + return 0; +} + +int +scsi_low_msgout(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct scsi_low_msgout_data *mdp; + int len = 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 (ti->ti_ophase != ti->ti_phase) + { + ti->ti_omsgflags = 0; + ti->ti_emsgflags = 0; + } + + /* STEP II. + * We did not assert attention, however still our target required + * msgs. Resend previous msgs. + */ + if (ti->ti_ophase == PH_MSGOUT && !(ti->ti_tflags & TARG_ASSERT_ATN)) + { + ti->ti_msgflags |= ti->ti_omsgflags; +#ifdef SCSI_LOW_DIAGNOSTIC + printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * OK. clear flags. + */ + ti->ti_tflags &= ~TARG_ASSERT_ATN; + + /* STEP III. + * We have no msgs. send MSG_LOOP (OK?) + */ + if (scsi_low_is_msgout_continue(ti) == 0) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); + + /* STEP IV. + * Process all msgs + */ + ti->ti_msgoutlen = 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) (ti); + else + len = 1; + + ti->ti_msgoutlen += len; + if ((slp->sl_cfgflags & CFG_MSGUNIFY) == 0 || + ti->ti_msgflags == 0) + break; + if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) + break; + } + } + + if (scsi_low_is_msgout_continue(ti) != 0) + { +#ifdef SCSI_LOW_DIAGNOSTIC + printf("SCSI_LOW_ATTENTION(msgout): 0x%x\n", ti->ti_msgflags); +#endif /* SCSI_LOW_DIAGNOSTIC */ + scsi_low_attention(slp, ti); + } + + /* + * OK. advance old phase. + */ + ti->ti_ophase = ti->ti_phase; + return ti->ti_msgoutlen; +} + +/************************************************************** + * msgin + **************************************************************/ +static int +scsi_low_msginfunc_noop(ti) + struct targ_info *ti; +{ + + return 0; +} + +static int +scsi_low_msginfunc_rejop(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + u_int8_t msg = ti->ti_msgin[0]; + + printf("%s: MSGIN: msg 0x%x reject\n", slp->sl_xname, (u_int) msg); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_msginfunc_cc(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); + return 0; +} + +static int +scsi_low_msginfunc_disc(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); + return 0; +} + +static int +scsi_low_msginfunc_sdp(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_nexus != NULL) + ti->ti_nexus->ccb_sscp = slp->sl_scp; + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_msginfunc_rdp(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_nexus != NULL) + slp->sl_scp = ti->ti_nexus->ccb_sscp; + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_synch(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct lun_info *li = ti->ti_li; + u_int period = 0, offset = 0, speed; + u_char *s; + int error; + + if (MSGIN_PERIOD(ti) >= li->li_maxsynch.period && + MSGIN_OFFSET(ti) <= li->li_maxsynch.offset) + { + 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. + */ + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 0; + printf("%s: target brain damaged. async transfer\n", + slp->sl_xname); + return EINVAL; + } + + li->li_maxsynch.period = period; + li->li_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. + */ + printf("%s: synch neg failed. retry synch msg neg ...\n", + slp->sl_xname); + return error; + } + +#ifdef SCSI_LOW_INFORM + /* inform data */ + printf("%s(%d:%d): <%s> offset %d period %dns ", + slp->sl_xname, ti->ti_id, li->li_lun, s, offset, period * 4); + if (period != 0) + { + speed = 1000 * 10 / (period * 4); + printf("%d.%d M/s", speed / 10, speed % 10); + } + printf("\n"); +#endif + + return 0; +} + +static int +scsi_low_msginfunc_ext(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct slccb *cb = ti->ti_nexus; + struct lun_info *li = ti->ti_li; + 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(ti); + if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); + return 0; + + case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): + if (li == NULL) + break; + + 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 void +scsi_low_retry_phase(ti) + struct targ_info *ti; +{ + + switch (ti->ti_sphase) + { + case PH_MSGOUT: + ti->ti_msgflags |= ti->ti_omsgflags; + break; + + default: + break; + } +} + +static int +scsi_low_msginfunc_parity(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_sphase != PH_MSGOUT) + slp->sl_error |= PARITYERR; + scsi_low_retry_phase(ti); + return 0; +} + +static int +scsi_low_msginfunc_msg_reject(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct lun_info *li = ti->ti_li; + struct scsi_low_msgout_data *mdp; + u_int msgflags; + + if (li == NULL) + { + /* not yet lun nexus established! */ + goto out; + } + + switch (ti->ti_sphase) + { + case PH_CMD: + slp->sl_error |= CMDREJECT; + break; + + case PH_MSGOUT: + if (ti->ti_emsgflags == 0) + break; + + 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) (ti, msgflags); + break; + } + } + break; + + default: + break; + } + +out: + scsi_low_info(slp, ti, "msg rejected"); + slp->sl_error |= MSGERR; + return 0; +} + +void +scsi_low_msgin(slp, ti, c) + struct scsi_low_softc *slp; + struct targ_info *ti; + u_int8_t c; +{ + struct scsi_low_msgin_data *sdp; + struct lun_info *li; + u_int8_t msg; + + /* + * Phase changes, clear the pointer. + */ + if (ti->ti_ophase != ti->ti_phase) + { + ti->ti_sphase = ti->ti_ophase; + ti->ti_ophase = ti->ti_phase; + MSGINPTR_CLR(ti); +#ifdef SCSI_LOW_DIAGNOSTIC + ti->ti_msgin_hist_pointer = 0; +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * Store a current messages byte into buffer and + * wait for the completion of the current msg. + */ + ti->ti_msgin[ti->ti_msginptr ++] = 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); + } + + /* + * 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; +#ifdef SCSI_LOW_DIAGNOSTIC + if (ti->ti_msgin_hist_pointer < MSGIN_HISTORY_LEN) + { + ti->ti_msgin_history[ti->ti_msgin_hist_pointer] = msg; + ti->ti_msgin_hist_pointer ++; + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * Check comletion. + */ + if (ti->ti_msginptr < ti->ti_msginlen) + return; + + /* + * Do process. + */ + if ((msg & MSG_IDENTIFY) == 0) + { + (void) ((*sdp->md_msgfunc) (ti)); + } + else + { + li = ti->ti_li; + if (li == NULL) + { + li = scsi_low_establish_lun(ti, MSGCMD_LUN(msg)); + if (li == NULL) + goto badlun; + } + + if (ti->ti_nexus == NULL) + { + /* XXX: + * move the following functions to + * tag queue msg process in the future. + */ + if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) + goto badlun; + } + + if (MSGCMD_LUN(msg) != li->li_lun) + goto badlun; + } + + /* + * Msg process completed, reset msin pointer and assert ATN if desired. + */ + if (ti->ti_msginptr >= ti->ti_msginlen) + { + ti->ti_sphase = ti->ti_phase; + MSGINPTR_CLR(ti); + + if (scsi_low_is_msgout_continue(ti) != 0) + { +#ifdef SCSI_LOW_DIAGNOSTIC + printf("SCSI_LOW_ATTETION(msgin): 0x%x\n", + ti->ti_msgflags); +#endif /* SCSI_LOW_DIAGNOSTIC */ + scsi_low_attention(slp, ti); + } + } + return; + +badlun: + scsi_low_info(slp, ti, "MSGIN: identify lun mismatch"); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); +} + +/************************************************************** + * Qurik setup + **************************************************************/ +#define MAXOFFSET 0x10 + +static void +scsi_low_calcf(ti, li) + struct targ_info *ti; + struct lun_info *li; +{ + u_int period; + u_int8_t offset; + struct scsi_low_softc *slp = ti->ti_sc; + + li->li_flags &= ~SCSI_LOW_DISC; + if ((slp->sl_cfgflags & CFG_NODISC) == 0 && +#ifdef SDEV_NODISC + (li->li_quirks & SDEV_NODISC) == 0 && +#endif /* SDEV_NODISC */ + (li->li_cfgflags & SCSI_LOW_DISC) != 0) + li->li_flags |= SCSI_LOW_DISC; + + li->li_flags |= SCSI_LOW_NOPARITY; + if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && +#ifdef SDEV_NOPARITY + (li->li_quirks & SDEV_NOPARITY) == 0 && +#endif /* SDEV_NOPARITY */ + (li->li_cfgflags & SCSI_LOW_NOPARITY) == 0) + li->li_flags &= ~SCSI_LOW_NOPARITY; + + li->li_flags &= ~SCSI_LOW_SYNC; + if ((li->li_cfgflags & SCSI_LOW_SYNC) && + (slp->sl_cfgflags & CFG_ASYNC) == 0) + { + offset = SCSI_LOW_OFFSET(li->li_cfgflags); + if (offset > li->li_maxsynch.offset) + offset = li->li_maxsynch.offset; + li->li_flags |= SCSI_LOW_SYNC; + } + else + offset = 0; + + if (offset > 0) + { + period = SCSI_LOW_PERIOD(li->li_cfgflags); + if (period > SCSI_LOW_MAX_SYNCH_SPEED) + period = SCSI_LOW_MAX_SYNCH_SPEED; + if (period != 0) + period = 1000 * 10 / (period * 4); + if (period < li->li_maxsynch.period) + period = li->li_maxsynch.period; + } + else + period = 0; + + li->li_maxsynch.offset = offset; + li->li_maxsynch.period = period; +} + +#ifdef SCSI_LOW_TARGET_OPEN +static int +scsi_low_target_open(link, cf) + struct scsipi_link *link; + struct cfdata *cf; +{ + u_int target = link->scsipi_scsi.target; + u_int lun = link->scsipi_scsi.lun; + struct scsi_low_softc *slp; + struct targ_info *ti; + struct lun_info *li; + + slp = (struct scsi_low_softc *) link->adapter_softc; + ti = slp->sl_ti[target]; + li = scsi_low_alloc_li(ti, lun, 0); + if (li == NULL) + return 0; + + li->li_quirks = (u_int) link->quirks; + li->li_cfgflags = cf->cf_flags; + if (li->li_state > UNIT_SYNCH) + li->li_state = UNIT_SYNCH; + + scsi_low_calcf(ti, li); + + printf("%s(%d:%d): max period(%dns) max offset(%d) flags 0x%b\n", + slp->sl_xname, target, lun, + li->li_maxsynch.period * 4, + li->li_maxsynch.offset, + li->li_flags, SCSI_LOW_BITS); + return 0; +} +#endif /* SCSI_LOW_TARGET_OPEN */ + +/********************************************************** + * DEBUG SECTION + **********************************************************/ +static void +scsi_low_info(slp, ti, s) + struct scsi_low_softc *slp; + struct targ_info *ti; + u_char *s; +{ + + printf("%s: SCSI_LOW: %s\n", slp->sl_xname, s); + if (ti == NULL) + { + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + 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 slccb *cb = NULL; + + if (ti == NULL) + ti = slp->sl_nexus; + if (ti != NULL) + cb = ti->ti_nexus; + + printf("%s: TARGET(0x%lx) T_NEXUS(0x%lx) C_NEXUS(0x%lx) NDISCS(%d)\n", + slp->sl_xname, (u_long) ti, (u_long) slp->sl_nexus, + (u_long) cb, slp->sl_disc); + + /* target stat */ + if (ti != NULL) + { + struct sc_p *sp = &slp->sl_scp; + struct lun_info *li = ti->ti_li; + u_int flags = 0; + int lun = -1; + + if (li != NULL) + { + lun = li->li_lun; + flags = li->li_flags; + } + + printf("%s(%d:%d) ph<%s> => ph<%s>\n", slp->sl_xname, + ti->ti_id, lun, phase[(int) ti->ti_ophase], + phase[(int) ti->ti_phase]); + +printf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] STATUSIN: 0x%x T_FLAGS: 0x%x\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]), + ti->ti_status, ti->ti_tflags); +#ifdef SCSI_LOW_DIAGNOSTIC +printf("MSGIN HISTORY: (%d) [0x%x] => [0x%x] => [0x%x] => [0x%x] => [0x%x]\n", + ti->ti_msgin_hist_pointer, + (u_int) (ti->ti_msgin_history[0]), + (u_int) (ti->ti_msgin_history[1]), + (u_int) (ti->ti_msgin_history[2]), + (u_int) (ti->ti_msgin_history[3]), + (u_int) (ti->ti_msgin_history[4])); +#endif /* SCSI_LOW_DIAGNOSTIC */ + +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); + +printf("SCP: datalen 0x%x dataaddr 0x%lx ", + sp->scp_datalen, + (u_long) sp->scp_data); + + if (cb != NULL) + { +printf("CCB: cmdlen %x cmdaddr %lx cmd[0] %x datalen %x", + cb->ccb_scp.scp_cmdlen, + (u_long) cb->ccb_scp.scp_cmd, + (u_int) cb->ccb_scp.scp_cmd[0], + cb->ccb_scp.scp_datalen); + } + printf("\n"); + } + printf("error flags %b\n", slp->sl_error, SCSI_LOW_ERRORBITS); +} Property changes on: stable/4/sys/cam/scsi/scsi_low.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/cam/scsi/scsi_low.h =================================================================== --- stable/4/sys/cam/scsi/scsi_low.h (nonexistent) +++ stable/4/sys/cam/scsi/scsi_low.h (revision 67524) @@ -0,0 +1,615 @@ +/* $FreeBSD$ */ +/* $NecBSD: scsi_low.h,v 1.24 1999/07/23 21:00:05 honda Exp $ */ +/* $NetBSD$ */ + +#define SCSI_LOW_DIAGNOSTIC + +/* + * [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. + */ + +#ifndef _SCSI_LOW_H_ +#define _SCSI_LOW_H_ + +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#include +#define CAM +#include +#include +#include +#include +#include + +#include +#endif + +/* user configuration flags defs */ +#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 32 + +#define SCSI_LOW_MAX_MSGLEN 16 +#define SCSI_LOW_MAX_RETRY 3 + +/* timeout control macro */ +#define SCSI_LOW_MIN_TOUT 24 +#define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 4 +#define SCSI_LOW_POWDOWN_TC 15 +#define SCSI_LOW_MAX_PHCHANGES 256 + +/* max synch period */ +#ifndef SCSI_LOW_MAX_SYNCH_SPEED +#define SCSI_LOW_MAX_SYNCH_SPEED (100) /* 10.0M */ +#endif /* !SCSI_LOW_MAX_SYNCH_SPEED */ + +/************************************************* + * 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_int scp_direction; +#define SCSI_LOW_RWUNK (-1) +#define SCSI_LOW_WRITE 0 +#define SCSI_LOW_READ 1 +}; + +#define SCSI_LOW_SETUP_PHASE(ti, phase) \ +{ \ + if ((ti)->ti_phase != (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_TARGET_ASSERT_ATN(slp) \ +{ \ + (ti)->ti_tflags |= TARG_ASSERT_ATN; \ +} + +/************************************************* + * 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; + +#ifdef CAM + union ccb *ccb; + struct buf *bp; +#else + struct scsipi_xfer *xs; /* scsi upper */ +#endif + struct targ_info *ti; /* targ_info */ + struct lun_info *li; /* lun info */ + scsi_low_tag_t ccb_tag; /* tag */ + + /***************************************** + * Scsi data pointers (original and saved) + *****************************************/ + struct sc_p ccb_scp; /* given */ + struct sc_p ccb_sscp; /* saved scsi data pointer */ + +#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT + u_int8_t msgout[SCSI_LOW_MAX_MSGLEN]; /* scsi msgout */ + u_int msgoutlen; +#endif /* SCSI_LOW_SUPPORT_USER_MSGOUT */ + + /***************************************** + * Error or Timeout counters + *****************************************/ + u_int ccb_flags; +#define CCB_SENSE 0x01 + u_int ccb_error; + + int ccb_rcnt; /* retry counter */ + int ccb_tc; /* timer counter */ + int ccb_tcmax; /* max timeout */ + + /***************************************** + * Sense data buffer + *****************************************/ +#ifdef __NetBSD__ + struct scsipi_sense ccb_sense_cmd; + struct scsipi_sense_data ccb_sense; +#endif +#ifdef __FreeBSD__ + struct scsi_sense ccb_sense_cmd; + struct scsi_sense_data ccb_sense; +#endif +}; + +/* ccb assert */ +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#include +#endif +GENERIC_CCB_ASSERT(scsi_low, slccb) + +/************************************************* + * Target structures + *************************************************/ +struct 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 */ + + int li_disc; /* num disconnects */ + int li_maxnexus; + + /* + * lun state + */ +#define UNIT_SLEEP 0x00 +#define UNIT_START 0x01 +#define UNIT_SYNCH 0x02 +#define UNIT_WIDE 0x03 +#define UNIT_OK 0x04 +#define UNIT_NEGSTART UNIT_SYNCH + u_int li_state; /* target lun state */ + u_int li_maxstate; /* max state */ + + /* + * lun control flags + */ + u_int li_flags; /* real control flags */ + u_int li_cfgflags; /* given target cfgflags */ + u_int li_quirks; /* given target quirk */ + + /* + * lun synch and wide data + */ + struct synch { + u_int8_t offset; + u_int8_t period; + } li_maxsynch; /* synch data */ + + u_int li_width; +}; + +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 */ + + /* + * Nexus + */ + struct slccb *ti_nexus; /* current nexus */ + struct lun_info *ti_li; /* current nexus lun_info */ + + /* + * Target status + */ +#define TARG_ASSERT_ATN 0x01 + u_int ti_tflags; /* target state I */ + + /* + * Scsi phase control + */ + struct slccbtab ti_discq; /* disconnect queue */ + +#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 */ + + /* + * Status in + */ + u_int8_t ti_status; /* status in */ + + /* + * Msg in + */ + u_int ti_msginptr; /* msgin ptr */ + u_int ti_msginlen; /* expected msg length */ + u_int8_t ti_msgin[SCSI_LOW_MAX_MSGLEN]; /* msgin buffer */ + u_int ti_sphase; + +#ifdef SCSI_LOW_DIAGNOSTIC +#define MSGIN_HISTORY_LEN 5 + u_int8_t ti_msgin_history[MSGIN_HISTORY_LEN]; + int ti_msgin_hist_pointer; +#endif /* SCSI_LOW_DIAGNOSTIC */ + + /* + * 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_ABORT 0x00000002 +#define SCSI_LOW_MSG_REJECT 0x00000004 +#define SCSI_LOW_MSG_PARITY 0x00000008 +#define SCSI_LOW_MSG_ERROR 0x00000010 +#define SCSI_LOW_MSG_IDENTIFY 0x00000020 +#define SCSI_LOW_MSG_SYNCH 0x00000040 +#define SCSI_LOW_MSG_WIDE 0x00000080 +#define SCSI_LOW_MSG_USER 0x00000100 +#define SCSI_LOW_MSG_NOOP 0x00000200 +#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 */ + + /* + * lun info size. + */ + int ti_lunsize; +}; + +/************************************************* + * COMMON HEADER STRUCTURE + *************************************************/ +struct scsi_low_softc; +typedef struct scsi_low_softc *sc_low_t; + +#define SCSI_LOW_START_OK 0 +#define SCSI_LOW_START_FAIL 1 + +#define SC_LOW_INIT_T (int (*) __P((sc_low_t, int))) +#define SC_LOW_BUSRST_T (void (*) __P((sc_low_t))) +#define SC_LOW_LUN_INIT_T (int (*) __P((sc_low_t, struct targ_info *, struct lun_info *))) +#define SC_LOW_SELECT_T (int (*) __P((sc_low_t, struct slccb *))) +#define SC_LOW_ATTEN_T (void (*) __P((sc_low_t))) +#define SC_LOW_NEXUS_T (int (*) __P((sc_low_t, struct targ_info *))) +#define SC_LOW_MSG_T (int (*) __P((sc_low_t, struct targ_info *, u_int))) +#define SC_LOW_POLL_T (int (*) __P((void *))) +#define SC_LOW_POWER_T (int (*) __P((sc_low_t, u_int))) + +struct scsi_low_funcs { + int (*scsi_low_init) __P((sc_low_t, int)); + void (*scsi_low_bus_reset) __P((sc_low_t)); + int (*scsi_low_lun_init) __P((sc_low_t, struct targ_info *, struct lun_info *)); + + int (*scsi_low_start_bus) __P((sc_low_t, struct slccb *)); + int (*scsi_low_establish_nexus) __P((sc_low_t, struct targ_info *)); + + void (*scsi_low_attention) __P((sc_low_t)); + int (*scsi_low_msg) __P((sc_low_t, struct targ_info *, u_int)); + + int (*scsi_low_poll) __P((void *)); + +#define SCSI_LOW_POWDOWN 1 +#define SCSI_LOW_ENGAGE 2 + int (*scsi_low_power) __P((sc_low_t, u_int)); +}; + +/************************************************* + * SCSI LOW SOFTC + *************************************************/ +struct scsi_low_softc { + DEVPORT_DEVICE sl_dev; + u_char sl_xname[16]; + + /* upper interface */ +#ifdef CAM + struct cam_sim *sim; + struct cam_path *path; +#else + struct scsipi_link sl_link; +#endif + + /* my targets */ + struct targ_info *sl_ti[SCSI_LOW_NTARGETS]; + struct targ_info_tab sl_titab; + + /* current active nexus */ + int sl_nexus_call; + struct targ_info *sl_nexus; + + /* ccb start queue */ + struct slccbtab sl_start; + + /* retry limit and phase change counter */ + int sl_max_retry; + int sl_ph_count; + + /* selection & total num disconnect targets */ + int sl_disc; + struct targ_info *sl_selid; + + /* scsi phased 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 */ + + /* error */ +#define FATALIO 0x01 /* generic io error & retry io */ +#define ABORTIO 0x02 /* generic io error & terminate io */ +#define TIMEOUTIO 0x04 /* watch dog timeout */ +#define SELTIMEOUTIO 0x08 /* selection timeout */ +#define PDMAERR 0x10 /* dma xfer error */ +#define MSGERR 0x20 /* msgsys error */ +#define PARITYERR 0x40 /* parity error */ +#define BUSYERR 0x80 /* target busy error */ +#define CMDREJECT 0x100 /* cmd reject error */ +#define SCSI_LOW_ERRORBITS "\020\009cmdrej\008busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal" + u_int sl_error; /* error flags */ + + /* 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 0x01 +#define HW_RESUME 0x02 +#define HW_PDMASTART 0x04 +#define HW_INACTIVE 0x08 +#define HW_POWERCTRL 0x10 + + u_int sl_cfgflags; +#define CFG_NODISC 0x01 +#define CFG_NOPARITY 0x02 +#define CFG_NOATTEN 0x04 +#define CFG_ASYNC 0x08 +#define CFG_MSGUNIFY 0x10 + + /* host informations */ + u_int sl_hostid; + int sl_nluns; + int sl_ntargs; + int sl_openings; + + /* interface functions */ + struct scsi_low_funcs *sl_funcs; + +#if defined(i386) + u_int sl_irq; /* XXX */ +#endif /* i386 */ +#ifdef __FreeBSD__ + struct callout_handle engage_ch; + struct callout_handle timeout_ch; +#ifdef SCSI_LOW_POWFUNC + struct callout_handle recover_ch; +#endif +#endif /* __FreeBSD__ */ +}; + +/************************************************* + * SCSI LOW service functions + *************************************************/ +/* + * Scsi low attachment function. + */ +int scsi_low_attach __P((struct scsi_low_softc *, int, int, int, int)); +int scsi_low_dettach __P((struct scsi_low_softc *)); + +/* + * Scsi phase "bus service" functions. + * These functions are corresponding to each scsi bus phaeses. + */ +/* nexus abort (selection failed) */ +void scsi_low_clear_nexus __P((struct scsi_low_softc *, struct targ_info *)); +/* msgout phase */ +int scsi_low_msgout __P((struct scsi_low_softc *, struct targ_info *)); +/* msgin phase */ +void scsi_low_msgin __P((struct scsi_low_softc *, struct targ_info *, u_int8_t)); +/* data phase */ +int scsi_low_data __P((struct scsi_low_softc *, struct targ_info *, struct buf **, int)); +/* cmd phase */ +int scsi_low_cmd __P((struct scsi_low_softc *, struct targ_info *)); + +/* reselection phase */ +struct targ_info *scsi_low_reselected __P((struct scsi_low_softc *, u_int)); +/* disconnection phase */ +int scsi_low_disconnected __P((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 __P((struct scsi_low_softc *, int, u_char *)); + +/* + * Scsi utility fucntions + */ +/* print current status */ +void scsi_low_print __P((struct scsi_low_softc *, struct targ_info *)); +/* timeout utility (only in used scsi_low_pisa) */ +void scsi_low_timeout __P((void *)); +#define SCSI2_RESET_DELAY 5000000 +#define TWIDDLEWAIT 10000 +/* bus reset utility */ +void scsi_low_bus_reset __P((struct scsi_low_softc *)); + +/************************************************* + * Inline utility + *************************************************/ +static __inline u_int8_t scsi_low_identify __P((struct targ_info *ti)); +static __inline void scsi_low_attention __P((struct scsi_low_softc *, struct targ_info *)); +static __inline int scsi_low_is_msgout_continue __P((struct targ_info *)); +static __inline int scsi_low_assert_msg __P((struct scsi_low_softc *, struct targ_info *, u_int, int)); +static __inline void scsi_low_arbit_win __P((struct scsi_low_softc *, struct targ_info *)); + +static __inline int +scsi_low_is_msgout_continue(ti) + struct targ_info *ti; +{ + + return (ti->ti_msgflags != 0); +} + +static __inline u_int8_t +scsi_low_identify(ti) + struct targ_info *ti; +{ + u_int8_t msg; + struct lun_info *li = ti->ti_li; + + msg = (li->li_flags & SCSI_LOW_DISC) ? 0xc0 : 0x80; + msg |= li->li_lun; + return msg; +} + +#define ID_MSG_SETUP(ti) (scsi_low_identify(ti)) + +static __inline void +scsi_low_attention(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + (*slp->sl_funcs->scsi_low_attention) (slp); + SCSI_LOW_TARGET_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, ti); + return 0; +} + +static __inline void +scsi_low_arbit_win(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + slp->sl_selid = NULL; +} + +/************************************************* + * 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_QUEFULL 0x28 + +#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 +#ifdef __FreeBSD__ +#undef MSG_IDENTIFY +#endif +#define MSG_IDENTIFY 0x80 + +#define OS_DEPEND(s) (s) +#endif /* !_SCSI_LOW_H_ */ Property changes on: stable/4/sys/cam/scsi/scsi_low.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ata/ata-raid.c =================================================================== --- stable/4/sys/dev/ata/ata-raid.c (nonexistent) +++ stable/4/sys/dev/ata/ata-raid.c (revision 67524) @@ -0,0 +1,582 @@ +/*- + * Copyright (c) 2000 Søren Schmidt + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * $FreeBSD$ + */ + +#include "opt_global.h" +#include "opt_ata.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* device structures */ +static d_open_t aropen; +static d_strategy_t arstrategy; +static struct cdevsw ar_cdevsw = { + /* open */ aropen, + /* close */ nullclose, + /* read */ physread, + /* write */ physwrite, + /* ioctl */ noioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ arstrategy, + /* name */ "ar", + /* maj */ 157, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ D_DISK, + /* bmaj */ -1 +}; +static struct cdevsw ardisk_cdevsw; + +/* prototypes */ +static void ar_attach(struct ar_softc *); +static void ar_done(struct bio *); +static int ar_highpoint_conf(struct ad_softc *, struct ar_config *); +static int32_t ar_promise_magic(struct promise_raid_conf *); +static int ar_promise_conf(struct ad_softc *, struct ar_config *); +static int ar_read(struct ad_softc *, u_int32_t, int, char *); + +/* internal vars */ +static int ar_init = 0; +static struct ar_config ar_table; +MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver"); + +/* defines */ +#define PRINT_AD(adp) \ + printf(" ad%d: %luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n", \ + adp->lun, adp->total_secs / ((1024L * 1024L) / DEV_BSIZE), \ + adp->controller->dev_param[ATA_DEV(adp->unit)]->model, \ + adp->total_secs / (adp->heads * adp->sectors), \ + adp->heads, adp->sectors, device_get_unit(adp->controller->dev),\ + (adp->unit == ATA_MASTER) ? "master" : "slave", \ + (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", \ + ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)])) + +int +ar_probe(struct ad_softc *adp) +{ + if (!ar_init) { + bzero(&ar_table, sizeof(ar_table)); + ar_init = 1; + } + + switch(adp->controller->chiptype) { + case 0x4d33105a: + case 0x4d38105a: + case 0x4d30105a: + case 0x0d30105a: + if (ar_promise_conf(adp, &ar_table)) + break; + return 0; + + case 0x00041103: + if (ar_highpoint_conf(adp, &ar_table)) + break; + return 0; + } + return 1; +} + +static void +ar_attach(struct ar_softc *raid) +{ + dev_t dev; + int i; + + printf("ar%d: %luMB lun, raid->total_secs / ((1024L*1024L)/DEV_BSIZE)); + switch (raid->flags & (AR_F_RAID_0 | AR_F_RAID_1 | AR_F_SPAN)) { + case AR_F_RAID_0: + printf("RAID0 "); break; + case AR_F_RAID_1: + printf("RAID1 "); break; + case AR_F_SPAN: + printf("SPAN "); break; + case (AR_F_RAID_0 | AR_F_RAID_1): + printf("RAID0+1 "); break; + default: + printf("unknown array 0x%x ", raid->flags); + return; + } + printf("array> [%d/%d/%d] subdisks: \n", + raid->cylinders, raid->heads, raid->sectors); + for (i = 0; i < raid->num_subdisks; i++) + PRINT_AD(raid->subdisk[i]); + for (i = 0; i < raid->num_mirrordisks; i++) + PRINT_AD(raid->mirrordisk[i]); + + dev = disk_create(raid->lun, &raid->disk, 0, &ar_cdevsw, &ardisk_cdevsw); + dev->si_drv1 = raid; + dev->si_iosize_max = 256 * DEV_BSIZE; + raid->dev = dev; +} + +static int +aropen(dev_t dev, int flags, int fmt, struct proc *p) +{ + struct ar_softc *rdp = dev->si_drv1; + struct disklabel *dl; + + dl = &rdp->disk.d_label; + bzero(dl, sizeof *dl); + dl->d_secsize = DEV_BSIZE; + dl->d_nsectors = rdp->sectors; + dl->d_ntracks = rdp->heads; + dl->d_ncylinders = rdp->cylinders; + dl->d_secpercyl = rdp->sectors * rdp->heads; + dl->d_secperunit = rdp->total_secs; + return 0; +} + +static void +arstrategy(struct bio *bp) +{ + struct ar_softc *rdp = bp->bio_dev->si_drv1; + int lba, count, chunk; + caddr_t data; + + /* if it's a null transfer, return immediatly. */ + if (bp->bio_bcount == 0) { + bp->bio_resid = 0; + biodone(bp); + return; + } + + bp->bio_resid = bp->bio_bcount; + lba = bp->bio_pblkno; + data = bp->bio_data; + for (count = howmany(bp->bio_bcount, DEV_BSIZE); count > 0; + count -= chunk, lba += chunk, data += (chunk * DEV_BSIZE)) { + struct ar_buf *buf1, *buf2; + int plba; + + buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); + bzero(buf1, sizeof(struct ar_buf)); + if (rdp->flags & AR_F_SPAN) { + plba = lba; + while (plba >= (rdp->subdisk[buf1->drive]->total_secs-rdp->reserved) + && buf1->drive < rdp->num_subdisks) + plba-=(rdp->subdisk[buf1->drive++]->total_secs-rdp->reserved); + buf1->bp.bio_pblkno = plba; + chunk = min(rdp->subdisk[buf1->drive]->total_secs - + rdp->reserved - plba, count); + } + else if (rdp->flags & AR_F_RAID_0) { + plba = lba / rdp->interleave; + chunk = lba % rdp->interleave; + buf1->drive = plba % rdp->num_subdisks; + buf1->bp.bio_pblkno = + ((plba / rdp->num_subdisks) * rdp->interleave) + chunk; + chunk = min(rdp->interleave - chunk, count); + } + else { + buf1->bp.bio_pblkno = lba; + buf1->drive = 0; + chunk = count; + } + + buf1->bp.bio_pblkno += rdp->offset; + buf1->bp.bio_caller1 = (void *)rdp; + buf1->bp.bio_bcount = chunk * DEV_BSIZE; + buf1->bp.bio_data = data; + buf1->bp.bio_cmd = bp->bio_cmd; + buf1->bp.bio_flags = bp->bio_flags; + buf1->bp.bio_done = ar_done; + buf1->org = bp; + + /* simpleminded load balancing on RAID1 arrays */ + if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_READ) { + if (buf1->bp.bio_pblkno < + (rdp->last_lba[buf1->drive][rdp->last_disk] - 100) || + buf1->bp.bio_pblkno > + (rdp->last_lba[buf1->drive][rdp->last_disk] + 100)) { + rdp->last_disk = 1 - rdp->last_disk; + rdp->last_lba[buf1->drive][rdp->last_disk] = + buf1->bp.bio_pblkno; + } + if (rdp->last_disk) + buf1->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev; + else + buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev; + } + else + buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev; + + if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_WRITE) { + buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); + bcopy(buf1, buf2, sizeof(struct ar_buf)); + buf2->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev; + buf2->mirror = buf1; + buf1->mirror = buf2; + buf2->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf2); + } + buf1->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf1); + } +} + +static void +ar_done(struct bio *bp) +{ + struct ar_softc *rdp = (struct ar_softc *)bp->bio_caller1; + struct ar_buf *buf = (struct ar_buf *)bp; + int s; + + s = splbio(); + + if (bp->bio_flags & BIO_ERROR) { + if (bp->bio_cmd == BIO_WRITE || buf->done || !(rdp->flags&AR_F_RAID_1)){ + buf->org->bio_flags |= BIO_ERROR; + buf->org->bio_error = bp->bio_error; + } + printf("ar%d: subdisk error\n", rdp->lun); + } + + if (rdp->flags & AR_F_RAID_1) { + if (bp->bio_cmd == BIO_WRITE) { + if (!buf->done) { + buf->mirror->done = 1; + goto done; + } + } + else { + if (!buf->done && bp->bio_flags & BIO_ERROR) { + /* read error on this disk, try mirror */ + buf->done = 1; + buf->bp.bio_dev = rdp->mirrordisk[buf->drive]->dev; + buf->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio*)buf); + return; + } + } + } + buf->org->bio_resid -= bp->bio_bcount; + if (buf->org->bio_resid == 0) + biodone(buf->org); +done: + free(buf, M_AR); + splx(s); +} + +/* read the RAID info from a disk on a HighPoint controller */ +static int +ar_highpoint_conf(struct ad_softc *adp, struct ar_config *raidp) +{ + struct highpoint_raid_conf info; + struct ar_softc *raid; + int array_done = 0, r; + + if (ar_read(adp, 0x09, DEV_BSIZE, (char *)&info)) { + if (bootverbose) + printf("HighPoint read conf failed\n"); + return 1; + } + + /* check if this is a HighPoint RAID struct */ + if (info.magic != HPT_MAGIC_OK) { + if (bootverbose) + printf("HighPoint check1 failed\n"); + return 1; + } + + /* now convert HighPoint config info into our generic form */ + for (r = 0; r < 8; r++) { + if (!raidp->raid[r]) { + raidp->raid[r] = + (struct ar_softc*)malloc(sizeof(struct ar_softc),M_AR,M_NOWAIT); + if (!raidp->raid[r]) { + printf("ar: failed to allocate raid config storage\n"); + return 1; + } + bzero(raidp->raid[r], sizeof(struct ar_softc)); + } + raid = raidp->raid[r]; + + switch (info.type) { + case HPT_T_RAID_0: + /* check the order byte to determine what this really is */ + switch (info.order & (HPT_O_MIRROR | HPT_O_STRIPE)) { + case HPT_O_MIRROR: + goto hpt_mirror; + + case HPT_O_STRIPE: + if (raid->magic_0 && raid->magic_0 != info.magic_0) + continue; + raid->magic_0 = info.magic_0; + raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1); + raid->interleave = 1 << info.raid0_shift; + raid->subdisk[info.disk_number] = adp; + raid->num_subdisks++; + if ((raid->num_subdisks + raid->num_mirrordisks) == + (info.raid_disks * 2)) + array_done = 1; + break; + + case (HPT_O_MIRROR | HPT_O_STRIPE): + if (raid->magic_1 && raid->magic_1 != info.magic_1) + continue; + raid->magic_1 = info.magic_1; + raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1); + raid->mirrordisk[info.disk_number] = adp; + raid->num_mirrordisks++; + if ((raid->num_subdisks + raid->num_mirrordisks) == + (info.raid_disks * 2)) + array_done = 1; + break; + + default: + if (raid->magic_0 && raid->magic_0 != info.magic_0) + continue; + raid->magic_0 = info.magic_0; + raid->magic_1 = 0xffffffff; + raid->flags |= AR_F_RAID_0; + raid->interleave = 1 << info.raid0_shift; + raid->subdisk[info.disk_number] = adp; + raid->num_subdisks++; + if (raid->num_subdisks == info.raid_disks) + array_done = 1; + } + break; + + case HPT_T_RAID_1: +hpt_mirror: + if (raid->magic_1 && raid->magic_1 != info.magic_1) + continue; + raid->magic_1 = info.magic_1; + raid->magic_0 = 0xffffffff; + raid->flags |= AR_F_RAID_1; + if (info.disk_number == 0 && raid->num_subdisks == 0) { + raid->subdisk[raid->num_subdisks] = adp; + raid->num_subdisks = 1; + } + if (info.disk_number == 1 && raid->num_mirrordisks == 0) { + raid->mirrordisk[raid->num_mirrordisks] = adp; + raid->num_mirrordisks = 1; + } + if ((raid->num_subdisks + + raid->num_mirrordisks) == (info.raid_disks * 2)) + array_done = 1; + break; + + case HPT_T_SPAN: + if (raid->magic_0 && raid->magic_0 != info.magic_0) + continue; + raid->magic_0 = info.magic_0; + raid->flags |= AR_F_SPAN; + raid->subdisk[raid->num_subdisks] = adp; + raid->num_subdisks++; + if (raid->num_subdisks == info.raid_disks) + array_done = 1; + break; + + default: + printf("HighPoint unknown RAID type 0x%02x\n", info.type); + } + if (array_done) { + raid->lun = r; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = (info.total_secs - 9) / (63 * 255); + raid->total_secs = info.total_secs - (9 * raid->num_subdisks); + raid->offset = 10; + raid->reserved = 10; + ar_attach(raid); + return 0; + } + break; + } + return 0; +} + +static int32_t +ar_promise_magic(struct promise_raid_conf *info) +{ + int i, j; + int32_t magic = 0; + + for (i = 0; i < 4; i++) { + if ((info->raid[i].flags != PR_F_CONFED) || + (((info->raid[i].status & (PR_S_DEFINED|PR_S_ONLINE)) != + (PR_S_DEFINED|PR_S_ONLINE)))) + continue; + for (j = 0; j < info->raid[i].total_disks; j++) { + magic <<= 8; + magic |= ((info->raid[i].disk[j].magic_0 & 0x00ff0000)>>16); + } + } + return magic; +} + +/* read the RAID info from a disk on a Promise Fasttrak controller */ +static int +ar_promise_conf(struct ad_softc *adp, struct ar_config *raidp) +{ + struct promise_raid_conf info; + struct ar_softc *raid; + u_int32_t lba; + u_int32_t cksum, *ckptr; + int count, i, j, r; + + lba = adp->total_secs - adp->sectors; + + if (ar_read(adp, lba, 4 * DEV_BSIZE, (char *)&info)) { + if (bootverbose) + printf("Promise read conf failed\n"); + return 1; + } + + /* check if this is a Promise RAID struct */ + if (strncmp(info.promise_id, PR_MAGIC, sizeof(PR_MAGIC))) { + if (bootverbose) + printf("Promise check1 failed\n"); + return 1; + } + + /* check if the checksum is OK */ + for (cksum = 0, ckptr = (int32_t *)&info, count = 0; count < 511; count++) + cksum += *ckptr++; + if (cksum != *ckptr) { + if (bootverbose) + printf("Promise check2 failed\n"); + return 1; + } + + /* now convert Promise config info into our generic form */ + for (i = 0, r = 0; i < 4; i++) { + if ((info.raid[i].flags != PR_F_CONFED) || + (((info.raid[i].status & (PR_S_DEFINED|PR_S_ONLINE)) != + (PR_S_DEFINED|PR_S_ONLINE)))) { + continue; + } + + if (raidp->raid[r]) { + if (ar_promise_magic(&info) != raidp->raid[r]->magic_0) { + r++; + i--; + continue; + } + } + else { + if (!(raidp->raid[r] = (struct ar_softc *) + malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT))) { + printf("ar: failed to allocate raid config storage\n"); + return 1; + } + else + bzero(raidp->raid[r], sizeof(struct ar_softc)); + } + raid = raidp->raid[r]; + raid->magic_0 = ar_promise_magic(&info); + + switch (info.raid[i].type) { + case PR_T_STRIPE: + raid->flags |= AR_F_RAID_0; + raid->interleave = 1 << info.raid[i].raid0_shift; + break; + + case PR_T_MIRROR: + raid->flags |= AR_F_RAID_1; + break; + + case PR_T_SPAN: + raid->flags |= AR_F_SPAN; + break; + + default: + printf("Promise unknown RAID type 0x%02x\n", info.raid[i].type); + } + + /* find out where this disk is in the defined array */ + /* first RAID0 / SPAN disks */ + for (j = 0; j < info.raid[i].raid0_disks; j++) { + if (info.channel == info.raid[i].disk[j].channel && + info.device == info.raid[i].disk[j].device) { + raid->subdisk[raid->num_subdisks] = adp; + raid->num_subdisks++; + if (raid->num_subdisks > 1 && !(raid->flags & AR_F_SPAN)) { + raid->flags |= AR_F_RAID_0; + raid->interleave = 1 << info.raid[i].raid0_shift; + } + } + } + + /* if any left they are RAID1 disks eventually in a RADI0+1 config */ + for (; j < info.raid[i].total_disks; j++) { + if (info.channel == info.raid[i].disk[j].channel && + info.device == info.raid[i].disk[j].device) { + raid-> mirrordisk[raid->num_mirrordisks] = adp; + raid->num_mirrordisks++; + } + } + + /* do we have a complete array to attach to ? */ + if (raid->num_subdisks + raid->num_mirrordisks == + info.raid[i].total_disks) { + raid->lun = r; + raid->heads = info.raid[i].heads + 1; + raid->sectors = info.raid[i].sectors; + raid->cylinders = info.raid[i].cylinders + 1; + raid->total_secs = info.raid[i].total_secs; + raid->offset = 0; + raid->reserved = 63; + ar_attach(raid); + } + r++; + } + return 0; +} + +int +ar_read(struct ad_softc *adp, u_int32_t lba, int count, char *data) +{ + if (ata_command(adp->controller, adp->unit | ATA_D_LBA, + (count > DEV_BSIZE) ? ATA_C_READ_MUL : ATA_C_READ, + (lba >> 8) & 0xffff, (lba >> 24) & 0xff, lba & 0xff, + count / DEV_BSIZE, 0, ATA_WAIT_INTR)) { + ata_printf(adp->controller, adp->unit, "RAID read config failed\n"); + return 1; + } + if (ata_wait(adp->controller, adp->unit, ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)) { + ata_printf(adp->controller, adp->unit, "RAID read config timeout\n"); + return 1; + } + insw(adp->controller->ioaddr + ATA_DATA, data, count/sizeof(int16_t)); + inb(adp->controller->ioaddr + ATA_STATUS); + return 0; +} Property changes on: stable/4/sys/dev/ata/ata-raid.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ata/ata-raid.h =================================================================== --- stable/4/sys/dev/ata/ata-raid.h (nonexistent) +++ stable/4/sys/dev/ata/ata-raid.h (revision 67524) @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 2000 Søren Schmidt + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * $FreeBSD$ + */ + +struct ar_softc { + int lun; + int32_t magic_0; + int32_t magic_1; + int flags; +#define AR_F_RAID_0 0x0001 /* STRIPE */ +#define AR_F_RAID_1 0x0002 /* MIRROR */ +#define AR_F_SPAN 0x0004 /* SPAN */ + + int num_subdisks; + struct ad_softc *subdisk[8]; + int num_mirrordisks; + struct ad_softc *mirrordisk[8]; + int interleave; + int last_disk; + int32_t last_lba[8][2]; + + u_int16_t heads; + u_int16_t sectors; + u_int32_t cylinders; + u_int32_t total_secs; + int reserved; /* sectors that are NOT to be used */ + int offset; /* offset from start of disk */ + + struct disk disk; /* disklabel/slice stuff */ + dev_t dev; /* device place holder */ + +}; + +struct ar_config { + int num_raids; + struct ar_softc *raid[8]; /* configs for each RAID */ +}; + +struct ar_buf { + struct bio bp; + struct bio *org; + int drive; + struct ar_buf *mirror; + int done; +}; + +struct highpoint_raid_conf { + int8_t filler1[32]; + u_int32_t magic; /* 0x20 */ +#define HPT_MAGIC_OK 0x5a7816f0 +#define HPT_MAGIC_BAD 0x5a7816fd + + u_int32_t magic_0; + u_int32_t magic_1; + u_int32_t order; +#define HPT_O_MIRROR 0x01 +#define HPT_O_STRIPE 0x02 +#define HPT_O_OK 0x04 + + u_int8_t raid_disks; + u_int8_t raid0_shift; + u_int8_t type; +#define HPT_T_RAID_0 0x00 +#define HPT_T_RAID_1 0x01 +#define HPT_T_RAID_01_RAID_0 0x02 +#define HPT_T_SPAN 0x03 +#define HPT_T_RAID_3 0x04 +#define HPT_T_RAID_5 0x05 +#define HPT_T_SINGLEDISK 0x06 +#define HPT_T_RAID_01_RAID_1 0x07 + + u_int8_t disk_number; + u_int32_t total_secs; + u_int32_t disk_mode; + u_int32_t boot_mode; + u_int8_t boot_disk; + u_int8_t boot_protect; + u_int8_t error_log_entries; + u_int8_t error_log_index; + struct { + u_int32_t timestamp; + u_int8_t reason; +#define HPT_R_REMOVED 0xfe +#define HPT_R_BROKEN 0xff + + u_int8_t disk; + u_int8_t status; + u_int8_t sectors; + u_int32_t lba; + } errorlog[32]; + int8_t filler2[60]; +}; + +struct promise_raid_conf { + char promise_id[24]; +#define PR_MAGIC "Promise Technology, Inc." + + int32_t dummy_0; + int32_t magic_0; + int16_t dummy_1; + int8_t channel; + int8_t device; + int32_t magic_1; + int16_t dummy_2; + int8_t filler1[470]; + struct { + int32_t flags; /* 0x200 */ +#define PR_F_CONFED 0x00000080 + + int8_t dummy_0; + int8_t device_0; + int8_t dummy_1; + int8_t device_1; + int32_t magic_0; + int32_t dummy_2; + int32_t dummy_3; /* 0x210 */ + int32_t disk_secs; + int32_t dummy_4; + int16_t dummy_5; + int8_t status; +#define PR_S_DEFINED 0x01 +#define PR_S_ONLINE 0x02 +#define PR_S_OFFLINE 0x10 + + int8_t type; +#define PR_T_STRIPE 0x00 +#define PR_T_MIRROR 0x01 +#define PR_T_STRIPE_MIRROR 0x04 +#define PR_T_SPAN 0x08 + + u_int8_t total_disks; /* 0x220 */ + u_int8_t raid0_shift; + u_int8_t raid0_disks; + u_int8_t dummy_6; + u_int32_t total_secs; + u_int16_t cylinders; + u_int8_t heads; + u_int8_t sectors; + int32_t magic_1; + int32_t dummy_7; /* 0x230 */ + struct { + int16_t dummy_0; + int8_t channel; + int8_t device; + int32_t magic_0; + int32_t disk_number; /* subdisk # */ + } disk[8]; + } raid[4]; + int32_t filler2[235]; + uint32_t checksum; +}; + +int ar_probe(struct ad_softc *); + Property changes on: stable/4/sys/dev/ata/ata-raid.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/mly/mly.c =================================================================== --- stable/4/sys/dev/mly/mly.c (nonexistent) +++ stable/4/sys/dev/mly/mly.c (revision 67524) @@ -0,0 +1,1713 @@ +/*- + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* XXX: This is not where we should get fldoff() from. */ +#include + +#include +#include +#define MLY_DEFINE_TABLES +#include + +static int mly_get_controllerinfo(struct mly_softc *sc); +static void mly_scan_devices(struct mly_softc *sc); +static void mly_rescan_btl(struct mly_softc *sc, int bus, int target); +static void mly_complete_rescan(struct mly_command *mc); +static int mly_get_eventstatus(struct mly_softc *sc); +static int mly_enable_mmbox(struct mly_softc *sc); +static int mly_flush(struct mly_softc *sc); +static int mly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, + size_t datasize, u_int8_t *status, void *sense_buffer, size_t *sense_length); +static void mly_fetch_event(struct mly_softc *sc); +static void mly_complete_event(struct mly_command *mc); +static void mly_process_event(struct mly_softc *sc, struct mly_event *me); +static void mly_periodic(void *data); + +static int mly_immediate_command(struct mly_command *mc); +static int mly_start(struct mly_command *mc); +static void mly_complete(void *context, int pending); + +static int mly_get_slot(struct mly_command *mc); +static void mly_alloc_command_cluster_map(void *arg, bus_dma_segment_t *segs, int nseg, int error); +static void mly_alloc_command_cluster(struct mly_softc *sc); +static void mly_map_command(struct mly_command *mc); +static void mly_unmap_command(struct mly_command *mc); + +static int mly_fwhandshake(struct mly_softc *sc); + +static void mly_describe_controller(struct mly_softc *sc); +#ifdef MLY_DEBUG +static void mly_printstate(struct mly_softc *sc); +static void mly_print_command(struct mly_command *mc); +static void mly_print_packet(struct mly_command *mc); +static void mly_panic(struct mly_softc *sc, char *reason); +#endif + +/******************************************************************************** + ******************************************************************************** + Device Interface + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Initialise the controller and softc + */ +int +mly_attach(struct mly_softc *sc) +{ + int error; + + debug_called(1); + + /* + * Initialise per-controller queues. + */ + TAILQ_INIT(&sc->mly_freecmds); + TAILQ_INIT(&sc->mly_ready); + TAILQ_INIT(&sc->mly_completed); + TAILQ_INIT(&sc->mly_clusters); + +#if __FreeBSD_version >= 500005 + /* + * Initialise command-completion task. + */ + TASK_INIT(&sc->mly_task_complete, 0, mly_complete, sc); +#endif + + /* disable interrupts before we start talking to the controller */ + MLY_MASK_INTERRUPTS(sc); + + /* + * Wait for the controller to come ready, handshake with the firmware if required. + * This is typically only necessary on platforms where the controller BIOS does not + * run. + */ + if ((error = mly_fwhandshake(sc))) + return(error); + + /* + * Initialise the slot allocator so that we can issue commands. + */ + sc->mly_max_commands = MLY_SLOT_MAX; + sc->mly_last_slot = MLY_SLOT_START; + + /* + * Obtain controller feature information + */ + if ((error = mly_get_controllerinfo(sc))) + return(error); + + /* + * Update the slot allocator limit based on the controller inquiry. + */ + sc->mly_max_commands = imin(sc->mly_controllerinfo->maximum_parallel_commands, MLY_SLOT_MAX); + + /* + * Get the current event counter for health purposes, populate the initial + * health status buffer. + */ + if ((error = mly_get_eventstatus(sc))) + return(error); + + /* + * Enable memory-mailbox mode + */ + if ((error = mly_enable_mmbox(sc))) + return(error); + + /* + * Attach to CAM. + */ + if ((error = mly_cam_attach(sc))) + return(error); + + /* + * Print a little information about the controller + */ + mly_describe_controller(sc); + + /* + * Mark all attached devices for rescan + */ + mly_scan_devices(sc); + + /* + * Instigate the first status poll immediately. Rescan completions won't + * happen until interrupts are enabled, which should still be before + * the SCSI subsystem gets to us. (XXX assuming CAM and interrupt-driven + * discovery here...) + */ + mly_periodic((void *)sc); + + /* enable interrupts now */ + MLY_UNMASK_INTERRUPTS(sc); + + return(0); +} + +/******************************************************************************** + * Bring the controller to a state where it can be safely left alone. + */ +void +mly_detach(struct mly_softc *sc) +{ + + debug_called(1); + + /* kill the periodic event */ + untimeout(mly_periodic, sc, sc->mly_periodic); + + sc->mly_state |= MLY_STATE_SUSPEND; + + /* flush controller */ + mly_printf(sc, "flushing cache..."); + printf("%s\n", mly_flush(sc) ? "failed" : "done"); + + MLY_MASK_INTERRUPTS(sc); +} + +/******************************************************************************** + ******************************************************************************** + Command Wrappers + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Fill in the mly_controllerinfo and mly_controllerparam fields in the softc. + */ +static int +mly_get_controllerinfo(struct mly_softc *sc) +{ + struct mly_command_ioctl mci; + u_int8_t status; + int error; + + debug_called(1); + + if (sc->mly_controllerinfo != NULL) + free(sc->mly_controllerinfo, M_DEVBUF); + + /* build the getcontrollerinfo ioctl and send it */ + bzero(&mci, sizeof(mci)); + sc->mly_controllerinfo = NULL; + mci.sub_ioctl = MDACIOCTL_GETCONTROLLERINFO; + if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerinfo, sizeof(*sc->mly_controllerinfo), + &status, NULL, NULL))) + return(error); + if (status != 0) + return(EIO); + + if (sc->mly_controllerparam != NULL) + free(sc->mly_controllerparam, M_DEVBUF); + + /* build the getcontrollerparameter ioctl and send it */ + bzero(&mci, sizeof(mci)); + sc->mly_controllerparam = NULL; + mci.sub_ioctl = MDACIOCTL_GETCONTROLLERPARAMETER; + if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerparam, sizeof(*sc->mly_controllerparam), + &status, NULL, NULL))) + return(error); + if (status != 0) + return(EIO); + + return(0); +} + +/******************************************************************************** + * Schedule all possible devices for a rescan. + * + */ +static void +mly_scan_devices(struct mly_softc *sc) +{ + int bus, target, nchn; + + debug_called(1); + + /* + * Clear any previous BTL information. + */ + bzero(&sc->mly_btl, sizeof(sc->mly_btl)); + + /* + * Mark all devices as requiring a rescan, and let the early periodic scan collect them. + */ + nchn = sc->mly_controllerinfo->physical_channels_present + + sc->mly_controllerinfo->virtual_channels_present; + for (bus = 0; bus < nchn; bus++) + for (target = 0; target < MLY_MAX_TARGETS; target++) + sc->mly_btl[bus][target].mb_flags = MLY_BTL_RESCAN; + +} + +/******************************************************************************** + * Rescan a device, possibly as a consequence of getting an event which suggests + * that it may have changed. + */ +static void +mly_rescan_btl(struct mly_softc *sc, int bus, int target) +{ + struct mly_command *mc; + struct mly_command_ioctl *mci; + + debug_called(2); + + /* get a command */ + mc = NULL; + if (mly_alloc_command(sc, &mc)) + return; /* we'll be retried soon */ + + /* set up the data buffer */ + if ((mc->mc_data = malloc(sizeof(union mly_devinfo), M_DEVBUF, M_NOWAIT)) == NULL) { + mly_release_command(mc); + return; /* we'll get retried the next time a command completes */ + } + bzero(mc->mc_data, sizeof(union mly_devinfo)); + mc->mc_flags |= MLY_CMD_DATAIN; + mc->mc_complete = mly_complete_rescan; + + sc->mly_btl[bus][target].mb_flags &= ~MLY_BTL_RESCAN; + + /* + * Build the ioctl. + * + * At this point we are committed to sending this request, as it + * will be the only one constructed for this particular update. + */ + mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; + mci->opcode = MDACMD_IOCTL; + mci->addr.phys.controller = 0; + mci->timeout.value = 30; + mci->timeout.scale = MLY_TIMEOUT_SECONDS; + if (bus >= sc->mly_controllerinfo->physical_channels_present) { + mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getlogdevinfovalid); + mci->sub_ioctl = MDACIOCTL_GETLOGDEVINFOVALID; + mci->addr.log.logdev = ((bus - sc->mly_controllerinfo->physical_channels_present) * MLY_MAX_TARGETS) + + target; + debug(2, "logical device %d", mci->addr.log.logdev); + } else { + mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getphysdevinfovalid); + mci->sub_ioctl = MDACIOCTL_GETPHYSDEVINFOVALID; + mci->addr.phys.lun = 0; + mci->addr.phys.target = target; + mci->addr.phys.channel = bus; + debug(2, "physical device %d:%d", mci->addr.phys.channel, mci->addr.phys.target); + } + + /* + * Use the ready queue to get this command dispatched. + */ + mly_enqueue_ready(mc); + mly_startio(sc); +} + +/******************************************************************************** + * Handle the completion of a rescan operation + */ +static void +mly_complete_rescan(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + struct mly_ioctl_getlogdevinfovalid *ldi; + struct mly_ioctl_getphysdevinfovalid *pdi; + int bus, target; + + debug_called(2); + + /* iff the command completed OK, we should use the result to update our data */ + if (mc->mc_status == 0) { + if (mc->mc_length == sizeof(*ldi)) { + ldi = (struct mly_ioctl_getlogdevinfovalid *)mc->mc_data; + bus = MLY_LOGDEV_BUS(sc, ldi->logical_device_number); + target = MLY_LOGDEV_TARGET(ldi->logical_device_number); + sc->mly_btl[bus][target].mb_flags = MLY_BTL_LOGICAL; /* clears all other flags */ + sc->mly_btl[bus][target].mb_type = ldi->raid_level; + sc->mly_btl[bus][target].mb_state = ldi->state; + debug(2, "BTL rescan for %d returns %s, %s", ldi->logical_device_number, + mly_describe_code(mly_table_device_type, ldi->raid_level), + mly_describe_code(mly_table_device_state, ldi->state)); + } else if (mc->mc_length == sizeof(*pdi)) { + pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data; + bus = pdi->channel; + target = pdi->target; + sc->mly_btl[bus][target].mb_flags = MLY_BTL_PHYSICAL; /* clears all other flags */ + sc->mly_btl[bus][target].mb_type = MLY_DEVICE_TYPE_PHYSICAL; + sc->mly_btl[bus][target].mb_state = pdi->state; + if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED) + sc->mly_btl[bus][target].mb_flags |= MLY_BTL_PROTECTED; + debug(2, "BTL rescan for %d:%d returns %s", bus, target, + mly_describe_code(mly_table_device_state, pdi->state)); + } else { + mly_printf(sc, "BTL rescan result corrupted\n"); + } + } else { + /* + * A request sent for a device beyond the last device present will fail. + * We don't care about this, so we do nothing about it. + */ + } + free(mc->mc_data, M_DEVBUF); + mly_release_command(mc); +} + +/******************************************************************************** + * Get the current health status and set the 'next event' counter to suit. + */ +static int +mly_get_eventstatus(struct mly_softc *sc) +{ + struct mly_command_ioctl mci; + struct mly_health_status *mh; + u_int8_t status; + int error; + + /* build the gethealthstatus ioctl and send it */ + bzero(&mci, sizeof(mci)); + mh = NULL; + mci.sub_ioctl = MDACIOCTL_GETHEALTHSTATUS; + + if ((error = mly_ioctl(sc, &mci, (void **)&mh, sizeof(*mh), &status, NULL, NULL))) + return(error); + if (status != 0) + return(EIO); + + /* get the event counter */ + sc->mly_event_change = mh->change_counter; + sc->mly_event_waiting = mh->next_event; + sc->mly_event_counter = mh->next_event; + + /* save the health status into the memory mailbox */ + bcopy(mh, &sc->mly_mmbox->mmm_health.status, sizeof(*mh)); + + debug(1, "initial change counter %d, event counter %d", mh->change_counter, mh->next_event); + + free(mh, M_DEVBUF); + return(0); +} + +/******************************************************************************** + * Enable the memory mailbox mode. + */ +static int +mly_enable_mmbox(struct mly_softc *sc) +{ + struct mly_command_ioctl mci; + u_int8_t *sp, status; + int error; + + debug_called(1); + + /* build the ioctl and send it */ + bzero(&mci, sizeof(mci)); + mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX; + /* set buffer addresses */ + mci.param.setmemorymailbox.command_mailbox_physaddr = sc->mly_mmbox_busaddr + fldoff(mly_mmbox, mmm_command); + mci.param.setmemorymailbox.status_mailbox_physaddr = sc->mly_mmbox_busaddr + fldoff(mly_mmbox, mmm_status); + mci.param.setmemorymailbox.health_buffer_physaddr = sc->mly_mmbox_busaddr + fldoff(mly_mmbox, mmm_health); + + /* set buffer sizes - abuse of data_size field is revolting */ + sp = (u_int8_t *)&mci.data_size; + sp[0] = ((sizeof(union mly_command_packet) * MLY_MMBOX_COMMANDS) / 1024); + sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) / 1024; + mci.param.setmemorymailbox.health_buffer_size = sizeof(union mly_health_region) / 1024; + + debug(1, "memory mailbox at %p (0x%llx/%d 0x%llx/%d 0x%llx/%d", sc->mly_mmbox, + mci.param.setmemorymailbox.command_mailbox_physaddr, sp[0], + mci.param.setmemorymailbox.status_mailbox_physaddr, sp[1], + mci.param.setmemorymailbox.health_buffer_physaddr, mci.param.setmemorymailbox.health_buffer_size); + + if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) + return(error); + if (status != 0) + return(EIO); + sc->mly_state |= MLY_STATE_MMBOX_ACTIVE; + debug(1, "memory mailbox active"); + return(0); +} + +/******************************************************************************** + * Flush all pending I/O from the controller. + */ +static int +mly_flush(struct mly_softc *sc) +{ + struct mly_command_ioctl mci; + u_int8_t status; + int error; + + debug_called(1); + + /* build the ioctl */ + bzero(&mci, sizeof(mci)); + mci.sub_ioctl = MDACIOCTL_FLUSHDEVICEDATA; + mci.param.deviceoperation.operation_device = MLY_OPDEVICE_PHYSICAL_CONTROLLER; + + /* pass it off to the controller */ + if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) + return(error); + + return((status == 0) ? 0 : EIO); +} + +/******************************************************************************** + * Perform an ioctl command. + * + * If (data) is not NULL, the command requires data transfer. If (*data) is NULL + * the command requires data transfer from the controller, and we will allocate + * a buffer for it. If (*data) is not NULL, the command requires data transfer + * to the controller. + * + * XXX passing in the whole ioctl structure is ugly. Better ideas? + * + * XXX we don't even try to handle the case where datasize > 4k. We should. + */ +static int +mly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, size_t datasize, + u_int8_t *status, void *sense_buffer, size_t *sense_length) +{ + struct mly_command *mc; + struct mly_command_ioctl *mci; + int error; + + debug_called(1); + + mc = NULL; + if (mly_alloc_command(sc, &mc)) { + error = ENOMEM; + goto out; + } + + /* copy the ioctl structure, but save some important fields and then fixup */ + mci = &mc->mc_packet->ioctl; + ioctl->sense_buffer_address = mci->sense_buffer_address; + ioctl->maximum_sense_size = mci->maximum_sense_size; + *mci = *ioctl; + mci->opcode = MDACMD_IOCTL; + mci->timeout.value = 30; + mci->timeout.scale = MLY_TIMEOUT_SECONDS; + + /* handle the data buffer */ + if (data != NULL) { + if (*data == NULL) { + /* allocate data buffer */ + if ((mc->mc_data = malloc(datasize, M_DEVBUF, M_NOWAIT)) == NULL) { + error = ENOMEM; + goto out; + } + mc->mc_flags |= MLY_CMD_DATAIN; + } else { + mc->mc_data = *data; + mc->mc_flags |= MLY_CMD_DATAOUT; + } + mc->mc_length = datasize; + mc->mc_packet->generic.data_size = datasize; + } + + /* run the command */ + if ((error = mly_immediate_command(mc))) + goto out; + + /* clean up and return any data */ + *status = mc->mc_status; + if ((mc->mc_sense > 0) && (sense_buffer != NULL)) { + bcopy(mc->mc_packet, sense_buffer, mc->mc_sense); + *sense_length = mc->mc_sense; + goto out; + } + + /* should we return a data pointer? */ + if ((data != NULL) && (*data == NULL)) + *data = mc->mc_data; + + /* command completed OK */ + error = 0; + +out: + if (mc != NULL) { + /* do we need to free a data buffer we allocated? */ + if (error && (mc->mc_data != NULL) && (*data == NULL)) + free(mc->mc_data, M_DEVBUF); + mly_release_command(mc); + } + return(error); +} + +/******************************************************************************** + * Fetch one event from the controller. + */ +static void +mly_fetch_event(struct mly_softc *sc) +{ + struct mly_command *mc; + struct mly_command_ioctl *mci; + int s; + u_int32_t event; + + debug_called(2); + + /* get a command */ + mc = NULL; + if (mly_alloc_command(sc, &mc)) + return; /* we'll get retried the next time a command completes */ + + /* set up the data buffer */ + if ((mc->mc_data = malloc(sizeof(struct mly_event), M_DEVBUF, M_NOWAIT)) == NULL) { + mly_release_command(mc); + return; /* we'll get retried the next time a command completes */ + } + bzero(mc->mc_data, sizeof(struct mly_event)); + mc->mc_length = sizeof(struct mly_event); + mc->mc_flags |= MLY_CMD_DATAIN; + mc->mc_complete = mly_complete_event; + + /* + * Get an event number to fetch. It's possible that we've raced with another + * context for the last event, in which case there will be no more events. + */ + s = splcam(); + if (sc->mly_event_counter == sc->mly_event_waiting) { + mly_release_command(mc); + splx(s); + return; + } + event = sc->mly_event_counter++; + splx(s); + + /* + * Build the ioctl. + * + * At this point we are committed to sending this request, as it + * will be the only one constructed for this particular event number. + */ + mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; + mci->opcode = MDACMD_IOCTL; + mci->data_size = sizeof(struct mly_event); + mci->addr.phys.lun = (event >> 16) & 0xff; + mci->addr.phys.target = (event >> 24) & 0xff; + mci->addr.phys.channel = 0; + mci->addr.phys.controller = 0; + mci->timeout.value = 30; + mci->timeout.scale = MLY_TIMEOUT_SECONDS; + mci->sub_ioctl = MDACIOCTL_GETEVENT; + mci->param.getevent.sequence_number_low = event & 0xffff; + + debug(2, "fetch event %u", event); + + /* + * Use the ready queue to get this command dispatched. + */ + mly_enqueue_ready(mc); + mly_startio(sc); +} + +/******************************************************************************** + * Handle the completion of an event poll. + * + * Note that we don't actually have to instigate another poll; the completion of + * this command will trigger that if there are any more events to poll for. + */ +static void +mly_complete_event(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + struct mly_event *me = (struct mly_event *)mc->mc_data; + + debug_called(2); + + /* + * If the event was successfully fetched, process it. + */ + if (mc->mc_status == SCSI_STATUS_OK) { + mly_process_event(sc, me); + free(me, M_DEVBUF); + } + mly_release_command(mc); +} + +/******************************************************************************** + * Process a controller event. + */ +static void +mly_process_event(struct mly_softc *sc, struct mly_event *me) +{ + struct scsi_sense_data *ssd = (struct scsi_sense_data *)&me->sense[0]; + char *fp, *tp; + int bus, target, event, class, action; + + /* + * Errors can be reported using vendor-unique sense data. In this case, the + * event code will be 0x1c (Request sense data present), the sense key will + * be 0x09 (vendor specific), the MSB of the ASC will be set, and the + * actual event code will be a 16-bit value comprised of the ASCQ (low byte) + * and low seven bits of the ASC (low seven bits of the high byte). + */ + if ((me->code == 0x1c) && + ((ssd->flags & SSD_KEY) == SSD_KEY_Vendor_Specific) && + (ssd->add_sense_code & 0x80)) { + event = ((int)(ssd->add_sense_code & ~0x80) << 8) + ssd->add_sense_code_qual; + } else { + event = me->code; + } + + /* look up event, get codes */ + fp = mly_describe_code(mly_table_event, event); + + debug(2, "Event %d code 0x%x", me->sequence_number, me->code); + + /* quiet event? */ + class = fp[0]; + if (isupper(class) && bootverbose) + class = tolower(class); + + /* get action code, text string */ + action = fp[1]; + tp = &fp[2]; + + /* + * Print some information about the event. + * + * This code uses a table derived from the corresponding portion of the Linux + * driver, and thus the parser is very similar. + */ + switch(class) { + case 'p': /* error on physical device */ + mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); + if (action == 'r') + sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; + break; + case 'l': /* error on logical unit */ + case 'm': /* message about logical unit */ + bus = MLY_LOGDEV_BUS(sc, me->lun); + target = MLY_LOGDEV_TARGET(me->lun); + mly_name_device(sc, bus, target); + mly_printf(sc, "logical device %d (%s) %s\n", me->lun, sc->mly_btl[bus][target].mb_name, tp); + if (action == 'r') + sc->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN; + break; + break; + case 's': /* report of sense data */ + if (((ssd->flags & SSD_KEY) == SSD_KEY_NO_SENSE) || + (((ssd->flags & SSD_KEY) == SSD_KEY_NOT_READY) && + (ssd->add_sense_code == 0x04) && + ((ssd->add_sense_code_qual == 0x01) || (ssd->add_sense_code_qual == 0x02)))) + break; /* ignore NO_SENSE or NOT_READY in one case */ + + mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); + mly_printf(sc, " sense key %d asc %02x ascq %02x\n", + ssd->flags & SSD_KEY, ssd->add_sense_code, ssd->add_sense_code_qual); + mly_printf(sc, " info %4D csi %4D\n", ssd->info, "", ssd->cmd_spec_info, ""); + if (action == 'r') + sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; + break; + case 'e': + mly_printf(sc, tp, me->target, me->lun); + break; + case 'c': + mly_printf(sc, "controller %s\n", tp); + break; + case '?': + mly_printf(sc, "%s - %d\n", tp, me->code); + break; + default: /* probably a 'noisy' event being ignored */ + break; + } +} + +/******************************************************************************** + * Perform periodic activities. + */ +static void +mly_periodic(void *data) +{ + struct mly_softc *sc = (struct mly_softc *)data; + int nchn, bus, target; + + debug_called(2); + + /* + * Scan devices. + */ + nchn = sc->mly_controllerinfo->physical_channels_present + + sc->mly_controllerinfo->virtual_channels_present; + for (bus = 0; bus < nchn; bus++) { + for (target = 0; target < MLY_MAX_TARGETS; target++) { + + /* ignore the controller in this scan */ + if (target == sc->mly_controllerparam->initiator_id) + continue; + + /* perform device rescan? */ + if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_RESCAN) + mly_rescan_btl(sc, bus, target); + } + } + + sc->mly_periodic = timeout(mly_periodic, sc, hz); +} + +/******************************************************************************** + ******************************************************************************** + Command Processing + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Run a command and wait for it to complete. + * + */ +static int +mly_immediate_command(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + int error, s; + + debug_called(2); + + /* spinning at splcam is ugly, but we're only used during controller init */ + s = splcam(); + if ((error = mly_start(mc))) + return(error); + + if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) { + /* sleep on the command */ + while(MLY_CMD_STATE(mc) != MLY_CMD_COMPLETE) { + tsleep(mc, PRIBIO, "mlywait", 0); + } + } else { + /* spin and collect status while we do */ + while(MLY_CMD_STATE(mc) != MLY_CMD_COMPLETE) + mly_done(mc->mc_sc); + } + splx(s); + return(0); +} + +/******************************************************************************** + * Start as much queued I/O as possible on the controller + */ +void +mly_startio(struct mly_softc *sc) +{ + struct mly_command *mc; + + debug_called(2); + + for (;;) { + + /* try for a ready command */ + mc = mly_dequeue_ready(sc); + + /* try to build a command from a queued ccb */ + if (!mc) + mly_cam_command(sc, &mc); + + /* no command == nothing to do */ + if (!mc) + break; + + /* try to post the command */ + if (mly_start(mc)) { + /* controller busy, or no resources - defer for later */ + mly_requeue_ready(mc); + break; + } + } +} + +/******************************************************************************** + * Deliver a command to the controller; allocate controller resources at the + * last moment. + */ +static int +mly_start(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + union mly_command_packet *pkt; + int s; + + debug_called(2); + + /* + * Set the command up for delivery to the controller. This may fail + * due to resource shortages. + */ + if (mly_get_slot(mc)) + return(EBUSY); + mly_map_command(mc); + + s = splcam(); + /* + * Do we have to use the hardware mailbox? + */ + if (!(sc->mly_state & MLY_STATE_MMBOX_ACTIVE)) { + /* + * Check to see if the controller is ready for us. + */ + if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) { + splx(s); + return(EBUSY); + } + + /* + * It's ready, send the command. + */ + MLY_SET_MBOX(sc, sc->mly_command_mailbox, &mc->mc_packetphys); + MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_CMDSENT); + + } else { /* use memory-mailbox mode */ + + pkt = &sc->mly_mmbox->mmm_command[sc->mly_mmbox_command_index]; + + /* check to see if the next slot is free yet */ + if (pkt->mmbox.flag != 0) { + splx(s); + return(EBUSY); + } + + /* copy in new command */ + bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data)); + /* barrier to ensure completion of previous write before we write the flag */ + bus_space_barrier(NULL, NULL, 0, 0, BUS_SPACE_BARRIER_WRITE); /* tag/handle? */ + /* copy flag last */ + pkt->mmbox.flag = mc->mc_packet->mmbox.flag; + /* barrier to ensure completion of previous write before we notify the controller */ + bus_space_barrier(NULL, NULL, 0, 0, BUS_SPACE_BARRIER_WRITE); /* tag/handle */ + + /* signal controller, update index */ + MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT); + sc->mly_mmbox_command_index = (sc->mly_mmbox_command_index + 1) % MLY_MMBOX_COMMANDS; + } + + splx(s); + return(0); +} + +/******************************************************************************** + * Pick up command status from the controller, schedule a completion event + */ +void +mly_done(struct mly_softc *sc) +{ + struct mly_command *mc; + union mly_status_packet *sp; + u_int16_t slot; + int s, worked; + + s = splcam(); + worked = 0; + + /* pick up hardware-mailbox commands */ + if (MLY_ODBR_TRUE(sc, MLY_HM_STSREADY)) { + slot = MLY_GET_REG2(sc, sc->mly_status_mailbox); + if (slot < MLY_SLOT_MAX) { + mc = sc->mly_busycmds[slot]; + if (mc != NULL) { + mc->mc_status = MLY_GET_REG(sc, sc->mly_status_mailbox + 2); + mc->mc_sense = MLY_GET_REG(sc, sc->mly_status_mailbox + 3); + mc->mc_resid = MLY_GET_REG4(sc, sc->mly_status_mailbox + 4); + mly_enqueue_completed(mc); + sc->mly_busycmds[slot] = NULL; + worked = 1; + } else { + mly_printf(sc, "got HM completion for nonbusy slot %u\n", slot); + } + } else { + /* slot 0xffff may mean "extremely bogus command" */ + mly_printf(sc, "got HM completion for illegal slot %u\n", slot); + } + /* unconditionally acknowledge status */ + MLY_SET_REG(sc, sc->mly_odbr, MLY_HM_STSREADY); + MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); + } + + /* pick up memory-mailbox commands */ + if (MLY_ODBR_TRUE(sc, MLY_AM_STSREADY)) { + for (;;) { + sp = &sc->mly_mmbox->mmm_status[sc->mly_mmbox_status_index]; + + /* check for more status */ + if (sp->mmbox.flag == 0) + break; + + /* get slot number */ + slot = sp->status.command_id; + if (slot < MLY_SLOT_MAX) { + mc = sc->mly_busycmds[slot]; + if (mc != NULL) { + mc->mc_status = sp->status.status; + mc->mc_sense = sp->status.sense_length; + mc->mc_resid = sp->status.residue; + mly_enqueue_completed(mc); + sc->mly_busycmds[slot] = NULL; + worked = 1; + } else { + mly_printf(sc, "got AM completion for nonbusy slot %u\n", slot); + } + } else { + /* slot 0xffff may mean "extremely bogus command" */ + mly_printf(sc, "got AM completion for illegal slot %u at %d\n", slot, sc->mly_mmbox_status_index); + } + + /* clear and move to next slot */ + sp->mmbox.flag = 0; + sc->mly_mmbox_status_index = (sc->mly_mmbox_status_index + 1) % MLY_MMBOX_STATUS; + } + /* acknowledge that we have collected status value(s) */ + MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY); + } + + splx(s); + if (worked) { +#if __FreeBSD_version >= 500005 + if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) + taskqueue_enqueue(taskqueue_swi, &sc->mly_task_complete); + else +#endif + mly_complete(sc, 0); + } +} + +/******************************************************************************** + * Process completed commands + */ +static void +mly_complete(void *context, int pending) +{ + struct mly_softc *sc = (struct mly_softc *)context; + struct mly_command *mc; + void (* mc_complete)(struct mly_command *mc); + + + debug_called(2); + + /* + * Spin pulling commands off the completed queue and processing them. + */ + while ((mc = mly_dequeue_completed(sc)) != NULL) { + + /* + * Free controller resources, mark command complete. + * + * Note that as soon as we mark the command complete, it may be freed + * out from under us, so we need to save the mc_complete field in + * order to later avoid dereferencing mc. (We would not expect to + * have a polling/sleeping consumer with mc_complete != NULL). + */ + mly_unmap_command(mc); + mc_complete = mc->mc_complete; + MLY_CMD_SETSTATE(mc, MLY_CMD_COMPLETE); + + /* + * Call completion handler or wake up sleeping consumer. + */ + if (mc_complete != NULL) { + mc_complete(mc); + } else { + wakeup(mc); + } + } + + /* + * We may have freed up controller resources which would allow us + * to push more commands onto the controller, so we check here. + */ + mly_startio(sc); + + /* + * The controller may have updated the health status information, + * so check for it here. + * + * Note that we only check for health status after a completed command. It + * might be wise to ping the controller occasionally if it's been idle for + * a while just to check up on it. While a filesystem is mounted, or I/O is + * active this isn't really an issue. + */ + if (sc->mly_mmbox->mmm_health.status.change_counter != sc->mly_event_change) { + sc->mly_event_change = sc->mly_mmbox->mmm_health.status.change_counter; + debug(1, "event change %d, event status update, %d -> %d", sc->mly_event_change, + sc->mly_event_waiting, sc->mly_mmbox->mmm_health.status.next_event); + sc->mly_event_waiting = sc->mly_mmbox->mmm_health.status.next_event; + } + if (sc->mly_event_counter != sc->mly_event_waiting) + mly_fetch_event(sc); +} + +/******************************************************************************** + ******************************************************************************** + Command Buffer Management + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Give a command a slot in our lookup table, so that we can recover it when + * the controller returns the slot number. + * + * Slots are freed in mly_done(). + */ +static int +mly_get_slot(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + u_int16_t slot; + int tries; + + debug_called(3); + + if (mc->mc_flags & MLY_CMD_SLOTTED) + return(0); + + /* + * Optimisation for the controller-busy case - check to see whether + * we are already over the limit and stop immediately. + */ + if (sc->mly_busy_count >= sc->mly_max_commands) + return(EBUSY); + + /* + * Scan forward from the last slot that we assigned looking for a free + * slot. Don't scan more than the maximum number of commands that we + * support (we should never reach the limit here due to the optimisation + * above) + */ + slot = sc->mly_last_slot; + for (tries = sc->mly_max_commands; tries > 0; tries--) { + if (sc->mly_busycmds[slot] == NULL) { + sc->mly_busycmds[slot] = mc; + mc->mc_slot = slot; + mc->mc_packet->generic.command_id = slot; + mc->mc_flags |= MLY_CMD_SLOTTED; + sc->mly_last_slot = slot; + return(0); + } + slot++; + if (slot >= MLY_SLOT_MAX) + slot = MLY_SLOT_START; + } + return(EBUSY); +} + +/******************************************************************************** + * Allocate a command. + */ +int +mly_alloc_command(struct mly_softc *sc, struct mly_command **mcp) +{ + struct mly_command *mc; + + debug_called(3); + + if ((mc = mly_dequeue_free(sc)) == NULL) { + mly_alloc_command_cluster(sc); + mc = mly_dequeue_free(sc); + } + if (mc != NULL) + TAILQ_REMOVE(&sc->mly_freecmds, mc, mc_link); + + if (mc == NULL) + return(ENOMEM); + + MLY_CMD_SETSTATE(mc, MLY_CMD_SETUP); + *mcp = mc; + return(0); +} + +/******************************************************************************** + * Release a command back to the freelist. + */ +void +mly_release_command(struct mly_command *mc) +{ + debug_called(3); + + /* + * Fill in parts of the command that may cause confusion if + * a consumer doesn't when we are later allocated. + */ + MLY_CMD_SETSTATE(mc, MLY_CMD_FREE); + mc->mc_data = NULL; + mc->mc_flags = 0; + mc->mc_complete = NULL; + mc->mc_private = NULL; + + /* + * By default, we set up to overwrite the command packet with + * sense information. + */ + mc->mc_packet->generic.sense_buffer_address = mc->mc_packetphys; + mc->mc_packet->generic.maximum_sense_size = sizeof(union mly_command_packet); + + mly_enqueue_free(mc); +} + +/******************************************************************************** + * Map helper for command cluster allocation. + * + * Note that there are never more command packets in a cluster than will fit in + * a page, so there is no need to look at anything other than the base of the + * allocation (which will be page-aligned). + */ +static void +mly_alloc_command_cluster_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct mly_command_cluster *mcc = (struct mly_command_cluster *)arg; + + debug_called(2); + + mcc->mcc_packetphys = segs[0].ds_addr; +} + +/******************************************************************************** + * Allocate and initialise a cluster of commands. + */ +static void +mly_alloc_command_cluster(struct mly_softc *sc) +{ + struct mly_command_cluster *mcc; + struct mly_command *mc; + int i; + + debug_called(1); + + mcc = malloc(sizeof(struct mly_command_cluster), M_DEVBUF, M_NOWAIT); + if (mcc != NULL) { + + /* + * Allocate enough space for all the command packets for this cluster and + * map them permanently into controller-visible space. + */ + if (bus_dmamem_alloc(sc->mly_packet_dmat, (void **)&mcc->mcc_packet, + BUS_DMA_NOWAIT, &mcc->mcc_packetmap)) { + free(mcc, M_DEVBUF); + return; + } + bus_dmamap_load(sc->mly_packet_dmat, mcc->mcc_packetmap, mcc->mcc_packet, + MLY_CMD_CLUSTERCOUNT * sizeof(union mly_command_packet), + mly_alloc_command_cluster_map, mcc, 0); + + mly_enqueue_cluster(sc, mcc); + for (i = 0; i < MLY_CMD_CLUSTERCOUNT; i++) { + mc = &mcc->mcc_command[i]; + bzero(mc, sizeof(*mc)); + mc->mc_sc = sc; + mc->mc_packet = mcc->mcc_packet + i; + mc->mc_packetphys = mcc->mcc_packetphys + (i * sizeof(union mly_command_packet)); + if (!bus_dmamap_create(sc->mly_buffer_dmat, 0, &mc->mc_datamap)) + mly_release_command(mc); + } + } +} + +/******************************************************************************** + * Command-mapping helper function - populate this command slot's s/g table + * with the s/g entries for this command. + */ +static void +mly_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct mly_command *mc = (struct mly_command *)arg; + struct mly_softc *sc = mc->mc_sc; + struct mly_command_generic *gen = &(mc->mc_packet->generic); + struct mly_sg_entry *sg; + int i, tabofs; + + debug_called(3); + + /* can we use the transfer structure directly? */ + if (nseg <= 2) { + sg = &gen->transfer.direct.sg[0]; + gen->command_control.extended_sg_table = 0; + } else { + tabofs = (mc->mc_slot * MLY_MAXSGENTRIES); + sg = sc->mly_sg_table + tabofs; + gen->transfer.indirect.entries[0] = nseg; + gen->transfer.indirect.table_physaddr[0] = sc->mly_sg_busaddr + (tabofs * sizeof(struct mly_sg_entry)); + gen->command_control.extended_sg_table = 1; + } + + /* copy the s/g table */ + for (i = 0; i < nseg; i++) { + sg[i].physaddr = segs[i].ds_addr; + sg[i].length = segs[i].ds_len; + } + +} + +#if 0 +/******************************************************************************** + * Command-mapping helper function - save the cdb's physical address. + * + * We don't support 'large' SCSI commands at this time, so this is unused. + */ +static void +mly_map_command_cdb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct mly_command *mc = (struct mly_command *)arg; + + debug_called(3); + + /* XXX can we safely assume that a CDB will never cross a page boundary? */ + if ((segs[0].ds_addr % PAGE_SIZE) > + ((segs[0].ds_addr + mc->mc_packet->scsi_large.cdb_length) % PAGE_SIZE)) + panic("cdb crosses page boundary"); + + /* fix up fields in the command packet */ + mc->mc_packet->scsi_large.cdb_physaddr = segs[0].ds_addr; +} +#endif + +/******************************************************************************** + * Map a command into controller-visible space + */ +static void +mly_map_command(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + + debug_called(2); + + /* don't map more than once */ + if (mc->mc_flags & MLY_CMD_MAPPED) + return; + + /* does the command have a data buffer? */ + if (mc->mc_data != NULL) + bus_dmamap_load(sc->mly_buffer_dmat, mc->mc_datamap, mc->mc_data, mc->mc_length, + mly_map_command_sg, mc, 0); + + if (mc->mc_flags & MLY_CMD_DATAIN) + bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREREAD); + if (mc->mc_flags & MLY_CMD_DATAOUT) + bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREWRITE); + + mc->mc_flags |= MLY_CMD_MAPPED; +} + +/******************************************************************************** + * Unmap a command from controller-visible space + */ +static void +mly_unmap_command(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + + debug_called(2); + + if (!(mc->mc_flags & MLY_CMD_MAPPED)) + return; + + if (mc->mc_flags & MLY_CMD_DATAIN) + bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTREAD); + if (mc->mc_flags & MLY_CMD_DATAOUT) + bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTWRITE); + + /* does the command have a data buffer? */ + if (mc->mc_data != NULL) + bus_dmamap_unload(sc->mly_buffer_dmat, mc->mc_datamap); + + mc->mc_flags &= ~MLY_CMD_MAPPED; +} + +/******************************************************************************** + ******************************************************************************** + Hardware Control + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Handshake with the firmware while the card is being initialised. + */ +static int +mly_fwhandshake(struct mly_softc *sc) +{ + u_int8_t error, param0, param1; + int spinup = 0; + + debug_called(1); + + /* set HM_STSACK and let the firmware initialise */ + MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); + DELAY(1000); /* too short? */ + + /* if HM_STSACK is still true, the controller is initialising */ + if (!MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) + return(0); + mly_printf(sc, "controller initialisation started\n"); + + /* spin waiting for initialisation to finish, or for a message to be delivered */ + while (MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) { + /* check for a message */ + if (MLY_ERROR_VALID(sc)) { + error = MLY_GET_REG(sc, sc->mly_error_status) & ~MLY_MSG_EMPTY; + param0 = MLY_GET_REG(sc, sc->mly_command_mailbox); + param1 = MLY_GET_REG(sc, sc->mly_command_mailbox + 1); + + switch(error) { + case MLY_MSG_SPINUP: + if (!spinup) { + mly_printf(sc, "drive spinup in progress\n"); + spinup = 1; /* only print this once (should print drive being spun?) */ + } + break; + case MLY_MSG_RACE_RECOVERY_FAIL: + mly_printf(sc, "mirror race recovery failed, one or more drives offline\n"); + break; + case MLY_MSG_RACE_IN_PROGRESS: + mly_printf(sc, "mirror race recovery in progress\n"); + break; + case MLY_MSG_RACE_ON_CRITICAL: + mly_printf(sc, "mirror race recovery on a critical drive\n"); + break; + case MLY_MSG_PARITY_ERROR: + mly_printf(sc, "FATAL MEMORY PARITY ERROR\n"); + return(ENXIO); + default: + mly_printf(sc, "unknown initialisation code 0x%x\n", error); + } + } + } + return(0); +} + +/******************************************************************************** + ******************************************************************************** + Debugging and Diagnostics + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Print some information about the controller. + */ +static void +mly_describe_controller(struct mly_softc *sc) +{ + struct mly_ioctl_getcontrollerinfo *mi = sc->mly_controllerinfo; + + mly_printf(sc, "%16s, %d channel%s, firmware %d.%02d-%d-%02d (%02d%02d%02d%02d), %dMB RAM\n", + mi->controller_name, mi->physical_channels_present, (mi->physical_channels_present) > 1 ? "s" : "", + mi->fw_major, mi->fw_minor, mi->fw_turn, mi->fw_build, /* XXX turn encoding? */ + mi->fw_century, mi->fw_year, mi->fw_month, mi->fw_day, + mi->memory_size); + + if (bootverbose) { + mly_printf(sc, "%s %s (%x), %dMHz %d-bit %.16s\n", + mly_describe_code(mly_table_oemname, mi->oem_information), + mly_describe_code(mly_table_controllertype, mi->controller_type), mi->controller_type, + mi->interface_speed, mi->interface_width, mi->interface_name); + mly_printf(sc, "%dMB %dMHz %d-bit %s%s%s, cache %dMB\n", + mi->memory_size, mi->memory_speed, mi->memory_width, + mly_describe_code(mly_table_memorytype, mi->memory_type), + mi->memory_parity ? "+parity": "",mi->memory_ecc ? "+ECC": "", + mi->cache_size); + mly_printf(sc, "CPU: %s @ %dMHZ\n", + mly_describe_code(mly_table_cputype, mi->cpu[0].type), mi->cpu[0].speed); + if (mi->l2cache_size != 0) + mly_printf(sc, "%dKB L2 cache\n", mi->l2cache_size); + if (mi->exmemory_size != 0) + mly_printf(sc, "%dMB %dMHz %d-bit private %s%s%s\n", + mi->exmemory_size, mi->exmemory_speed, mi->exmemory_width, + mly_describe_code(mly_table_memorytype, mi->exmemory_type), + mi->exmemory_parity ? "+parity": "",mi->exmemory_ecc ? "+ECC": ""); + mly_printf(sc, "battery backup %s\n", mi->bbu_present ? "present" : "not installed"); + mly_printf(sc, "maximum data transfer %d blocks, maximum sg entries/command %d\n", + mi->maximum_block_count, mi->maximum_sg_entries); + mly_printf(sc, "logical devices present/critical/offline %d/%d/%d\n", + mi->logical_devices_present, mi->logical_devices_critical, mi->logical_devices_offline); + mly_printf(sc, "physical devices present %d\n", + mi->physical_devices_present); + mly_printf(sc, "physical disks present/offline %d/%d\n", + mi->physical_disks_present, mi->physical_disks_offline); + mly_printf(sc, "%d physical channel%s, %d virtual channel%s of %d possible\n", + mi->physical_channels_present, mi->physical_channels_present == 1 ? "" : "s", + mi->virtual_channels_present, mi->virtual_channels_present == 1 ? "" : "s", + mi->virtual_channels_possible); + mly_printf(sc, "%d parallel commands supported\n", mi->maximum_parallel_commands); + mly_printf(sc, "%dMB flash ROM, %d of %d maximum cycles\n", + mi->flash_size, mi->flash_age, mi->flash_maximum_age); + } +} + +#ifdef MLY_DEBUG +/******************************************************************************** + * Print some controller state + */ +static void +mly_printstate(struct mly_softc *sc) +{ + mly_printf(sc, "IDBR %02x ODBR %02x ERROR %02x (%x %x %x)\n", + MLY_GET_REG(sc, sc->mly_idbr), + MLY_GET_REG(sc, sc->mly_odbr), + MLY_GET_REG(sc, sc->mly_error_status), + sc->mly_idbr, + sc->mly_odbr, + sc->mly_error_status); + mly_printf(sc, "IMASK %02x ISTATUS %02x\n", + MLY_GET_REG(sc, sc->mly_interrupt_mask), + MLY_GET_REG(sc, sc->mly_interrupt_status)); + mly_printf(sc, "COMMAND %02x %02x %02x %02x %02x %02x %02x %02x\n", + MLY_GET_REG(sc, sc->mly_command_mailbox), + MLY_GET_REG(sc, sc->mly_command_mailbox + 1), + MLY_GET_REG(sc, sc->mly_command_mailbox + 2), + MLY_GET_REG(sc, sc->mly_command_mailbox + 3), + MLY_GET_REG(sc, sc->mly_command_mailbox + 4), + MLY_GET_REG(sc, sc->mly_command_mailbox + 5), + MLY_GET_REG(sc, sc->mly_command_mailbox + 6), + MLY_GET_REG(sc, sc->mly_command_mailbox + 7)); + mly_printf(sc, "STATUS %02x %02x %02x %02x %02x %02x %02x %02x\n", + MLY_GET_REG(sc, sc->mly_status_mailbox), + MLY_GET_REG(sc, sc->mly_status_mailbox + 1), + MLY_GET_REG(sc, sc->mly_status_mailbox + 2), + MLY_GET_REG(sc, sc->mly_status_mailbox + 3), + MLY_GET_REG(sc, sc->mly_status_mailbox + 4), + MLY_GET_REG(sc, sc->mly_status_mailbox + 5), + MLY_GET_REG(sc, sc->mly_status_mailbox + 6), + MLY_GET_REG(sc, sc->mly_status_mailbox + 7)); + mly_printf(sc, " %04x %08x\n", + MLY_GET_REG2(sc, sc->mly_status_mailbox), + MLY_GET_REG4(sc, sc->mly_status_mailbox + 4)); +} + +struct mly_softc *mly_softc0 = NULL; +void +mly_printstate0(void) +{ + if (mly_softc0 != NULL) + mly_printstate(mly_softc0); +} + +/******************************************************************************** + * Print a command + */ +static void +mly_print_command(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + + mly_printf(sc, "COMMAND @ %p\n", mc); + mly_printf(sc, " slot %d\n", mc->mc_slot); + mly_printf(sc, " state %d\n", MLY_CMD_STATE(mc)); + mly_printf(sc, " status 0x%x\n", mc->mc_status); + mly_printf(sc, " sense len %d\n", mc->mc_sense); + mly_printf(sc, " resid %d\n", mc->mc_resid); + mly_printf(sc, " packet %p/0x%llx\n", mc->mc_packet, mc->mc_packetphys); + if (mc->mc_packet != NULL) + mly_print_packet(mc); + mly_printf(sc, " data %p/%d\n", mc->mc_data, mc->mc_length); + mly_printf(sc, " flags %b\n", mc->mc_flags, "\20\11slotted\12mapped\13priority\14datain\15dataout\n"); + mly_printf(sc, " complete %p\n", mc->mc_complete); + mly_printf(sc, " private %p\n", mc->mc_private); +} + +/******************************************************************************** + * Print a command packet + */ +static void +mly_print_packet(struct mly_command *mc) +{ + struct mly_softc *sc = mc->mc_sc; + struct mly_command_generic *ge = (struct mly_command_generic *)mc->mc_packet; + struct mly_command_scsi_small *ss = (struct mly_command_scsi_small *)mc->mc_packet; + struct mly_command_scsi_large *sl = (struct mly_command_scsi_large *)mc->mc_packet; + struct mly_command_ioctl *io = (struct mly_command_ioctl *)mc->mc_packet; + int transfer; + + mly_printf(sc, " command_id %d\n", ge->command_id); + mly_printf(sc, " opcode %d\n", ge->opcode); + mly_printf(sc, " command_control fua %d dpo %d est %d dd %s nas %d ddis %d\n", + ge->command_control.force_unit_access, + ge->command_control.disable_page_out, + ge->command_control.extended_sg_table, + (ge->command_control.data_direction == MLY_CCB_WRITE) ? "WRITE" : "READ", + ge->command_control.no_auto_sense, + ge->command_control.disable_disconnect); + mly_printf(sc, " data_size %d\n", ge->data_size); + mly_printf(sc, " sense_buffer_address 0x%llx\n", ge->sense_buffer_address); + mly_printf(sc, " lun %d\n", ge->addr.phys.lun); + mly_printf(sc, " target %d\n", ge->addr.phys.target); + mly_printf(sc, " channel %d\n", ge->addr.phys.channel); + mly_printf(sc, " logical device %d\n", ge->addr.log.logdev); + mly_printf(sc, " controller %d\n", ge->addr.phys.controller); + mly_printf(sc, " timeout %d %s\n", + ge->timeout.value, + (ge->timeout.scale == MLY_TIMEOUT_SECONDS) ? "seconds" : + ((ge->timeout.scale == MLY_TIMEOUT_MINUTES) ? "minutes" : "hours")); + mly_printf(sc, " maximum_sense_size %d\n", ge->maximum_sense_size); + switch(ge->opcode) { + case MDACMD_SCSIPT: + case MDACMD_SCSI: + mly_printf(sc, " cdb length %d\n", ss->cdb_length); + mly_printf(sc, " cdb %*D\n", ss->cdb_length, ss->cdb, " "); + transfer = 1; + break; + case MDACMD_SCSILC: + case MDACMD_SCSILCPT: + mly_printf(sc, " cdb length %d\n", sl->cdb_length); + mly_printf(sc, " cdb 0x%llx\n", sl->cdb_physaddr); + transfer = 1; + break; + case MDACMD_IOCTL: + mly_printf(sc, " sub_ioctl 0x%x\n", io->sub_ioctl); + switch(io->sub_ioctl) { + case MDACIOCTL_SETMEMORYMAILBOX: + mly_printf(sc, " health_buffer_size %d\n", + io->param.setmemorymailbox.health_buffer_size); + mly_printf(sc, " health_buffer_phys 0x%llx\n", + io->param.setmemorymailbox.health_buffer_physaddr); + mly_printf(sc, " command_mailbox 0x%llx\n", + io->param.setmemorymailbox.command_mailbox_physaddr); + mly_printf(sc, " status_mailbox 0x%llx\n", + io->param.setmemorymailbox.status_mailbox_physaddr); + transfer = 0; + break; + + case MDACIOCTL_SETREALTIMECLOCK: + case MDACIOCTL_GETHEALTHSTATUS: + case MDACIOCTL_GETCONTROLLERINFO: + case MDACIOCTL_GETLOGDEVINFOVALID: + case MDACIOCTL_GETPHYSDEVINFOVALID: + case MDACIOCTL_GETPHYSDEVSTATISTICS: + case MDACIOCTL_GETLOGDEVSTATISTICS: + case MDACIOCTL_GETCONTROLLERSTATISTICS: + case MDACIOCTL_GETBDT_FOR_SYSDRIVE: + case MDACIOCTL_CREATENEWCONF: + case MDACIOCTL_ADDNEWCONF: + case MDACIOCTL_GETDEVCONFINFO: + case MDACIOCTL_GETFREESPACELIST: + case MDACIOCTL_MORE: + case MDACIOCTL_SETPHYSDEVPARAMETER: + case MDACIOCTL_GETPHYSDEVPARAMETER: + case MDACIOCTL_GETLOGDEVPARAMETER: + case MDACIOCTL_SETLOGDEVPARAMETER: + mly_printf(sc, " param %10D\n", io->param.data.param, " "); + transfer = 1; + break; + + case MDACIOCTL_GETEVENT: + mly_printf(sc, " event %d\n", + io->param.getevent.sequence_number_low + ((u_int32_t)io->addr.log.logdev << 16)); + transfer = 1; + break; + + case MDACIOCTL_SETRAIDDEVSTATE: + mly_printf(sc, " state %d\n", io->param.setraiddevstate.state); + transfer = 0; + break; + + case MDACIOCTL_XLATEPHYSDEVTORAIDDEV: + mly_printf(sc, " raid_device %d\n", io->param.xlatephysdevtoraiddev.raid_device); + mly_printf(sc, " controller %d\n", io->param.xlatephysdevtoraiddev.controller); + mly_printf(sc, " channel %d\n", io->param.xlatephysdevtoraiddev.channel); + mly_printf(sc, " target %d\n", io->param.xlatephysdevtoraiddev.target); + mly_printf(sc, " lun %d\n", io->param.xlatephysdevtoraiddev.lun); + transfer = 0; + break; + + case MDACIOCTL_GETGROUPCONFINFO: + mly_printf(sc, " group %d\n", io->param.getgroupconfinfo.group); + transfer = 1; + break; + + case MDACIOCTL_GET_SUBSYSTEM_DATA: + case MDACIOCTL_SET_SUBSYSTEM_DATA: + case MDACIOCTL_STARTDISOCVERY: + case MDACIOCTL_INITPHYSDEVSTART: + case MDACIOCTL_INITPHYSDEVSTOP: + case MDACIOCTL_INITRAIDDEVSTART: + case MDACIOCTL_INITRAIDDEVSTOP: + case MDACIOCTL_REBUILDRAIDDEVSTART: + case MDACIOCTL_REBUILDRAIDDEVSTOP: + case MDACIOCTL_MAKECONSISTENTDATASTART: + case MDACIOCTL_MAKECONSISTENTDATASTOP: + case MDACIOCTL_CONSISTENCYCHECKSTART: + case MDACIOCTL_CONSISTENCYCHECKSTOP: + case MDACIOCTL_RESETDEVICE: + case MDACIOCTL_FLUSHDEVICEDATA: + case MDACIOCTL_PAUSEDEVICE: + case MDACIOCTL_UNPAUSEDEVICE: + case MDACIOCTL_LOCATEDEVICE: + case MDACIOCTL_SETMASTERSLAVEMODE: + case MDACIOCTL_DELETERAIDDEV: + case MDACIOCTL_REPLACEINTERNALDEV: + case MDACIOCTL_CLEARCONF: + case MDACIOCTL_GETCONTROLLERPARAMETER: + case MDACIOCTL_SETCONTRLLERPARAMETER: + case MDACIOCTL_CLEARCONFSUSPMODE: + case MDACIOCTL_STOREIMAGE: + case MDACIOCTL_READIMAGE: + case MDACIOCTL_FLASHIMAGES: + case MDACIOCTL_RENAMERAIDDEV: + default: /* no idea what to print */ + transfer = 0; + break; + } + break; + + case MDACMD_IOCTLCHECK: + case MDACMD_MEMCOPY: + default: + transfer = 0; + break; /* print nothing */ + } + if (transfer) { + if (ge->command_control.extended_sg_table) { + mly_printf(sc, " sg table 0x%llx/%d\n", + ge->transfer.indirect.table_physaddr[0], ge->transfer.indirect.entries[0]); + } else { + mly_printf(sc, " 0000 0x%llx/%lld\n", + ge->transfer.direct.sg[0].physaddr, ge->transfer.direct.sg[0].length); + mly_printf(sc, " 0001 0x%llx/%lld\n", + ge->transfer.direct.sg[1].physaddr, ge->transfer.direct.sg[1].length); + } + } +} + +/******************************************************************************** + * Panic in a slightly informative fashion + */ +static void +mly_panic(struct mly_softc *sc, char *reason) +{ + mly_printstate(sc); + panic(reason); +} +#endif Property changes on: stable/4/sys/dev/mly/mly.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ncv/ncr53c500.c =================================================================== --- stable/4/sys/dev/ncv/ncr53c500.c (nonexistent) +++ stable/4/sys/dev/ncv/ncr53c500.c (revision 67524) @@ -0,0 +1,1197 @@ +/* $FreeBSD$ */ +/* $NecBSD: ncr53c500.c,v 1.30 1999/07/23 21:00:04 honda Exp $ */ +/* $NetBSD$ */ + +#define NCV_DEBUG +#define NCV_STATICS + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * 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 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#if __FreeBSD_version < 400001 +#include "ncv.h" +struct ncv_softc *ncvdata[NNCV]; +#endif +#endif /* __FreeBSD__ */ + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (ncr53c500.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("ncv") +#endif /* __FreeBSD__ */ +#endif + +#ifdef NCV_DEBUG +int ncv_debug; +#endif /* NCV_DEBUG */ + +#ifdef NCV_STATICS +struct ncv_statics { + int disconnect; + int reselect; +} ncv_statics[NCV_NTARGETS]; +#endif /* NCV_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver ncv_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void ncv_pio_read __P((struct ncv_softc *, u_int8_t *, u_int)); +static void ncv_pio_write __P((struct ncv_softc *, u_int8_t *, u_int)); +static int ncv_msg __P((struct ncv_softc *, struct targ_info *, u_int)); +static __inline int ncv_reselected __P((struct ncv_softc *)); +static __inline int ncv_disconnected __P((struct ncv_softc *, struct targ_info *)); +static __inline void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *)); + +static __inline void ncvhw_set_count __P((bus_space_tag_t, bus_space_handle_t, int)); +static __inline u_int ncvhw_get_count __P((bus_space_tag_t, bus_space_handle_t)); +static __inline void ncvhw_select_register_0 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static __inline void ncvhw_select_register_1 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static __inline void ncvhw_fpush __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int)); + +static int ncv_world_start __P((struct ncv_softc *, int)); +static void ncvhw_bus_reset __P((struct ncv_softc *)); +static void ncvhw_reset __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static int ncvhw_check __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static void ncvhw_init __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static int ncvhw_start_selection __P((struct ncv_softc *sc, struct slccb *)); +static void ncvhw_attention __P((struct ncv_softc *)); +static int ncv_nexus __P((struct ncv_softc *, struct targ_info *)); +#ifdef NCV_POWER_CONTROL +static int ncvhw_power __P((struct ncv_softc *, u_int)); +#endif +static int ncv_lun_init __P((struct ncv_softc *, struct targ_info *, struct lun_info *)); +static void settimeout __P((void *)); + +struct scsi_low_funcs ncv_funcs = { + SC_LOW_INIT_T ncv_world_start, + SC_LOW_BUSRST_T ncvhw_bus_reset, + SC_LOW_LUN_INIT_T ncv_lun_init, + + SC_LOW_SELECT_T ncvhw_start_selection, + SC_LOW_NEXUS_T ncv_nexus, + + SC_LOW_ATTEN_T ncvhw_attention, + SC_LOW_MSG_T ncv_msg, + + 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; +{ + + bus_space_write_1(iot, ioh, cr0_cfg4, 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; +{ + + bus_space_write_1(iot, ioh, cr1_cfg5, 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; +{ + int ptr; + + for (ptr = 0; ptr < len; ptr ++) + bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]); +} + +static int +ncvhw_check(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + 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)) + { +#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) + { +#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); + + /* 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); + delay(100 * 1000); + + /* check response */ + bus_space_read_1(iot, ioh, cr0_stat); + stat = bus_space_read_1(iot, ioh, cr0_istat); + delay(1000); + + if (((stat & INTR_SBR) == 0) || + (bus_space_read_1(iot, ioh, 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_select_register_0(iot, ioh, hw); + + /* dummy cmd twice */ + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + + /* chip reset */ + bus_space_write_1(iot, ioh, 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); +} + +static void +ncvhw_init(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + + ncvhw_select_register_0(iot, ioh, hw); + bus_space_write_1(iot, ioh, cr0_clk, 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); + + bus_space_write_1(iot, ioh, cr0_cfg1, hw->cfg1); + bus_space_write_1(iot, ioh, cr0_cfg2, hw->cfg2); + bus_space_write_1(iot, ioh, cr0_cfg3, hw->cfg3); + bus_space_write_1(iot, ioh, 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_0(iot, ioh, 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; + + if (flags == SCSI_LOW_POWDOWN) + { + printf("%s power down\n", slp->sl_xname); + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN); + } + else + { + switch (sc->sc_rstep) + { + case 0: + printf("%s resume step O\n", slp->sl_xname); + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); + break; + + case 1: + printf("%s resume step I\n", slp->sl_xname); + ncvhw_reset(iot, ioh, &sc->sc_hw); + ncvhw_init(iot, ioh, &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); + 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); +} + +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 targ_info *ti = cb->ti; + int s; + u_int8_t msg; + + msg = ID_MSG_SETUP(ti); + sc->sc_compseq = 0; + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + + s = splhigh(); + + if (slp->sl_disc > 0 && + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat) & STAT_INT)) + { + splx(s); + 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); + bus_space_write_1(iot, ioh, cr0_sfifo, msg); + + if (scsi_low_is_msgout_continue(ti) != 0) + { + bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATNS); + sc->sc_selstop = 1; + } + else + { + /* XXX: + * emulate nexus call because ncv bypasses CMD phase. + */ + scsi_low_cmd(slp, ti); + ncvhw_fpush(iot, ioh, + slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATN); + sc->sc_selstop = 0; + } + splx(s); + + SCSI_LOW_TARGET_ASSERT_ATN(ti); + 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; + u_int8_t stat; + intrmask_t s; + + ncvhw_reset(iot, ioh, &sc->sc_hw); + ncvhw_init(iot, ioh, &sc->sc_hw); + + s = splcam(); + scsi_low_bus_reset((struct scsi_low_softc *) sc); + + 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); + splx(s); + delay(1000); + + if (((stat & INTR_SBR) == 0) || + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR)) + return ENODEV; + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +static int +ncv_msg(sc, ti, msg) + struct ncv_softc *sc; + struct targ_info *ti; + u_int msg; +{ + struct lun_info *li = ti->ti_li; + struct ncv_lun_info *nli = (void *) li; + u_int hwcycle, period; + + if ((msg & SCSI_LOW_MSG_SYNCH) == 0) + return 0; + + period = li->li_maxsynch.period; + hwcycle = 1000 / ((sc->sc_hw.clk == 0) ? 40 : (5 * sc->sc_hw.clk)); + + if (period < 200 / 4 && period >= 100 / 4) + nli->nli_reg_cfg3 |= C3_FSCSI; + else + nli->nli_reg_cfg3 &= ~C3_FSCSI; + + period = ((period * 40 / hwcycle) + 5) / 10; + nli->nli_reg_period = period & 0x1f; + nli->nli_reg_offset = li->li_maxsynch.offset; + return 0; +} + +static int +ncv_lun_init(sc, ti, li) + struct ncv_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct ncv_lun_info *nli = (void *) li; + + li->li_maxsynch.period = sc->sc_hw.mperiod; + li->li_maxsynch.offset = sc->sc_hw.moffset; + + nli->nli_reg_cfg3 = sc->sc_hw.cfg3; + nli->nli_reg_period = 0; + nli->nli_reg_offset = 0; + return 0; +} + +/************************************************************** + * General probe attach + **************************************************************/ +static int ncv_setup_img __P((struct ncv_hw *, u_int, int)); + +static int +ncv_setup_img(hw, dvcfg, hsid) + struct ncv_hw *hw; + u_int dvcfg; + int hsid; +{ + + if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F) + { + printf("ncv: invalid dvcfg flags\n"); + return EINVAL; + } + + if (NCV_C5IMG(dvcfg) != 0) + { + hw->cfg5 = NCV_C5IMG(dvcfg); + hw->clk = NCV_CLKFACTOR(dvcfg); + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) + hw->mperiod = 100 / 4; + + /* XXX: + * RATOC scsi cards have fatal fifo asic bug. + * To avoid it, currently make sync offset 0 (async)! + */ + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG) + { + hw->mperiod = 0; + hw->moffset = 0; + } + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1) + hw->cfg2 &= ~C2_SCSI2; + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW) + hw->cfg1 |= C1_SLOW; + } + + /* setup configuration image 3 */ + if (hw->clk != CLK_40M_F && hw->clk <= CLK_25M_F) + hw->cfg3 &= ~C3_FCLK; + + /* setup configuration image 1 */ + hw->cfg1 = (hw->cfg1 & 0xf0) | hsid; + return 0; +} + +int +ncvprobesubr(iot, ioh, dvcfg, hsid) + bus_space_tag_t iot; + bus_space_handle_t ioh; + 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) + return 0; + + return 1; +} + +int +ncvprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +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; + (void) scsi_low_attach(slp, 2, NCV_NTARGETS, NCV_NLUNS, + sizeof(struct ncv_lun_info)); +} + +/************************************************************** + * PDMA + **************************************************************/ +static __inline void +ncvhw_set_count(iot, ioh, count) + bus_space_tag_t iot; + bus_space_handle_t ioh; + 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))); +} + +static __inline u_int +ncvhw_get_count(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + 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); + return count; +} + +static __inline 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; + int len; + + slp->sl_flags &= ~HW_PDMASTART; + if (ti->ti_phase == PH_DATA) + { + len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh); + if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) + len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh, + cr0_sffl) & CR0_SFFLR_BMASK); + + if ((u_int) len <= (u_int) slp->sl_scp.scp_datalen) + { + slp->sl_scp.scp_data += (slp->sl_scp.scp_datalen - len); + slp->sl_scp.scp_datalen = len; + if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) && + sc->sc_tdatalen != len) + goto bad; + } + else + { +bad: + slp->sl_error |= PDMAERR; + printf("%s stragne count hw 0x%x soft 0x%x tlen 0x%x\n", + slp->sl_xname, len, slp->sl_scp.scp_datalen, + sc->sc_tdatalen); + } + } + else + { + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } + + 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); +} + +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; + int s; + int tout = 0; + register u_int8_t fstat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_pflag, 0); + + 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_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); + slp->sl_flags |= HW_PDMASTART; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (reqlen >= FIFO_F_SZ && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_F) + { +#define NCV_FAST32_ACCESS +#ifdef NCV_FAST32_ACCESS + bus_space_read_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_F_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_read_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_F_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_F_SZ; + reqlen -= FIFO_F_SZ; + continue; + } + else if (fstat & FIFO_BRK) + break; + + } + + if (reqlen >= FIFO_2_SZ) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_2) + { +#ifdef NCV_FAST32_ACCESS + bus_space_read_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_2_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_read_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_2_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_2_SZ; + reqlen -= FIFO_2_SZ; + } + } + + while (reqlen > 0 && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if ((fstat & FIFO_E) == 0) + { + *buf++ = bus_space_read_1(iot, ioh, cr1_fdata); + reqlen --; + continue; + } + else if (fstat & FIFO_BRK) + break; + + } + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + sc->sc_tdatalen = reqlen; + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +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; + int s; + int tout = 0; + register u_int8_t fstat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_pflag, 0); + + 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_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); + slp->sl_flags |= HW_PDMASTART; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (reqlen >= FIFO_F_SZ && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_BRK) + goto done; + + if (fstat & FIFO_E) + { +#ifdef NCV_FAST32_ACCESS + bus_space_write_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_F_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_write_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_F_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_F_SZ; + reqlen -= FIFO_F_SZ; + } + } + + while (reqlen > 0 && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_BRK) + break; + + if ((fstat & FIFO_F) == 0) /* fifo not full */ + { + bus_space_write_1(iot, ioh, cr1_fdata, *buf++); + reqlen --; + } + } + +done: + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +/************************************************************** + * disconnect & reselect (HW low) + **************************************************************/ +static __inline 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 targ_info *ti; + u_int sid; + + if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2) + { + printf("%s illegal fifo bytes\n", slp->sl_xname); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused"); + return EJUSTRETURN; + } + + sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo); + sid = ffs(sid) - 1; + ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid); + if (ti == NULL) + return EJUSTRETURN; + +#ifdef NCV_STATICS + ncv_statics[sid].reselect ++; +#endif /* NCV_STATICS */ + bus_space_write_1(iot, ioh, cr0_dstid, sid); + return 0; +} + +static __inline 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; + + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL); + +#ifdef NCV_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + ncv_statics[ti->ti_id].disconnect ++; +#endif /* NCV_STATICS */ + + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static int +ncv_nexus(sc, ti) + struct ncv_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct lun_info *li = ti->ti_li; + struct ncv_lun_info *nli = (void *) li; + + if (li->li_flags & SCSI_LOW_NOPARITY) + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); + else + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1 | C1_PARENB); + bus_space_write_1(iot, ioh, cr0_period, nli->nli_reg_period); + bus_space_write_1(iot, ioh, cr0_offs, nli->nli_reg_offset); + bus_space_write_1(iot, ioh, cr0_cfg3, nli->nli_reg_cfg3); + return 0; +} + +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 targ_info *ti; + struct physio_proc *pp; + struct buf *bp; + int len, identify; + u_int8_t regv, status, ireason; + + 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); + if ((status & STAT_INT) == 0) + return 0; + + ireason = bus_space_read_1(iot, ioh, cr0_istat); + if (ireason & INTR_SBR) + { + 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); + + /* 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); + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, ireason); + if (ncv_debug > 1) + Debugger(); + } +#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_nexus) == NULL) + return 0; + + if ((status & (STAT_PE | STAT_GE)) != 0) + { + slp->sl_error |= PARITYERR; + if (ti->ti_phase == PH_MSGIN) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1); + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); + } + + 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, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + identify = 0; + + if (sc->sc_selstop == 0) + { + /* XXX: + * Here scsi phases expected are + * DATA PHASE: + * MSGIN : target wants to disconnect the host. + * STATUSIN : immediate command completed. + * MSGOUT : identify command failed. + */ + if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) + break; + identify = 1; + } + else + { + /* XXX: + * Here scsi phase should be MSGOUT. + * The driver NEVER supports devices + * which neglect ATN singal. + */ + if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) + { + slp->sl_error |= FATALIO; + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "msgout error"); + return 1; + } + + if ((ireason & INTR_FC) == 0) + identify = 1; + } + + if (identify != 0) + { + printf("%s msg identify failed\n", slp->sl_xname); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + } + break; + + case PH_RESEL: + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + break; + + default: + if (slp->sl_flags & HW_PDMASTART) + 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) + break; + + pp = physio_proc_enter(bp); + ncv_pio_write(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); + physio_proc_leave(pp); + 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) + break; + + pp = physio_proc_enter(bp); + ncv_pio_read(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); + physio_proc_leave(pp); + break; + + case COMMAND_PHASE: /* cmd out */ + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + ncvhw_fpush(iot, ioh, + slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); + bus_space_write_1(iot, ioh, 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); + 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); + + len = scsi_low_msgout(slp, ti); + ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + if (scsi_low_is_msgout_continue(ti) == 0) + bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTATN); + 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; + if (sc->sc_compseq != 0) + { + sc->sc_compseq = 0; + if ((ireason & INTR_FC) && len == 2) + { + ti->ti_status = + bus_space_read_1(iot, ioh, cr0_sfifo); + len --; + } + else + { + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "compseq error"); + 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); + break; + } + + if ((ireason & INTR_FC) && len == 1) + { + regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, + cr0_sfifo); + scsi_low_msgin(slp, ti, regv); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, + CMD_MSGOK); + } + else + { + slp->sl_error |= MSGERR; + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, ireason); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "hw msgin error"); + } + break; + } + + return 1; +} Property changes on: stable/4/sys/dev/ncv/ncr53c500.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ncv/ncr53c500hw.h =================================================================== --- stable/4/sys/dev/ncv/ncr53c500hw.h (nonexistent) +++ stable/4/sys/dev/ncv/ncr53c500hw.h (revision 67524) @@ -0,0 +1,67 @@ +/* $FreeBSD$ */ +/* $NecBSD: ncr53c500hw.h,v 1.6 1998/11/26 01:59:12 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + * + * 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 __NCR53C500HW_H_ +#define __NCR53C500HW_H_ + +#include + +#define NCV_HOSTID 7 +#define NCV_NTARGETS 8 +#define NCV_NLUNS 8 + +struct ncv_hw { + /* configuration images */ + u_int8_t cfg1; + u_int8_t cfg2; + u_int8_t cfg3; + u_int8_t cfg4; + u_int8_t cfg5; + + /* synch */ + u_int8_t clk; + u_int8_t mperiod; + u_int8_t moffset; +}; + +/* dvcfg */ +#define NCV_C5IMG(flags) ((DVCFG_MAJOR(flags) >> 8) & 0xff) +#define NCV_CLKFACTOR(flags) (DVCFG_MAJOR(flags) & 0x0f) +#define NCVHWCFG_MAX10M 0x01 +#define NCVHWCFG_SCSI1 0x02 +#define NCVHWCFG_SLOW 0x04 +#define NCVHWCFG_FIFOBUG 0x08 +#define NCV_SPECIAL(flags) ((DVCFG_MAJOR(flags) >> 4) & 0x0f) +#endif /* !__NCR53C500HW_H_ */ Property changes on: stable/4/sys/dev/ncv/ncr53c500hw.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ncv/ncr53c500hwtab.h =================================================================== --- stable/4/sys/dev/ncv/ncr53c500hwtab.h (nonexistent) +++ stable/4/sys/dev/ncv/ncr53c500hwtab.h (revision 67524) @@ -0,0 +1,47 @@ +/* $FreeBSD$ */ +/* $NecBSD: ncr53c500hwtab.h,v 1.2 1998/11/26 01:59:13 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + * + * 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. + */ + +static struct ncv_hw ncv_template = { + NCV_HOSTID, + C2_FE | C2_SCSI2, + C3_FCLK, + C4_ANE, + 0x80, + + CLK_40M_F, + + 200 / 4, + 15, +}; Property changes on: stable/4/sys/dev/ncv/ncr53c500hwtab.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ncv/ncr53c500reg.h =================================================================== --- stable/4/sys/dev/ncv/ncr53c500reg.h (nonexistent) +++ stable/4/sys/dev/ncv/ncr53c500reg.h (revision 67524) @@ -0,0 +1,192 @@ +/* $FreeBSD$ */ +/* $NecBSD: ncr53c500reg.h,v 1.5 1998/12/26 11:50:01 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + * Copyright (c) 1995, 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 _NCR53C500REG_H_ +#define _NCR53C500REG_H_ + +/* Control Register Set 0 */ +#define NCVIOSZ 0x10 + +#define cr0_tclsb 0x00 /* RW - Transfer Count Low */ +#define cr0_tcmsb 0x01 /* RW - Transfer Count Mid */ +#define cr0_sfifo 0x02 /* RW - FIFO data */ +#define cr0_cmd 0x03 /* RW - Command (2 deep) */ +#define cr0_stat 0x04 /* RO - Status */ +#define cr0_dstid 0x04 /* WO - Select/Reselect Bus ID */ +#define cr0_istat 0x05 /* RO - Interrupt */ +#define cr0_srtout 0x05 /* WO - Select/Reselect Timeout */ +#define cr0_seq 0x06 /* RO - Sequence Step */ +#define cr0_period 0x06 /* WO - Synch Transfer Period */ +#define cr0_sffl 0x07 /* RO - FIFO FLags */ +#define cr0_offs 0x07 /* WO - Synch Ofset */ +#define cr0_cfg1 0x08 /* RW - Configuration #1 */ +#define cr0_clk 0x09 /* WO - Clock Conversion Factor */ +#define cr0_tst 0x0a /* WO - Test (Chip Test Only) */ +#define cr0_cfg2 0x0b /* RW - Configuration #2 */ +#define cr0_cfg3 0x0c /* RW - Configuration #3 */ +#define cr0_cfg4 0x0d /* RW - Configuration #4 */ +#define cr0_tchsb 0x0e /* RW - Transfer Count High */ +#define cr0_fifo_bottom 0x0f /* WO - FIFO bottom */ + +/* Control Register Set 1 */ +#define cr1_jumper 0x00 /* RW - Jumper Sense Port */ +#define cr1_sram_ptr 0x01 /* RW - SRAM Address Pointer */ +#define cr1_sram_data 0x02 /* RW - SRAM Data */ +#define cr1_fdata 0x04 /* RW - PIO FIFO */ +#define cr1_fstat 0x08 /* RW - PIO Status */ +#define cr1_atacmd 0x09 /* RW - ATA Command/Status */ +#define cr1_ataerr 0x0a /* RW - ATA Features/Error */ +#define cr1_pflag 0x0b /* RW - PIO Flag Interrupt Enable */ +#define cr1_cfg5 0x0d /* RW - Configuration #5 */ +#define cr1_sig 0x0e /* RO - Signature */ +#define cr1_cfg6 0x0f /* RW - Configuration #6 */ + +/* atacmd (MPS110 ONLY) */ +#define ATACMD_POWDOWN 0x2d +#define ATACMD_ENGAGE 0x24 + +/* cr0_sffl regster */ +#define CR0_SFFLR_BMASK 0x1f /* scsi fifo byte mask */ + +/* cfg4 */ +#define C4_ANE 0x04 + +/* cfg3 */ +#define C3_NULL 0x00 +#define C3_FCLK 0x08 /* Fast SCSI */ +#define C3_FSCSI 0x10 /* Fast Clock (>25Mhz) */ + +/* cfg2 */ +#define C2_SCSI2 0x08 /* SCSI-2 Enable */ +#define C2_FE 0x40 /* Features Enable */ + +/* cfg1 */ +#define C1_SLOW 0x80 /* Slow Cable Mode */ +#define C1_SRR 0x40 /* SCSI Reset Rep Int Dis */ +#define C1_PARENB 0x10 /* Enable Parity Check */ + +/* clk factor */ +#define CLK_40M_F 0x00 +#define CLK_25M_F 0x05 +#define CLK_30M_F 0x06 +#define CLK_35M_F 0x07 + +/* interrupt status register */ +#define INTR_SBR 0x80 /* SCSI Bus Reset */ +#define INTR_ILL 0x40 /* Illegal Command */ +#define INTR_DIS 0x20 /* Disconnect */ +#define INTR_BS 0x10 /* Bus Service */ +#define INTR_FC 0x08 /* Function Complete */ +#define INTR_RESEL 0x04 /* Reselected */ +#define INTR_SELATN 0x02 /* Select with ATN */ +#define INTR_SEL 0x01 /* Selected */ +#define INTR_RESELECT (INTR_RESEL | INTR_FC) + +/* status register */ +#define STAT_INT 0x80 /* Interrupt */ +#define STAT_GE 0x40 /* Gross Error */ +#define STAT_PE 0x20 /* Parity Error */ +#define STAT_TC 0x10 /* Terminal Count */ + +/* phase bits */ +#define IOI 0x01 +#define CDI 0x02 +#define MSGI 0x04 + +/* Information transfer phases */ +#define DATA_OUT_PHASE (0) +#define DATA_IN_PHASE (IOI) +#define COMMAND_PHASE (CDI) +#define STATUS_PHASE (CDI|IOI) +#define MESSAGE_OUT_PHASE (MSGI|CDI) +#define MESSAGE_IN_PHASE (MSGI|CDI|IOI) + +#define PHASE_MASK (MSGI|CDI|IOI) + +/* fifo status register */ +#define FIFO_SMASK 0x1e +#define FIFO_E 0x10 /* fifo empty */ +#define FIFO_B 0x00 /* there exists any */ +#define FIFO_1 0x08 /* 1/3 <= bytes < 2/3 */ +#define FIFO_2 0x04 /* 2/3 <= bytes < full */ +#define FIFO_F 0x02 /* full */ +#define FIFO_EN 0x01 /* fifo direction */ +#define FIFO_BRK 0x40 /* phase miss */ + +#define FIFO_F_SZ 128 +#define FIFO_1_SZ 44 +#define FIFO_2_SZ 84 + +/* pflags */ +#define PFR_WRITE 0x01 + +/* Commands */ +#define CMD_DMA 0x80 /* DMA Bit */ +#define CMD_NOP 0x00 /* No Operation */ +#define CMD_FLUSH 0x01 /* Flush FIFO */ +#define CMD_RSTCHIP 0x02 /* Reset Chip */ +#define CMD_RSTSCSI 0x03 /* Reset SCSI Bus */ +#define CMD_RESEL 0x40 /* Reselect Sequence */ +#define CMD_SELNATN 0x41 /* Select without ATN */ +#define CMD_SELATN 0x42 /* Select with ATN */ +#define CMD_SELATNS 0x43 /* Select with ATN & Stop */ +#define CMD_ENSEL 0x44 /* Enable (Re)Selection */ +#define CMD_DISSEL 0x45 /* Disable (Re)Selection */ +#define CMD_SELATN3 0x46 /* Select with ATN3 */ +#define CMD_RESEL3 0x47 /* Reselect3 Sequence */ +#define CMD_SNDMSG 0x20 /* Send Message */ +#define CMD_SNDSTAT 0x21 /* Send Status */ +#define CMD_SNDDATA 0x22 /* Send Data */ +#define CMD_DISCSEQ 0x23 /* Disconnect Sequence */ +#define CMD_TERMSEQ 0x24 /* Terminate Sequence */ +#define CMD_TCCS 0x25 /* Target Command Comp Seq */ +#define CMD_DISC 0x27 /* Disconnect */ +#define CMD_RECMSG 0x28 /* Receive Message */ +#define CMD_RECCMD 0x29 /* Receive Command */ +#define CMD_RECDATA 0x2a /* Receive Data */ +#define CMD_RECCSEQ 0x2b /* Receive Command Sequence */ +#define CMD_ABORT 0x04 /* Target Abort DMA */ +#define CMD_TRANS 0x10 /* Transfer Information */ +#define CMD_ICCS 0x11 /* Initiator Cmd Comp Seq */ +#define CMD_MSGOK 0x12 /* Message Accepted */ +#define CMD_TRPAD 0x18 /* Transfer Pad */ +#define CMD_SETATN 0x1a /* Set ATN */ +#define CMD_RSTATN 0x1b /* Reset ATN */ + +/* Default timeout */ +#define SEL_TOUT 0xa3 +#endif /* !_NCR53C500REG_H_ */ Property changes on: stable/4/sys/dev/ncv/ncr53c500reg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/ncv/ncr53c500var.h =================================================================== --- stable/4/sys/dev/ncv/ncr53c500var.h (nonexistent) +++ stable/4/sys/dev/ncv/ncr53c500var.h (revision 67524) @@ -0,0 +1,90 @@ +/* $FreeBSD$ */ +/* $NecBSD: ncr53c500var.h,v 1.11 1998/11/28 18:42:42 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + */ + +#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; + + void *sc_ih; + int sc_selstop; /* sel atn stop asserted */ + int sc_compseq; /* completion seq cmd asserted */ + int sc_tdatalen; /* temp xfer data len */ + + struct ncv_hw sc_hw; /* hardware register images */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *ncv_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct ncv_lun_info { + struct lun_info nli_li; + + u_int8_t nli_reg_cfg3; /* cfg3 images per lun */ + u_int8_t nli_reg_offset; /* synch offset register per lun */ + u_int8_t nli_reg_period; /* synch period register per lun */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int ncvprobesubr __P((bus_space_tag_t, bus_space_handle_t ioh, u_int, int)); +void ncvattachsubr __P((struct ncv_softc *)); +int ncvprint __P((void *, const char *)); +int ncvintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_NCR53C500VAR_H_ */ Property changes on: stable/4/sys/dev/ncv/ncr53c500var.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/nsp/nsp.c =================================================================== --- stable/4/sys/dev/nsp/nsp.c (nonexistent) +++ stable/4/sys/dev/nsp/nsp.c (revision 67524) @@ -0,0 +1,1373 @@ +/* $FreeBSD$ */ +/* $NecBSD: nsp.c,v 1.21 1999/07/23 21:00:05 honda Exp $ */ +/* $NetBSD$ */ + +#define NSP_DEBUG +#define NSP_STATICS + +/* + * 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 "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version > 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if __FreeBSD_version < 400001 +#include "nsp.h" +struct nsp_softc *nspdata[NNSP]; +#endif +#endif /* __FreeBSD__ */ + +/*************************************************** + * USER SETTINGS + ***************************************************/ +/* DEVICE CONFIGURATION FLAGS (MINOR) + * + * 0x01 DISCONECT 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_SELTIMEOUT 200 + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (nsp.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("nsp") +#endif /* __FreeBSD__ */ +#endif + +#ifdef NSP_DEBUG +int nsp_debug; +#endif /* NSP_DEBUG */ + +#ifdef NSP_STATICS +struct nsp_statics { + int disconnect; + int reselect; + int data_phase_bypass; +} nsp_statics[NSP_NTARGETS]; +#endif /* NSP_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver nsp_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void nsp_pio_read __P((struct nsp_softc *, struct targ_info *)); +static void nsp_pio_write __P((struct nsp_softc *, struct targ_info *)); +static int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int)); +static int nsp_msg __P((struct nsp_softc *, struct targ_info *, u_int)); +static int nsp_reselected __P((struct nsp_softc *)); +static __inline int nsp_disconnected __P((struct nsp_softc *, struct targ_info *)); +static __inline void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *)); +static void nsphw_init __P((struct nsp_softc *)); +static int nsp_nexus __P((struct nsp_softc *, struct targ_info *)); +static int nsp_world_start __P((struct nsp_softc *, int)); +static int nsphw_start_selection __P((struct nsp_softc *sc, struct slccb *)); +static void nsphw_bus_reset __P((struct nsp_softc *)); +static void nsphw_attention __P((struct nsp_softc *)); +static u_int nsp_fifo_count __P((struct nsp_softc *)); +static int nsp_negate_signal __P((struct nsp_softc *, u_int8_t, u_char *)); +static int nsp_expect_signal __P((struct nsp_softc *, u_int8_t, u_int8_t)); +static __inline void nsp_start_timer __P((struct nsp_softc *, int)); +static int nsp_dataphase_bypass __P((struct nsp_softc *, struct targ_info *)); +static void nsp_setup_fifo __P((struct nsp_softc *, int)); +static int nsp_lun_init __P((struct nsp_softc *, struct targ_info *, struct lun_info *)); +static void settimeout __P((void *)); + +struct scsi_low_funcs nspfuncs = { + SC_LOW_INIT_T nsp_world_start, + SC_LOW_BUSRST_T nsphw_bus_reset, + SC_LOW_LUN_INIT_T nsp_lun_init, + + SC_LOW_SELECT_T nsphw_start_selection, + SC_LOW_NEXUS_T nsp_nexus, + + SC_LOW_ATTEN_T nsphw_attention, + SC_LOW_MSG_T nsp_msg, + + SC_LOW_POLL_T nspintr, + + NULL, +}; + +/**************************************************** + * hwfuncs + ****************************************************/ +static __inline u_int8_t nsp_cr_read_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs)); +static __inline void nsp_cr_write_1 __P((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; +{ + + bus_space_write_1(bst, bsh, nsp_idxr, ofs); + return bus_space_read_1(bst, bsh, nsp_datar); +} + +static __inline void +nsp_cr_write_1(bst, bsh, ofs, va) + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_addr_t ofs; + u_int8_t va; +{ + + bus_space_write_1(bst, bsh, nsp_idxr, ofs); + bus_space_write_1(bst, bsh, nsp_datar, va); +} + +static int +nsp_expect_signal(sc, curphase, mask) + struct nsp_softc *sc; + u_int8_t curphase, 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 rv = -1; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t ph, isrc; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (ph == 0xff) { + rv = -1; + break; + } + isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + if (isrc & IRQSR_SCSI) { + rv = 0; + break; + } + if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase) { + rv = 1; + break; + } + } + while (tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: nsp_expect_signal timeout\n", slp->sl_xname); + rv = -1; + } + + return rv; +} + +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); + + /* setup SCSI interface */ + bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_IFSEL); + + nsp_cr_write_1(bst, bsh, 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(bst, bsh, NSPR_SCIENR, sc->sc_icr); + nsp_cr_write_1(bst, bsh, NSPR_PARITYR, 0); + nsp_cr_write_1(bst, bsh, 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); + + 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(bst, bsh, NSPR_SYNCR, 0); + nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_cr_write_1(bst, bsh, NSPR_SCIENR, SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST); + bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); + + nsp_setup_fifo(sc, 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); +} + +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); + + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST); + delay(100 * 1000); /* 100ms */ + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0); + for (i = 0; i < 5; i ++) + (void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS); + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); +} + +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; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + /* check bus free */ + if (slp->sl_disc > 0) + { + s = splhigh(); + ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (ph != SCBUSMON_FREE) + { + splx(s); + return SCSI_LOW_START_FAIL; + } + splx(s); + } + + /* start arbitration */ + SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART); + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC); +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + do + { + /* XXX: what a stupid chip! */ + arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS); + delay(1); + } + while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + } + splx(s); + + if ((arbs & ARBITS_WIN) == 0) + { + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + return SCSI_LOW_START_FAIL; + } + + /* assert select line */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + scsi_low_arbit_win(slp, ti); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_DATA, + sc->sc_idbit | (1 << ti->ti_id)); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL | + SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc); + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc); + + /* check selection timeout */ + nsp_start_timer(sc, 1000 / 51); + 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; + intrmask_t s; + + s = splcam(); + 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; + sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST); + + nsphw_init(sc); + scsi_low_bus_reset(slp); + splx(s); + + SOFT_INTR_REQUIRED(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; +{ + struct ncp_synch_data *sdp; + struct lun_info *li = ti->ti_li; + struct nsp_lun_info *nli = (void *) li; + u_int period, offset; + int i; + + if ((msg & SCSI_LOW_MSG_SYNCH) == 0) + return 0; + + period = li->li_maxsynch.period; + offset = li->li_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. + */ + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 0; + nli->nli_reg_syncr = 0; + nli->nli_reg_ackwidth = 0; + return EINVAL; + } + + nli->nli_reg_syncr = (sdp->chip_period << SYNCR_PERS) | + (offset & SYNCR_OFFM); + nli->nli_reg_ackwidth = sdp->ack_width; + return 0; +} + +static int +nsp_lun_init(sc, ti, li) + struct nsp_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct nsp_lun_info *nli = (void *) li; + + li->li_maxsynch.period = 200 / 4; + li->li_maxsynch.offset = 15; + nli->nli_reg_syncr = 0; + nli->nli_reg_ackwidth = 0; + return 0; +} + +static __inline 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); +} + +/************************************************************** + * General probe attach + **************************************************************/ +int +nspprobesubr(iot, ioh, dvcfg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int dvcfg; +{ + u_int8_t regv; + + regv = bus_space_read_1(iot, ioh, nsp_fifosr); + if (regv < 0x11 || regv >= 0x20) + return 0; + return 1; +} + +int +nspprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +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_funcs = &nspfuncs; + if (sc->sc_memh != NULL) + sc->sc_xmode = NSP_MID_SMIT; + else + sc->sc_xmode = NSP_PIO; + + (void) scsi_low_attach(slp, 2, NSP_NTARGETS, NSP_NLUNS, + sizeof(struct nsp_lun_info)); +} + +/************************************************************** + * 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_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); + return count; +} + +static void +nsp_setup_fifo(sc, on) + struct nsp_softc *sc; + int on; +{ + 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_int8_t xfermode; + + if (on != 0) + xfermode = XFERMR_XEN | XFERMR_FIFOEN; + else + xfermode = 0; + + if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0) + { + sc->sc_mask = 0; + xfermode |= XFERMR_IO8; + } + else + { + sc->sc_mask = 3; + if (sc->sc_xmode == NSP_MID_SMIT) + xfermode |= XFERMR_MEM32; + else + xfermode |= XFERMR_IO32; + } + + sc->sc_xfermr = xfermode; + nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr); +} + +static __inline 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 = ti->ti_nexus; + u_int len = 0, cnt; + + slp->sl_flags &= ~HW_PDMASTART; + nsp_setup_fifo(sc, 0); + + 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 (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; + printf("%s len %x >= datalen %x\n", + slp->sl_xname, + len, slp->sl_scp.scp_datalen); + } + } + else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + { + if (sc->sc_cnt != cnt) + { + slp->sl_error |= PDMAERR; + printf("%s: data read count error %x != %x\n", + slp->sl_xname, sc->sc_cnt, cnt); + } + } + sc->sc_cnt = cnt; + } + else + { + + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } +} + +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +static void +nsp_pio_read(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; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int res, ocount, mask = sc->sc_mask; + u_int8_t stat, fstat; + + slp->sl_flags |= HW_PDMASTART; + ocount = sc->sc_cnt; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (slp->sl_scp.scp_datalen > 0 && tout == 0) + { + stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + stat &= SCBUSMON_PHMASK; + res = nsp_fifo_count(sc) - ocount; + if (res == 0) + { + if (stat == PHASE_DATAIN) + continue; + break; + } + + fstat = bus_space_read_1(bst, bsh, nsp_fifosr); + if ((fstat & FIFOSR_FULLEMP) == 0 && stat == PHASE_DATAIN) + continue; + + if (res > slp->sl_scp.scp_datalen) + break; + + if (res >= NSP_BUFFER_SIZE) + res = NSP_BUFFER_SIZE; + else + res &= ~mask; + + if (sc->sc_xfermr & XFERMR_MEM32) + { + bus_space_read_region_4(sc->sc_memt, + sc->sc_memh, + 0, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + } + else + { + if (mask != 0) + bus_space_read_multi_4(bst, bsh, nsp_fifodr, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + else + bus_space_read_multi_1(bst, bsh, nsp_fifodr, + (u_int8_t *) slp->sl_scp.scp_data, + res); + } + + slp->sl_scp.scp_data += res; + slp->sl_scp.scp_datalen -= res; + ocount += res; + } + + sc->sc_cnt = ocount; + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +static void +nsp_pio_write(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; + u_int res, ocount, mask = sc->sc_mask; + int s; + int tout = 0; + register u_int8_t stat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ocount = sc->sc_cnt; + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (slp->sl_scp.scp_datalen > 0 && tout == 0) + { + stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + stat &= SCBUSMON_PHMASK; + if (stat != PHASE_DATAOUT) + break; + + res = ocount - nsp_fifo_count(sc); + if (res > 0) + continue; + + res = (slp->sl_scp.scp_datalen > WFIFO_CRIT) ? WFIFO_CRIT : + slp->sl_scp.scp_datalen; + + if (sc->sc_xfermr & XFERMR_MEM32) + { + bus_space_write_region_4(sc->sc_memt, + sc->sc_memh, + 0, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + } + else + { + if (mask != 0) + bus_space_write_multi_4(bst, bsh, nsp_fifodr, + (u_int32_t *) slp->sl_scp.scp_data, res >> 2); + else + bus_space_write_multi_1(bst, bsh, nsp_fifodr, + (u_int8_t *) slp->sl_scp.scp_data, res); + } + + slp->sl_scp.scp_datalen -= res; + slp->sl_scp.scp_data += res; + ocount += res; + } + + sc->sc_cnt = ocount; + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +static int +nsp_negate_signal(sc, mask, s) + 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 tout = 0; + int s; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t regv; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (regv == 0xff) + break; + } + while ((regv & mask) != 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: %s singla off timeout \n", slp->sl_xname, s); + } + + return 0; +} + +static int +nsp_xfer(sc, buf, len, phase) + struct nsp_softc *sc; + u_int8_t *buf; + int len; + int phase; +{ + 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 ptr, rv, atn; + + atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0); + for (ptr = 0; len > 0; len --, ptr ++) + { + rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ); + if (rv <= 0) + goto out; + + if (len == 1 && atn == 0) + { + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_ADIR | SCBUSCR_ACKEN); + } + + if (phase & SCBUSMON_IO) + { + buf[ptr] = nsp_cr_read_1(bst, bsh, NSPR_DATAACK); + } + else + { + nsp_cr_write_1(bst, bsh, NSPR_DATAACK, buf[ptr]); + } + nsp_negate_signal(sc, SCBUSMON_ACK, "xfer"); + } + +out: + return len; +} + +static int +nsp_dataphase_bypass(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + struct slccb *cb = ti->ti_nexus; + u_int cnt; + + if (slp->sl_scp.scp_direction != SCSI_LOW_READ || + (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0) + return 0; + + cnt = nsp_fifo_count(sc); + if (sc->sc_cnt == cnt) + return 0; + if (cnt >= DEV_BSIZE) + return EINVAL; + + if (cb == NULL) + return 0; + + /* + * XXX: NSP_QUIRK + * Data phase skip only occures in case of SCSI_LOW_READ. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + nsp_pio_read(sc, ti); + nsp_pdma_end(sc, ti); +#ifdef NSP_STATICS + nsp_statics[ti->ti_id].data_phase_bypass ++; +#endif /* NSP_STATICS */ + return 0; +} + +/************************************************************** + * 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 &= ~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) & ~(SCBUSCR_BSY | SCBUSCR_ATN); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ADIR | SCBUSCR_ACKEN); + +#ifdef NSP_STATICS + nsp_statics[sid].reselect ++; +#endif /* NSP_STATCIS */ + return EJUSTRETURN; +} + +static __inline int +nsp_disconnected(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + +#ifdef NSP_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + nsp_statics[ti->ti_id].disconnect ++; +#endif /* NSP_STATICS */ + + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static void nspmsg __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t)); + +static void +nspmsg(sc, s, isrc, ph, irqphs) + struct nsp_softc *sc; + u_char *s; + u_int8_t isrc, ph, irqphs; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + + printf("%s: %s\n", slp->sl_xname, s); + printf("%s: isrc 0x%x scmon 0x%x irqphs 0x%x\n", + slp->sl_xname, (u_int) isrc, (u_int) ph, (u_int) irqphs); +} + +static int +nsp_nexus(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + struct nsp_lun_info *nli = (void *) ti->ti_li; + + /* setup synch transfer registers */ + nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nli->nli_reg_syncr); + nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nli->nli_reg_ackwidth); + + /* setup pdma fifo */ + nsp_setup_fifo(sc, 1); + + /* clear ack counter */ + sc->sc_cnt = 0; + nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | + PTCLRR_REQ | PTCLRR_HOST); + 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 physio_proc *pp; + struct buf *bp; + 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); + if (isrc == 0xff || (isrc & IRQSR_MASK) == 0) + { + bus_space_write_1(bst, bsh, 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); + if ((isrc & IRQSR_SCSI) != 0) + { + irqphs = nsp_cr_read_1(bst, bsh, 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); + sc->sc_timer = 0; + } + + if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0) + { + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL); + return 1; + } + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL | IRQCR_FIFOCL); + + /******************************************* + * debug section + *******************************************/ +#ifdef NSP_DEBUG + if (nsp_debug) + { + nspmsg(sc, "current status", isrc, ph, irqphs); + scsi_low_print(slp, NULL); + if (nsp_debug > 1) + Debugger(); + } +#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); + if (nsp_reselected(sc) == EJUSTRETURN) + return 1; + } + + if ((irqphs & (IRQPHS_PCHG | IRQPHS_LBF)) == 0) + return 1; + } + + /******************************************* + * nexus check + *******************************************/ + if ((ti = slp->sl_nexus) == NULL) + { + /* unknown scsi phase changes */ + nspmsg(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); + return nsp_disconnected(sc, ti); + } + sc->sc_seltout ++; + nsp_start_timer(sc, 1000 / 51); + return 1; + } + + /* attention assert */ + sc->sc_seltout = 0; + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc); + delay(1); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN); + + SCSI_LOW_TARGET_ASSERT_ATN(ti); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + return 1; + + case PH_RESEL: + if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + /* fall */ + + default: + if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) == 0) + return 1; + break; + } + + /******************************************* + * scsi seq + *******************************************/ + if (slp->sl_flags & HW_PDMASTART) + nsp_pdma_end(sc, ti); + + /* normal disconnect */ + if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0) + return nsp_disconnected(sc, ti); + + /* check unexpected bus free state */ + if (ph == 0) + { + nspmsg(sc, "unexpected bus free", isrc, ph, irqphs); + return nsp_disconnected(sc, ti); + } + + /* check normal scsi phase */ + switch (ph & SCBUSMON_PHMASK) + { + case PHASE_CMD: + if ((ph & SCBUSMON_REQ) == 0) + return 1; + + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR); + for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++) + nsp_cr_write_1(bst, bsh, NSPR_CMDDR, + slp->sl_scp.scp_cmd[len]); + + nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC); + break; + + case PHASE_DATAOUT: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + break; + + pp = physio_proc_enter(bp); + nsp_pio_write(sc, ti); + physio_proc_leave(pp); + break; + + case PHASE_DATAIN: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + break; + + pp = physio_proc_enter(bp); + nsp_pio_read(sc, ti); + physio_proc_leave(pp); + break; + + case PHASE_STATUS: + nsp_dataphase_bypass(sc, ti); + if ((ph & SCBUSMON_REQ) == 0) + return 1; + + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); + ti->ti_status = nsp_cr_read_1(bst, bsh, NSPR_DATAACK); + break; + + case PHASE_MSGOUT: + if ((ph & SCBUSMON_REQ) == 0) + goto timerout; + + /* + * 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); + + len = scsi_low_msgout(slp, ti); + if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT)) + { + scsi_low_assert_msg(slp, ti, + SCSI_LOW_MSG_RESET, 0); + nspmsg(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); + break; + + case PHASE_MSGIN: + nsp_dataphase_bypass(sc, ti); + if ((ph & SCBUSMON_REQ) == 0) + goto timerout; + + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + + /* + * 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 { + /* read a data */ + regv = nsp_cr_read_1(bst, bsh, NSPR_DATA); + + /* assert ack */ + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); + cr |= SCBUSCR_ACK; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_negate_signal(sc, SCBUSMON_REQ, "msgin"); + + scsi_low_msgin(slp, ti, regv); + + /* deassert ack */ + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); + cr &= ~SCBUSCR_ACK; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + + /* catch a next signal */ + rv = nsp_expect_signal(sc, PHASE_MSGIN, SCBUSMON_REQ); + } + while (rv > 0 && len -- > 0); + break; + + case PHASE_SEL: + default: + nspmsg(sc, "unknown scsi phase", isrc, ph, irqphs); + break; + } + + return 1; + +timerout: + nsp_start_timer(sc, 1000 / 102); + return 0; +} Property changes on: stable/4/sys/dev/nsp/nsp.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/nsp/nspreg.h =================================================================== --- stable/4/sys/dev/nsp/nspreg.h (nonexistent) +++ stable/4/sys/dev/nsp/nspreg.h (revision 67524) @@ -0,0 +1,201 @@ +/* $FreeBSD$ */ +/* $NecBSD: nspreg.h,v 1.4 1999/04/15 01:35:55 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + */ + +#ifndef _NSPREG_H_ +#define _NSPREG_H_ + +/* base registers */ +#define nsp_irqcr 0 +#define IRQCR_RESCL 0x01 +#define IRQCR_PHCL 0x02 +#define IRQCR_TIMERCL 0x04 +#define IRQCR_FIFOCL 0x08 +#define IRQCR_SCSIIDIS 0x10 +#define IRQCR_EXTIDIS 0x20 +#define IRQCR_TIMERIDIS 0x40 +#define IRQCR_FIFOIDIS 0x80 +#define IRQCR_ALLMASK 0xff +#define IRQCR_IRQDIS 0xf0 + +#define nsp_irqsr 0 +#define IRQSR_SCSI 0x01 +#define IRQSR_EXT 0x02 +#define IRQSR_TIMER 0x04 +#define IRQSR_FIFO 0x08 +#define IRQSR_MASK 0x0f + +#define nsp_ifselr 1 +#define IFSELR_IFSEL 0x01 +#define IFSELR_REGSEL 0x04 + +#define nsp_fifosr 1 +#define FIFOSR_CHIPREVM 0x0f +#define FIFOSR_CHIPIDM 0x70 +#define FIFOSR_FULLEMP 0x80 + +#define nsp_idxr 2 +#define nsp_datar 3 +#define nsp_fifodr 4 + +/* indexed registers */ +#define NSPR_EXTBUSC 0x10 + +#define NSPR_CLKDIVR 0x11 +#define CLKDIVR_40M 0x02 +#define CLKDIVR_20M 0x01 + +#define NSPR_TERMPWRC 0x13 +#define TERMPWRC_POWON 0x01 + +#define NSPR_SCIENR 0x15 +#define SCIENR_SCCHG 0x01 +#define SCIENR_RESEL 0x10 +#define SCIENR_FIFO 0x20 +#define SCIENR_RST 0x40 + +#define NSPR_IRQPHS 0x16 +#define IRQPHS_LMSG 0x01 +#define IRQPHS_LIO 0x02 +#define IRQPHS_LCD 0x04 +#define IRQPHS_LBF 0x08 +#define IRQPHS_PCHG 0x10 +#define IRQPHS_RSEL 0x20 +#define IRQPHS_FIFO 0x40 +#define IRQPHS_RST 0x80 + +#define NSPR_TIMERCNT 0x17 + +#define NSPR_SCBUSCR 0x18 +#define SCBUSCR_SEL 0x01 +#define SCBUSCR_RST 0x02 +#define SCBUSCR_DOUT 0x04 +#define SCBUSCR_ATN 0x08 +#define SCBUSCR_ACK 0x10 +#define SCBUSCR_BSY 0x20 +#define SCBUSCR_ADIR 0x40 +#define SCBUSCR_ACKEN 0x80 + +#define NSPR_SCBUSMON 0x19 +#define SCBUSMON_MSG 0x01 +#define SCBUSMON_IO 0x02 +#define SCBUSMON_CD 0x04 +#define SCBUSMON_BSY 0x08 +#define SCBUSMON_ACK 0x10 +#define SCBUSMON_REQ 0x20 +#define SCBUSMON_SEL 0x40 +#define SCBUSMON_ATN 0x80 + +#define NSPR_SETARBIT 0x1A + +#define NSPR_ARBITS 0x1A +#define ARBITS_EXEC 0x01 +#define ARBITS_CLR 0x02 +#define ARBITS_WIN 0x02 +#define ARBITS_FAIL 0x04 +#define ARBITS_RESEL 0x08 + +#define NSPR_PARITYR 0x1B /* (W/R) */ + +#define NSPR_CMDCR 0x1C /* (W) */ +#define CMDCR_PTCLR 0x01 +#define CMDCR_EXEC 0x02 + +#define NSPR_RESELR 0x1C /* (R) */ +#define NSPR_CMDDR 0x1D /* (W/R) */ + +#define NSPR_PTCLRR 0x1E /* (W) */ +#define PTCLRR_PT 0x01 +#define PTCLRR_ACK 0x02 +#define PTCLRR_REQ 0x04 +#define PTCLRR_HOST 0x08 +#define PTCLRR_RSS 0x30 + +#define NSPR_XFERCR 0x1E /* (R) */ + +#define NSPR_XFERMR 0x20 +#define XFERMR_MEM8 0x01 +#define XFERMR_MEM32 0x02 +#define XFERMR_ADR24 0x04 +#define XFERMR_ADR32 0x08 +#define XFERMR_IO8 0x10 +#define XFERMR_IO32 0x20 +#define XFERMR_XEN 0x40 +#define XFERMR_FIFOEN 0x80 + +#define NSPR_SYNCR 0x21 +#define SYNCR_OFFM 0x0f +#define SYNCR_PERM 0xf0 +#define SYNCR_PERS 4 + +#define NSPR_DATA 0x22 +#define NSPR_DATAACK 0x23 +#define NSPR_OCR 0x26 +#define OCR_ROMEN 0x01 +#define OCR_TERMPWROUT 0x02 +#define OCR_TERMPWRS 0x04 + +#define NSPR_ACKWIDTH 0x27 + +/* SCBUSMON phase defs */ +#define SCBUSMON_FREE 0 +#define SCBUSMON_CMD \ + (SCBUSMON_BSY | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_MSGIN \ + (SCBUSMON_BSY | SCBUSMON_MSG | SCBUSMON_IO | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_MSGOUT \ + (SCBUSMON_BSY | SCBUSMON_MSG | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_DATAIN \ + (SCBUSMON_BSY | SCBUSMON_IO | SCBUSMON_REQ) +#define SCBUSMON_DATAOUT \ + (SCBUSMON_BSY | SCBUSMON_REQ) +#define SCBUSMON_STATUS \ + (SCBUSMON_BSY | SCBUSMON_IO | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_RESELECT \ + (SCBUSMON_SEL | SCBUSMON_IO) +#define SCBUSMON_PHMASK \ + (SCBUSMON_SEL | SCBUSMON_CD | SCBUSMON_MSG | SCBUSMON_IO) + +/* SCSI phase */ +#define PHASE_CMD (SCBUSMON_CMD & SCBUSMON_PHMASK) +#define PHASE_DATAIN (SCBUSMON_DATAIN & SCBUSMON_PHMASK) +#define PHASE_DATAOUT (SCBUSMON_DATAOUT & SCBUSMON_PHMASK) +#define PHASE_STATUS (SCBUSMON_STATUS & SCBUSMON_PHMASK) +#define PHASE_MSGIN (SCBUSMON_MSGIN & SCBUSMON_PHMASK) +#define PHASE_MSGOUT (SCBUSMON_MSGOUT & SCBUSMON_PHMASK) +#define PHASE_SEL (SCBUSMON_SEL | SCBUSMON_IO) + +/* Size */ +#define NSP_MEMSIZE NBPG +#define NSP_IOSIZE 16 +#define NSP_BUFFER_SIZE 512 +#endif /* !_NSPREG_H_ */ Property changes on: stable/4/sys/dev/nsp/nspreg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/nsp/nspvar.h =================================================================== --- stable/4/sys/dev/nsp/nspvar.h (nonexistent) +++ stable/4/sys/dev/nsp/nspvar.h (revision 67524) @@ -0,0 +1,102 @@ +/* $FreeBSD$ */ +/* $NecBSD: nspvar.h,v 1.7 1999/04/15 01:35:55 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + */ + +#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; + + void *sc_ih; + + int sc_seltout; /* selection timeout counter */ + int sc_timer; /* timer start */ + + int sc_xmode; +#define NSP_HIGH_SMIT 2 /* write address data mode */ +#define NSP_MID_SMIT 1 /* mem access */ +#define NSP_PIO 0 /* io access */ + + u_int sc_idbit; /* host id bit pattern */ + u_int sc_mask; /* bus width mask */ + 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_xfermr; /* fifo control reg */ + u_int8_t sc_icr; /* interrupt control reg */ + + u_int8_t sc_busc; /* busc registers */ + u_long sc_ringp; /* data buffer ring pointer */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *nsp_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct nsp_lun_info { + struct lun_info nli_li; /* generic lun info */ + + u_int8_t nli_reg_syncr; /* sync registers per devices */ + u_int8_t nli_reg_ackwidth; /* ackwidth per devices */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int nspprobesubr __P((bus_space_tag_t, bus_space_handle_t, u_int)); +void nspattachsubr __P((struct nsp_softc *)); +int nspprint __P((void *, const char *)); +int nspintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_NSPVAR_H_ */ Property changes on: stable/4/sys/dev/nsp/nspvar.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/stg/tmc18c30.c =================================================================== --- stable/4/sys/dev/stg/tmc18c30.c (nonexistent) +++ stable/4/sys/dev/stg/tmc18c30.c (revision 67524) @@ -0,0 +1,1218 @@ +/* $FreeBSD$ */ +/* $NecBSD: tmc18c30.c,v 1.28 1999/07/23 21:00:06 honda Exp $ */ +/* $NetBSD$ */ + +#define STG_DEBUG +#define STG_STATICS + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998, 1999 + * 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 "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if __FreeBSD_version < 400001 +#include "stg.h" +struct stg_softc *stgdata[NSTG]; +#endif +#endif /* __FreeBSD__ */ + +/*************************************************** + * USER SETTINGS + ***************************************************/ +/* DEVICE CONFIGURATION FLAGS (MINOR) + * + * 0x01 DISCONECT 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_FCB 1 + +#define TMC18C50_FIFOSZ 0x2000 +#define TMC18C50_FCB 2 + +/*************************************************** + * PARAMS + ***************************************************/ +#define STG_NTARGETS 8 +#define STG_NLUNS 8 + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (tmc18c30.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("stg") +#endif /* __FreeBSD__ */ +#endif + +#ifdef STG_DEBUG +int stg_debug; +#endif /* STG_DEBUG */ + +#ifdef STG_STATICS +struct stg_statics { + int disconnect; + int reselect; + int sprious_arbit_fail_0; + int sprious_arbit_fail_1; + int sprious_arbit_fail_2; +} stg_statics[STG_NTARGETS]; +#endif /* STG_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver stg_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void stg_pio_read __P((struct stg_softc *, struct targ_info *)); +static void stg_pio_write __P((struct stg_softc *, struct targ_info *)); +static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int)); +static int stg_msg __P((struct stg_softc *, struct targ_info *, u_int)); +static int stg_reselected __P((struct stg_softc *)); +static __inline int stg_disconnected __P((struct stg_softc *, struct targ_info *)); +static __inline void stg_pdma_end __P((struct stg_softc *, struct targ_info *)); +static int stghw_select_targ_wait __P((struct stg_softc *, int)); +static int stghw_check __P((struct stg_softc *)); +static void stghw_init __P((struct stg_softc *)); +static int stg_negate_signal __P((struct stg_softc *, u_int8_t, u_char *)); +static int stg_expect_signal __P((struct stg_softc *, u_int8_t, u_int8_t)); +static int stg_world_start __P((struct stg_softc *, int)); +static int stghw_start_selection __P((struct stg_softc *sc, struct slccb *)); +static void stghw_bus_reset __P((struct stg_softc *)); +static void stghw_attention __P((struct stg_softc *)); +static int stg_nexus __P((struct stg_softc *, struct targ_info *)); +static int stg_lun_init __P((struct stg_softc *, struct targ_info *, struct lun_info *)); +static __inline void stghw_bcr_write_1 __P((struct stg_softc *, u_int8_t)); +static void settimeout __P((void *)); + +struct scsi_low_funcs stgfuncs = { + SC_LOW_INIT_T stg_world_start, + SC_LOW_BUSRST_T stghw_bus_reset, + SC_LOW_LUN_INIT_T stg_lun_init, + + SC_LOW_SELECT_T stghw_start_selection, + SC_LOW_NEXUS_T stg_nexus, + + SC_LOW_ATTEN_T stghw_attention, + SC_LOW_MSG_T stg_msg, + + SC_LOW_POLL_T stgintr, + + NULL, +}; + +/**************************************************** + * hwfuncs + ****************************************************/ +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_int16_t lsb, msb; + + sc->sc_chip = TMCCHIP_UNK; + sc->sc_fsz = TMC18C50_FIFOSZ; + sc->sc_fcb = TMC18C50_FCB; + sc->sc_fcsp = 0; + + 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; + + lsb = bus_space_read_1(iot, ioh, tmc_idlsb); + msb = bus_space_read_1(iot, ioh, 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: + sc->sc_chip = TMCCHIP_18C50; + sc->sc_fcsp |= FCTL_CLRINT; + if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02) + { + sc->sc_chip = TMCCHIP_18C30; + sc->sc_fsz = TMC18C30_FIFOSZ; + sc->sc_fcb = TMC18C30_FCB; + } + break; + + default: + return ENODEV; + } + + sc->sc_icinit = ICTL_ALLINT | sc->sc_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); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | sc->sc_fcRinit | + FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + + bus_space_write_1(iot, ioh, tmc_ssctl, 0); +} + +static int +stg_lun_init(sc, ti, li) + struct stg_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct stg_lun_info *sli = (void *) li; + + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 8; + sli->sli_reg_synch = 0; + return 0; +} + +/**************************************************** + * scsi low interface + ****************************************************/ +static __inline void +stghw_bcr_write_1(sc, bcv) + struct stg_softc *sc; + u_int8_t bcv; +{ + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, bcv); + sc->sc_busimg = bcv; +} + +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); +} + +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); + 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; +{ + 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 = cb->ti; + struct lun_info *li = ti->ti_li; + register u_int8_t stat; + int s; + + if (li->li_flags & SCSI_LOW_NOPARITY) + sc->sc_fcRinit &= ~FCTL_PARENB; + else + sc->sc_fcRinit |= FCTL_PARENB; + + stghw_bcr_write_1(sc, BCTL_BUSFREE); + + s = splhigh(); + if (slp->sl_disc > 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if (stat & (BSTAT_BSY | BSTAT_SEL | BSTAT_IO)) + { + 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); + + 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; + intrmask_t s; + + if ((error = stghw_check(sc)) != 0) + return error; + + s = splcam(); + stghw_init(sc); + scsi_low_bus_reset(slp); + stghw_init(sc); + splx(s); + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +static int +stg_msg(sc, ti, msg) + struct stg_softc *sc; + struct targ_info *ti; + u_int msg; +{ + struct lun_info *li = ti->ti_li; + struct stg_lun_info *sli = (void *) li; + u_int period, offset; + + if (msg != SCSI_LOW_MSG_SYNCH) + return EINVAL; + + period = li->li_maxsynch.period; + offset = li->li_maxsynch.offset; + period = period << 2; + if (period >= 200) + { + sli->sli_reg_synch = (period - 200) / 50; + if (period % 50) + sli->sli_reg_synch ++; + sli->sli_reg_synch |= SSCTL_SYNCHEN; + } + else if (period >= 100) + { + sli->sli_reg_synch = (period - 100) / 50; + if (period % 50) + sli->sli_reg_synch ++; + sli->sli_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN; + } + return 0; +} + +/************************************************************** + * General probe attach + **************************************************************/ +int +stgprobesubr(iot, ioh, dvcfg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + 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); + switch (msb << 8 | lsb) + { + default: + return 0; + case 0x6127: + /* not support! */ + return 0; + case 0x60e9: + return 1; + } + return 0; +} + +int +stgprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +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; + + slp->sl_cfgflags |= CFG_ASYNC; /* XXX */ + + if (stghw_check(sc) != 0) + { + printf("stg: hardware missing\n"); + return; + } + + (void) scsi_low_attach(slp, 2, STG_NTARGETS, STG_NLUNS, + sizeof(struct stg_lun_info)); +} + +/************************************************************** + * 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 = ti->ti_nexus; + u_int len, tres; + + slp->sl_flags &= ~HW_PDMASTART; + + if (ti->ti_phase == PH_DATA) + { + len = bus_space_read_2(iot, ioh, 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; + printf("%s len %x >= datalen %x\n", + slp->sl_xname, + len, slp->sl_scp.scp_datalen); + } + } + } + else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + { + if (len != 0) + { + slp->sl_error |= PDMAERR; + printf("%s: len %x left in fifo\n", + slp->sl_xname, len); + } + } + } + else + { + + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); +} + +static void +stg_pio_read(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 sc_p *sp = &slp->sl_scp; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int res; + u_int8_t stat; + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN); + + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (sp->scp_datalen > 0 && tout == 0) + { + res = bus_space_read_2(iot, ioh, tmc_fdcnt); + if (res == 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if ((stat & BSTAT_PHMASK) == BSTAT_IO) + continue; + break; /* phase mismatch */ + } + + /* XXX */ + if (res > sp->scp_datalen) + { + slp->sl_error |= PDMAERR; + break; + } + + sp->scp_datalen -= res; + if (res & 1) + { + *sp->scp_data = bus_space_read_1(iot, ioh, tmc_rfifo); + sp->scp_data ++; + res --; + } + + bus_space_read_multi_2(iot, ioh, tmc_rfifo, + (u_int16_t *) sp->scp_data, res >> 1); + sp->scp_data += res; + } + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +#define WFIFO_CRIT 0x100 + +static void +stg_pio_write(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 sc_p *sp = &slp->sl_scp; + u_int res; + int s; + int tout = 0; + register u_int8_t stat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + 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); + + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (sp->scp_datalen > 0 && tout == 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if ((stat & BSTAT_PHMASK) != 0) + break; + + if (bus_space_read_2(iot, ioh, tmc_fdcnt) >= WFIFO_CRIT) + continue; + + res = (sp->scp_datalen > WFIFO_CRIT) ? + WFIFO_CRIT : sp->scp_datalen; + sp->scp_datalen -= res; + if ((res & 0x1) != 0) + { + bus_space_write_1(iot, ioh, tmc_wfifo, *sp->scp_data); + sp->scp_data ++; + res --; + } + + bus_space_write_multi_2(iot, ioh, tmc_wfifo, + (u_int16_t *) sp->scp_data, res >> 1); + sp->scp_data += res; + } + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static int +stg_negate_signal(sc, mask, s) + 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 s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t regv; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + do + { + regv = bus_space_read_1(bst, bsh, tmc_bstat); + if (regv == 0xff) { + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + } + splx(s); + return EIO; + } + } + while ((regv & mask) != 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: %s singal off timeout \n", slp->sl_xname, s); + return EIO; + } + return 0; +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +static int +stg_expect_signal(sc, phase, mask) + struct stg_softc *sc; + u_int8_t phase, 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 rv = -1; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t ph; + + phase &= BSTAT_PHMASK; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + ph = bus_space_read_1(bst, bsh, tmc_bstat); + if (ph == 0xff) { + rv = -1; + break; + } + if ((ph & BSTAT_PHMASK) != phase) { + rv = 0; + break; + } + if ((ph & mask) != 0) { + rv = 1; + break; + } + } + while (tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: stg_expect_signal timeout\n", slp->sl_xname); + rv = -1; + } + return rv; +} + +static int +stg_xfer(sc, buf, len, phase) + struct stg_softc *sc; + u_int8_t *buf; + int len; + int phase; +{ + 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 rv, ptr, atn; + + atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0); + if (phase & BSTAT_IO) + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + else + bus_space_write_1(iot, ioh, 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 && atn == 0) + { + sc->sc_busc &= ~BCTL_ATN; + stghw_bcr_write_1(sc, sc->sc_busc); + } + + if (phase & BSTAT_IO) + { + buf[ptr ++] = bus_space_read_1(iot, ioh, tmc_rdata); + } + else + { + bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]); + } + stg_negate_signal(sc, BSTAT_ACK, "xfer"); + } + +bad: + bus_space_write_1(iot, ioh, 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; + struct targ_info *ti; + u_int sid; + + if (slp->sl_selid != NULL) + { + /* XXX: + * Selection vs Reselection conflicts. + */ +#ifdef STG_STATICS + stg_statics[slp->sl_selid->ti_id].sprious_arbit_fail_0 ++; +#endif /* STG_STATICS */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + } + + /* XXX: + * We should ack the reselection as soon as possible, + * becuase the target would abort the current reselection seq + * due to reselection timeout. + */ + sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | + sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY); + + sid &= ~sc->sc_idbit; + sid = ffs(sid) - 1; + if ((ti = scsi_low_reselected(slp, sid)) == NULL) + return EJUSTRETURN; + +#ifdef STG_STATICS + stg_statics[sid].reselect ++; +#endif /* STG_STATICS */ + return EJUSTRETURN; +} + +static __inline 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); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + sc->sc_fcRinit &= ~FCTL_PARENB; + sc->sc_busc &= ~BCTL_ATN; + +#ifdef STG_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + stg_statics[ti->ti_id].disconnect ++; +#endif /* STG_STATICS */ + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static int +stg_nexus(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct lun_info *li = ti->ti_li; + struct stg_lun_info *sli = (void *) ti->ti_li; + + if (li->li_flags & SCSI_LOW_NOPARITY) + sc->sc_fcRinit &= ~FCTL_PARENB; + else + sc->sc_fcRinit |= FCTL_PARENB; + + bus_space_write_1(iot, ioh, tmc_ssctl, sli->sli_reg_synch); + return 0; +} + +static int +stghw_select_targ_wait(sc, id) + struct stg_softc *sc; + int id; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int wc, error = EIO; + + bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit | (1 << id)); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit & (~FCTL_INTEN)); + stghw_bcr_write_1(sc, sc->sc_busc | sc->sc_imsg | BCTL_SEL); + + for (wc = 50000; wc; wc--) + { + if (bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) + { + error = 0; + break; + } + + delay(1); + } + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + return error; +} + +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 physio_proc *pp; + struct buf *bp; + 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); + + if ((astatus & ASTAT_STATMASK) == 0) + return 0; + + if (astatus & ASTAT_SCSIRST) + { + bus_space_write_1(iot, ioh, tmc_fctl, + sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + + 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); + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, astatus); + if (stg_debug > 1) + Debugger(); + } +#endif /* STG_DEBUG */ + + /******************************************* + * reselection & nexus + *******************************************/ + if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED) + { + if (stg_reselected(sc) == EJUSTRETURN) + return 1; + } + + if ((ti = slp->sl_nexus) == NULL) + { + status = bus_space_read_1(iot, ioh, tmc_bstat); + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + return 1; + + /* XXX: + * Some scsi devices overrun scsi phase. + */ + if (stg_reselected(sc) == EJUSTRETURN) + { +#ifdef STG_STATICS + if ((ti = slp->sl_nexus) != NULL) + stg_statics[ti->ti_id].sprious_arbit_fail_1 ++; +#endif /* STG_STATICS */ + return 1; + } + } + + if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART && + (sc->sc_fcRinit & FCTL_PARENB) != 0) + { + slp->sl_error |= PARITYERR; + if (ti->ti_phase == PH_MSGIN) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1); + 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) + goto arb_fail; + + status = bus_space_read_1(iot, ioh, tmc_bstat); + if ((status & BSTAT_IO) != 0) + { + /* XXX: + * Selection vs Reselection conflicts. + */ +#ifdef STG_STATICS + stg_statics[ti->ti_id].sprious_arbit_fail_2 ++; +#endif /* STG_STATICS */ +arb_fail: + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + scsi_low_clear_nexus(slp, ti); + return 1; + } + + /* + * selection assert start. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + scsi_low_arbit_win(slp, ti); +#ifdef STG_ALT_SELECTION + bus_space_write_1(iot, ioh, tmc_scsiid, + sc->sc_idbit | (1 << ti->ti_id)); + /* assert busy */ + stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc); + /* arb flag clear */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + /* assert sel */ + stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc | BCTL_SEL); + delay(3); + /* deassert busy */ + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); +#else /* !STG_ALT_SELECTION */ + bus_space_write_1(iot, ioh, tmc_scsiid, + sc->sc_idbit | (1 << ti->ti_id)); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); +#endif /* !STG_ALT_SELECTION */ + return 1; + + case PH_SELSTART: + if ((status & BSTAT_BSY) == 0) + { + if (stghw_select_targ_wait(sc, ti->ti_id) != 0) + { + return stg_disconnected(sc, ti); + } + } + + /* + * attention assert. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | + FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc); + SCSI_LOW_TARGET_ASSERT_ATN(ti); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + return 1; + + case PH_RESEL: + /* clear a busy line */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_busc); + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + break; + } + + /******************************************* + * scsi seq + *******************************************/ + if (slp->sl_flags & HW_PDMASTART) + stg_pdma_end(sc, ti); + + switch (status & PHASE_MASK) + { + case COMMAND_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + if (stg_xfer(sc, slp->sl_scp.scp_cmd, + slp->sl_scp.scp_cmdlen, COMMAND_PHASE) != 0) + { + printf("%s: MSGOUT short\n", slp->sl_xname); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0); + } + break; + + case DATA_OUT_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + break; + + pp = physio_proc_enter(bp); + stg_pio_write(sc, ti); + physio_proc_leave(pp); + break; + + case DATA_IN_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + break; + + pp = physio_proc_enter(bp); + stg_pio_read(sc, ti); + physio_proc_leave(pp); + break; + + case STATUS_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); + ti->ti_status = bus_space_read_1(iot, ioh, tmc_rdata); + break; + + case MESSAGE_OUT_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); + len = scsi_low_msgout(slp, ti); + if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE)) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0); + printf("%s: MSGOUT short\n", slp->sl_xname); + } + break; + + case MESSAGE_IN_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + + /* confirm REQ signal */ + regv = stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ); + if (regv <= 0) + { + printf("%s: MSGIN: no req\n", slp->sl_xname); + break; + } + /* read data with NOACK */ + regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_sdna); + + scsi_low_msgin(slp, ti, regv); + + /* read data with ACK */ + if (regv != bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_rdata)) + { + printf("%s: MSGIN: data mismatch\n", slp->sl_xname); + } + + if (slp->sl_msgphase != 0) + { + stg_negate_signal(sc, BSTAT_ACK, "discon"); + return stg_disconnected(sc, ti); + } + break; + + case BUSFREE_PHASE: + printf("%s unexpected disconnection\n", slp->sl_xname); + return stg_disconnected(sc, ti); + + default: + printf("%s unknown phase bus %x intr %x\n", + slp->sl_xname, status, astatus); + break; + } + + return 1; +} Property changes on: stable/4/sys/dev/stg/tmc18c30.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/stg/tmc18c30reg.h =================================================================== --- stable/4/sys/dev/stg/tmc18c30reg.h (nonexistent) +++ stable/4/sys/dev/stg/tmc18c30reg.h (revision 67524) @@ -0,0 +1,144 @@ +/* $FreeBSD$ */ +/* $NecBSD: tmc18c30reg.h,v 1.4 1998/03/14 07:05:23 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. 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 _TMC18C30REG_H_ +#define _TMC18C30REG_H_ + +#define tmc_wdata 0x00 +#define tmc_rdata 0x00 + +#define tmc_bctl 0x01 +#define BCTL_BUSFREE 0x00 +#define BCTL_RST 0x01 +#define BCTL_SEL 0x02 +#define BCTL_BSY 0x04 +#define BCTL_ATN 0x08 +#define BCTL_IO 0x10 +#define BCTL_CD 0x20 +#define BCTL_MSG 0x40 +#define BCTL_BUSEN 0x80 +#define tmc_bstat 0x01 +#define BSTAT_BSY 0x01 +#define BSTAT_MSG 0x02 +#define BSTAT_IO 0x04 +#define BSTAT_CMD 0x08 +#define BSTAT_REQ 0x10 +#define BSTAT_SEL 0x20 +#define BSTAT_ACK 0x40 +#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD) + +#define tmc_ictl 0x02 +#define ICTL_FIFO 0x10 +#define ICTL_ARBIT 0x20 +#define ICTL_SEL 0x40 +#define ICTL_CD 0x80 +#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL) +#define tmc_astat 0x02 +#define ASTAT_INT 0x01 +#define ASTAT_ARBIT 0x02 +#define ASTAT_PARERR 0x04 +#define ASTAT_SCSIRST 0x08 +#define ASTAT_STATMASK 0x0f +#define ASTAT_FIFODIR 0x10 +#define ASTAT_FIFOEN 0x20 +#define ASTAT_PARENB 0x40 +#define ASTAT_BUSEN 0x80 + +#define tmc_ssctl 0x03 +#define SSCTL_FSYNCHEN 0x40 +#define SSCTL_SYNCHEN 0x80 +#define tmc_fstat 0x03 + +#define tmc_fctl 0x04 +#define FCTL_CLRFIFO 0x01 +#define FCTL_ARBIT 0x04 +#define FCTL_PARENB 0x08 +#define FCTL_INTEN 0x10 +#define FCTL_CLRINT 0x20 +#define FCTL_FIFOW 0x40 +#define FCTL_FIFOEN 0x80 +#define tmc_icnd 0x04 + +#define tmc_mctl 0x05 +#define tmc_idlsb 0x05 + +#define tmc_idmsb 0x06 + +#define tmc_wlb 0x07 +#define tmc_rlb 0x07 + +#define tmc_scsiid 0x08 +#define tmc_sdna 0x08 + +#define tmc_istat 0x09 +#define ISTAT_INTEN 0x08 +#define ISTAT_FIFO 0x10 +#define ISTAT_ARBIT 0x20 +#define ISTAT_SEL 0x40 +#define ISTAT_CD 0x80 + +#define tmc_cfg1 0x0a + +#define tmc_ioctl 0x0b +#define tmc_cfg2 0x0b + +#define tmc_wfifo 0x0c +#define tmc_rfifo 0x0c + +#define tmc_fdcnt 0x0e + +/* Information transfer phases */ +#define BUSFREE_PHASE 0x00 +#define DATA_OUT_PHASE (BSTAT_BSY) +#define DATA_IN_PHASE (BSTAT_BSY|BSTAT_IO) +#define COMMAND_PHASE (BSTAT_CMD|BSTAT_BSY) +#define STATUS_PHASE (BSTAT_CMD|BSTAT_BSY|BSTAT_IO) +#define MESSAGE_OUT_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY) +#define MESSAGE_IN_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY|BSTAT_IO) + +#define PHASE_RESELECTED (BSTAT_SEL|BSTAT_IO) + +#define PHASE_MASK 0x2f +#define RESEL_PHASE_MASK 0x2e + +/* chip type */ +#define TMCCHIP_UNK 0x00 +#define TMCCHIP_1800 0x01 +#define TMCCHIP_18C50 0x02 +#define TMCCHIP_18C30 0x03 + +#define STGIOSZ 0x10 + +#endif /* !_TMC18C30REG_H_ */ Property changes on: stable/4/sys/dev/stg/tmc18c30reg.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/dev/stg/tmc18c30var.h =================================================================== --- stable/4/sys/dev/stg/tmc18c30var.h (nonexistent) +++ stable/4/sys/dev/stg/tmc18c30var.h (revision 67524) @@ -0,0 +1,99 @@ +/* $FreeBSD$ */ +/* $NecBSD: tmc18c30var.h,v 1.12 1998/11/30 00:08:30 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + */ + +#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; + + void *sc_ih; + + u_int sc_chip; /* chip type */ + u_int sc_fsz; /* fifo size */ + u_int sc_idbit; /* host id bit */ + u_int8_t sc_fcb; /* fifo intr thread */ + + u_int8_t sc_fcWinit; /* write flags */ + u_int8_t sc_fcRinit; /* read flags */ + + u_int8_t sc_fcsp; /* special control 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 */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *stg_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct stg_lun_info { + struct lun_info sli_li; /* generic data */ + + u_int8_t sli_reg_synch; /* synch register per lun */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int stgprobesubr __P((bus_space_tag_t, bus_space_handle_t, u_int)); +void stgattachsubr __P((struct stg_softc *)); +int stgprint __P((void *, const char *)); +int stgintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_TMC18C30VAR_H_ */ Property changes on: stable/4/sys/dev/stg/tmc18c30var.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/i386/include/physio_proc.h =================================================================== --- stable/4/sys/i386/include/physio_proc.h (nonexistent) +++ stable/4/sys/i386/include/physio_proc.h (revision 67524) @@ -0,0 +1,89 @@ +/* $FreeBSD$ */ +/* $NecBSD: physio_proc.h,v 3.4 1999/07/23 20:47:03 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [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. + */ +#ifndef _I386_PHYSIO_PROC_H_ +#define _I386_PHYSIO_PROC_H_ +#include +#include + +struct physio_proc; +TAILQ_HEAD(physio_proc_head, physio_proc); +struct physio_proc_head physio_proc_freet, physio_proc_busyt; + +struct physio_proc { + TAILQ_ENTRY(physio_proc) pp_chain; + struct proc *pp_proc; +}; + +static __inline struct physio_proc *physio_proc_enter __P((struct buf *)); +static __inline void physio_proc_leave __P((struct physio_proc *)); + +static __inline struct physio_proc * +physio_proc_enter(bp) + struct buf *bp; +{ + struct physio_proc *pp; + int s; + + if (bp == NULL || (bp->b_flags & B_PHYS) == 0) + return NULL; + if ((pp = physio_proc_freet.tqh_first) == NULL) + return NULL; + + s = splstatclock(); + TAILQ_REMOVE(&physio_proc_freet, pp, pp_chain); +#if !defined(__FreeBSD__) || __FreeBSD_version < 400001 + pp->pp_proc = bp->b_proc; +#endif + TAILQ_INSERT_TAIL(&physio_proc_busyt, pp, pp_chain); + splx(s); + return pp; +} + +static __inline void +physio_proc_leave(pp) + struct physio_proc *pp; +{ + int s; + + if (pp == NULL) + return; + + s = splstatclock(); + TAILQ_REMOVE(&physio_proc_busyt, pp, pp_chain); + TAILQ_INSERT_TAIL(&physio_proc_freet, pp, pp_chain); + pp->pp_proc = NULL; + splx(s); +} + +void physio_proc_init __P((void)); +#endif /* _I386_PHYSIO_PROC_H_ */ Property changes on: stable/4/sys/i386/include/physio_proc.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/4/sys/sys/device_port.h =================================================================== --- stable/4/sys/sys/device_port.h (nonexistent) +++ stable/4/sys/sys/device_port.h (revision 67524) @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 1999 Mitsuru IWASAKI + * Copyright (c) 1999 Takanori Watanabe + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#if defined(__NetBSD__) +# include +#elif defined(__FreeBSD__) +# if __FreeBSD_version >= 400001 +# include +# include +# else +# include +# endif +#endif + +/* + * Macro's to cope with the differences between operating systems and versions. + */ + +#if defined(__NetBSD__) +# define DEVPORT_DEVICE struct device +# define DEVPORT_DEVNAME(dev) (dev).dv_xname +# define DEVPORT_DEVUNIT(dev) (dev).dv_unit + +#elif defined(__FreeBSD__) +/* + * FreeBSD (compatibility for struct device) + */ +#if __FreeBSD_version >= 400001 +# define DEVPORT_DEVICE device_t +# define DEVPORT_DEVNAME(dev) device_get_name(dev) +# define DEVPORT_DEVUNIT(dev) device_get_unit(dev) +# define DEVPORT_ALLOC_SOFTC(dev) device_get_softc(dev) +# define DEVPORT_GET_SOFTC(dev) device_get_softc(dev) + +# define UNCONF 1 /* print " not configured\n" */ + +#else + +# define DEVPORT_DEVICE struct device +# define DEVPORT_DEVNAME(dev) (dev).dv_xname +# define DEVPORT_DEVUNIT(dev) (dev).dv_unit +# ifdef DEVPORT_ALLOCSOFTCFUNC +# define DEVPORT_ALLOC_SOFTC(dev) (DEVPORT_ALLOCSOFTCFUNC)((dev).dv_unit) +# else +# define DEVPORT_ALLOC_SOFTC(dev) DEVPORT_ALLOCSOFTCFUNC_is_not_defined_prior_than_device_port_h +# endif +# ifdef DEVPORT_SOFTCARRAY +# define DEVPORT_GET_SOFTC(dev) (DEVPORT_SOFTCARRAY)[(dev).dv_unit] +# else +# define DEVPORT_GET_SOFTC(dev) DEVPORT_SOFTCARRAY_is_not_defined_prior_than_device_port_h +# endif + +#endif + +/* + * PC-Card device driver (compatibility for struct pccard_devinfo *) + */ +#if __FreeBSD_version >= 400001 +# define DEVPORT_PDEVICE device_t +# define DEVPORT_PDEVUNIT(pdev) device_get_unit(pdev) +# define DEVPORT_PDEVFLAGS(pdev) device_get_flags(pdev) +# define DEVPORT_PDEVIOBASE(pdev) bus_get_resource_start(pdev, SYS_RES_IOPORT, 0) +# define DEVPORT_PDEVIRQ(pdev) bus_get_resource_start(pdev, SYS_RES_IRQ, 0) +# define DEVPORT_PDEVMADDR(pdev) bus_get_resource_start(pdev, SYS_RES_MEMORY, 0) +# define DEVPORT_PDEVALLOC_SOFTC(pdev) device_get_softc(pdev) +# define DEVPORT_PDEVGET_SOFTC(pdev) device_get_softc(pdev) + +#else + +# define DEVPORT_PDEVICE struct pccard_devinfo * +# define DEVPORT_PDEVUNIT(pdev) (pdev)->pd_unit +# define DEVPORT_PDEVFLAGS(pdev) (pdev)->pd_flags +# define DEVPORT_PDEVIOBASE(pdev) (pdev)->pd_iobase +# define DEVPORT_PDEVIRQ(pdev) (pdev)->pd_irq +# define DEVPORT_PDEVMADDR(pdev) (pdev)->pd_maddr +# ifdef DEVPORT_ALLOCSOFTCFUNC +# define DEVPORT_PDEVALLOC_SOFTC(pdev) (DEVPORT_ALLOCSOFTCFUNC)((pdev)->pd_unit) +# else +# define DEVPORT_PDEVALLOC_SOFTC(pdev) DEVPORT_ALLOCSOFTCFUNC_is_not_defined_prior_than_device_port_h +# endif +# ifdef DEVPORT_SOFTCARRAY +# define DEVPORT_PDEVGET_SOFTC(pdev) (DEVPORT_SOFTCARRAY)[(pdev)->pd_unit] +# else +# define DEVPORT_PDEVGET_SOFTC(pdev) DEVPORT_SOFTCARRAY_is_not_defined_prior_than_device_port_h +# endif +#endif + +#endif /* __FreeBSD__ */ + Property changes on: stable/4/sys/sys/device_port.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property