/* $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_ */