scsi_low.c revision 71999
167468Snon/* $FreeBSD: head/sys/cam/scsi/scsi_low.c 71999 2001-02-04 13:13:25Z phk $ */ 267468Snon/* $NecBSD: scsi_low.c,v 1.24 1999/07/26 06:27:01 honda Exp $ */ 367468Snon/* $NetBSD$ */ 467468Snon 567468Snon#define SCSI_LOW_STATICS 667468Snon#define SCSI_LOW_WARNINGS 767468Snon#ifdef __NetBSD__ 867468Snon#define SCSI_LOW_TARGET_OPEN 967468Snon#define SCSI_LOW_INFORM 1067468Snon#endif 1167468Snon#ifdef __FreeBSD__ 1267468Snon#define CAM 1367468Snon#endif 1467468Snon 1567468Snon/* 1667468Snon * [NetBSD for NEC PC-98 series] 1767468Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999 1867468Snon * NetBSD/pc98 porting staff. All rights reserved. 1967468Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999 2067468Snon * Naofumi HONDA. All rights reserved. 2167468Snon * 2267468Snon * Redistribution and use in source and binary forms, with or without 2367468Snon * modification, are permitted provided that the following conditions 2467468Snon * are met: 2567468Snon * 1. Redistributions of source code must retain the above copyright 2667468Snon * notice, this list of conditions and the following disclaimer. 2767468Snon * 2. Redistributions in binary form must reproduce the above copyright 2867468Snon * notice, this list of conditions and the following disclaimer in the 2967468Snon * documentation and/or other materials provided with the distribution. 3067468Snon * 3. The name of the author may not be used to endorse or promote products 3167468Snon * derived from this software without specific prior written permission. 3267468Snon * 3367468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 3467468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 3567468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 3667468Snon * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 3767468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3867468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3967468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4067468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4167468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 4267468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4367468Snon * POSSIBILITY OF SUCH DAMAGE. 4467468Snon */ 4567468Snon 4667468Snon/* <On the nexus establishment> 4767468Snon * When our host is reselected, 4867468Snon * nexus establish processes are little complicated. 4967468Snon * Normal steps are followings: 5067468Snon * 1) Our host selected by target => target nexus (slp->sl_nexus) 5167468Snon * 2) Identify msgin => lun nexus (ti->ti_li) 5267468Snon * 3) Qtag msg => slccb nexus (ti->ti_nexus) 5367468Snon */ 5467468Snon#include "opt_ddb.h" 5567468Snon 5667468Snon#include <sys/param.h> 5767468Snon#include <sys/systm.h> 5867468Snon#include <sys/kernel.h> 5967964Snon#ifdef __NetBSD__ 6067468Snon#include <sys/disklabel.h> 6167964Snon#endif 6267468Snon#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 6367468Snon#include <sys/bio.h> 6469979Snon#include <sys/devicestat.h> 6567468Snon#endif 6667468Snon#include <sys/buf.h> 6767468Snon#include <sys/queue.h> 6867468Snon#include <sys/malloc.h> 6967468Snon#include <sys/device_port.h> 7067468Snon#include <sys/errno.h> 7167468Snon 7267964Snon#ifdef __NetBSD__ 7367468Snon#include <vm/vm.h> 7467468Snon 7567468Snon#include <machine/bus.h> 7667468Snon#include <machine/intr.h> 7767468Snon#include <machine/dvcfg.h> 7867468Snon 7967468Snon#include <dev/cons.h> 8067468Snon 8167468Snon#include <dev/scsipi/scsipi_all.h> 8267468Snon#include <dev/scsipi/scsipiconf.h> 8367468Snon#include <dev/scsipi/scsipi_disk.h> 8467468Snon#include <dev/scsipi/scsi_all.h> 8567468Snon#include <dev/scsipi/scsiconf.h> 8667468Snon 8767468Snon#include <i386/Cbus/dev/scsi_low.h> 8867468Snon#endif 8967468Snon#ifdef __FreeBSD__ 9067468Snon#include <cam/cam.h> 9167468Snon#include <cam/cam_ccb.h> 9267468Snon#include <cam/cam_sim.h> 9367468Snon#include <cam/cam_debug.h> 9467468Snon#include <cam/cam_periph.h> 9567468Snon 9667468Snon#include <cam/scsi/scsi_all.h> 9767468Snon 9867468Snon#include <cam/scsi/scsi_low.h> 9967468Snon 10067468Snon#if !defined(__FreeBSD__) || __FreeBSD_version < 400001 10167468Snon#include <i386/i386/cons.h> 10267468Snon#else 10367468Snon#include <sys/cons.h> 10467468Snon#endif 10567468Snon#define delay(time) DELAY(time) 10667468Snon 10767468Snon/* from sys/dev/usb/usb_port.h 10867468Snon XXX Change this when FreeBSD has memset 10967468Snon */ 11067468Snon#define memset(d, v, s) \ 11167468Snon do{ \ 11267468Snon if ((v) == 0) \ 11367468Snon bzero((d), (s)); \ 11467468Snon else \ 11567468Snon panic("Non zero filler for memset, cannot handle!"); \ 11667468Snon } while (0) 11767468Snon#endif 11867468Snon 11967468Snon#define SCSI_LOW_DONE_COMPLETE 0 12067468Snon#define SCSI_LOW_DONE_RETRY 1 12167468Snon 12267468Snonstatic void scsi_low_engage __P((void *)); 12367468Snonstatic void scsi_low_info __P((struct scsi_low_softc *, struct targ_info *, u_char *)); 12467468Snonstatic void scsi_low_init_msgsys __P((struct scsi_low_softc *, struct targ_info *)); 12567468Snonstatic struct slccb *scsi_low_establish_ccb __P((struct targ_info *, struct lun_info *, scsi_low_tag_t)); 12667468Snonstatic int scsi_low_done __P((struct scsi_low_softc *, struct slccb *)); 12767468Snonstatic void scsi_low_twiddle_wait __P((void)); 12867468Snonstatic struct lun_info *scsi_low_alloc_li __P((struct targ_info *, int, int)); 12967468Snonstatic struct targ_info *scsi_low_alloc_ti __P((struct scsi_low_softc *, int)); 13067468Snonstatic void scsi_low_calcf __P((struct targ_info *, struct lun_info *)); 13167468Snonstatic struct lun_info *scsi_low_establish_lun __P((struct targ_info *, int)); 13267468Snon#ifndef CAM 13367468Snonstatic void scsi_low_scsi_minphys __P((struct buf *)); 13467468Snon#endif 13567468Snon#ifdef SCSI_LOW_TARGET_OPEN 13667468Snonstatic int scsi_low_target_open __P((struct scsipi_link *, struct cfdata *)); 13767468Snon#endif /* SCSI_LOW_TARGET_OPEN */ 13867468Snon#ifdef CAM 13967468Snonvoid scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb); 14067468Snonstatic void scsi_low_poll (struct cam_sim *sim); 14167468Snon#else 14267468Snonstatic int scsi_low_scsi_cmd __P((struct scsipi_xfer *)); 14367468Snon#endif 14467468Snonstatic void scsi_low_reset_nexus __P((struct scsi_low_softc *, int)); 14567468Snonstatic int scsi_low_init __P((struct scsi_low_softc *, u_int)); 14667468Snonstatic void scsi_low_start __P((struct scsi_low_softc *)); 14767468Snonstatic void scsi_low_free_ti __P((struct scsi_low_softc *)); 14867468Snonstatic void scsi_low_clear_ccb __P((struct slccb *)); 14967468Snon 15067468Snon#ifdef SCSI_LOW_STATICS 15167468Snonstruct scsi_low_statics { 15267468Snon int nexus_win; 15367468Snon int nexus_fail; 15467468Snon int nexus_disconnected; 15567468Snon int nexus_reselected; 15667468Snon int nexus_conflict; 15767468Snon} scsi_low_statics; 15867468Snon#endif /* SCSI_LOW_STATICS */ 15967468Snon/************************************************************** 16067468Snon * power control 16167468Snon **************************************************************/ 16267468Snonstatic void 16367468Snonscsi_low_engage(arg) 16467468Snon void *arg; 16567468Snon{ 16667468Snon struct scsi_low_softc *slp = arg; 16767468Snon int s = splbio(); 16867468Snon 16967468Snon switch (slp->sl_rstep) 17067468Snon { 17167468Snon case 0: 17267468Snon slp->sl_rstep ++; 17367468Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 17467468Snon#ifdef __FreeBSD__ 17567468Snon slp->engage_ch = 17667468Snon#endif 17767468Snon timeout(scsi_low_engage, slp, 1); 17867468Snon break; 17967468Snon 18067468Snon case 1: 18167468Snon slp->sl_rstep ++; 18267468Snon slp->sl_flags &= ~HW_RESUME; 18367468Snon scsi_low_start(slp); 18467468Snon break; 18567468Snon 18667468Snon case 2: 18767468Snon break; 18867468Snon } 18967468Snon splx(s); 19067468Snon} 19167468Snon 19267468Snonstatic int 19367468Snonscsi_low_init(slp, flags) 19467468Snon struct scsi_low_softc *slp; 19567468Snon u_int flags; 19667468Snon{ 19767468Snon 19867468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 19967468Snon { 20067468Snon#ifdef __FreeBSD__ 20167468Snon untimeout(scsi_low_engage, slp, slp->engage_ch); 20267468Snon#else /* NetBSD */ 20367468Snon untimeout(scsi_low_engage, slp); 20467468Snon#endif 20567468Snon slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); 20667468Snon slp->sl_active = 1; 20767468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 20867468Snon } 20967468Snon 21067468Snon /* reset current nexus */ 21167468Snon scsi_low_reset_nexus(slp, flags); 21267468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 21367468Snon return EBUSY; 21467468Snon 21567468Snon if (flags == SCSI_LOW_RESTART_SOFT) 21667468Snon return 0; 21767468Snon 21867468Snon return ((*slp->sl_funcs->scsi_low_init) (slp, flags)); 21967468Snon} 22067468Snon 22167468Snon/************************************************************** 22267468Snon * allocate lun_info 22367468Snon **************************************************************/ 22467468Snonstatic struct lun_info * 22567468Snonscsi_low_alloc_li(ti, lun, alloc) 22667468Snon struct targ_info *ti; 22767468Snon int lun; 22867468Snon int alloc; 22967468Snon{ 23067468Snon struct scsi_low_softc *slp = ti->ti_sc; 23167468Snon struct lun_info *li; 23267468Snon 23367468Snon li = LIST_FIRST(&ti->ti_litab); 23467468Snon if (li != NULL) 23567468Snon { 23667468Snon if (li->li_lun == lun) 23767468Snon return li; 23867468Snon 23967468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 24067468Snon { 24167468Snon if (li->li_lun == lun) 24267468Snon { 24367468Snon LIST_REMOVE(li, lun_chain); 24467468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 24567468Snon return li; 24667468Snon } 24767468Snon } 24867468Snon } 24967468Snon 25067468Snon if (alloc == 0) 25167468Snon return li; 25267468Snon 25367468Snon li = malloc(ti->ti_lunsize, M_DEVBUF, M_NOWAIT); 25467468Snon if (li == NULL) 25567468Snon panic("no lun info mem\n"); 25667468Snon 25767468Snon memset(li, 0, ti->ti_lunsize); 25867468Snon li->li_lun = lun; 25967468Snon li->li_ti = ti; 26067468Snon#if defined(SDEV_NOPARITY) && defined(SDEV_NODISC) 26167468Snon li->li_quirks = SDEV_NOPARITY | SDEV_NODISC; 26267468Snon#endif /* SDEV_NOPARITY && SDEV_NODISC */ 26367468Snon li->li_cfgflags = 0xffff0000 | SCSI_LOW_SYNC; 26467468Snon 26567468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 26667468Snon 26767468Snon /* host specific structure initialization per lun */ 26867468Snon (void) ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li)); 26967468Snon 27067468Snon return li; 27167468Snon} 27267468Snon 27367468Snon/************************************************************** 27467468Snon * allocate targ_info 27567468Snon **************************************************************/ 27667468Snonstatic struct targ_info * 27767468Snonscsi_low_alloc_ti(slp, targ) 27867468Snon struct scsi_low_softc *slp; 27967468Snon int targ; 28067468Snon{ 28167468Snon struct targ_info *ti; 28267468Snon 28371999Sphk if (TAILQ_FIRST(&slp->sl_titab) == NULL) 28467468Snon TAILQ_INIT(&slp->sl_titab); 28567468Snon 28667468Snon ti = malloc(sizeof(struct targ_info), M_DEVBUF, M_NOWAIT); 28767468Snon if (ti == NULL) 28867468Snon panic("%s short of memory\n", slp->sl_xname); 28967468Snon 29067468Snon memset(ti, 0, sizeof(struct targ_info)); 29167468Snon ti->ti_id = targ; 29267468Snon ti->ti_sc = slp; 29367468Snon 29467468Snon slp->sl_ti[targ] = ti; 29567468Snon TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); 29667468Snon TAILQ_INIT(&ti->ti_discq); 29767468Snon LIST_INIT(&ti->ti_litab); 29867468Snon 29967468Snon return ti; 30067468Snon} 30167468Snon 30267468Snonstatic void 30367468Snonscsi_low_free_ti(slp) 30467468Snon struct scsi_low_softc *slp; 30567468Snon{ 30667468Snon struct targ_info *ti, *tib; 30767468Snon struct lun_info *li, *nli; 30867468Snon 30971999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) 31067468Snon { 31171999Sphk tib = TAILQ_NEXT(ti, ti_chain); 31267468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) 31367468Snon { 31467468Snon nli = LIST_NEXT(li, lun_chain); 31567468Snon free(li, M_DEVBUF); 31667468Snon } 31767468Snon free(ti, M_DEVBUF); 31867468Snon } 31967468Snon} 32067468Snon 32167468Snon/************************************************************** 32267468Snon * timeout 32367468Snon **************************************************************/ 32467468Snonvoid 32567468Snonscsi_low_timeout(arg) 32667468Snon void *arg; 32767468Snon{ 32867468Snon struct scsi_low_softc *slp = arg; 32967468Snon struct targ_info *ti; 33067468Snon struct slccb *cb = NULL; /* XXX */ 33167468Snon int s = splbio(); 33267468Snon 33367468Snon /* check */ 33467468Snon if ((ti = slp->sl_nexus) != NULL && (cb = ti->ti_nexus) != NULL) 33567468Snon { 33667468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 33767468Snon if (cb->ccb_tc < 0) 33867468Snon goto bus_reset; 33967468Snon } 34067468Snon else if (slp->sl_disc > 0) 34167468Snon { 34267468Snon struct targ_info *ti; 34367468Snon 34471999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 34571999Sphk ti = TAILQ_NEXT(ti, ti_chain)) 34667468Snon { 34771999Sphk for (cb = TAILQ_FIRST(&ti->ti_discq); cb != NULL; 34871999Sphk cb = TAILQ_NEXT(cb, ccb_chain)) 34967468Snon { 35067468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 35167468Snon if (cb->ccb_tc < 0) 35267468Snon goto bus_reset; 35367468Snon } 35467468Snon } 35567468Snon } 35667468Snon else 35767468Snon { 35871999Sphk cb = TAILQ_FIRST(&slp->sl_start); 35967468Snon if (cb != NULL) 36067468Snon { 36167468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 36267468Snon if (cb->ccb_tc < 0) 36367468Snon goto bus_reset; 36467468Snon } 36567468Snon else if ((slp->sl_flags & HW_POWERCTRL) != 0) 36667468Snon { 36767468Snon if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) 36867468Snon goto out; 36967468Snon 37067468Snon if (slp->sl_active != 0) 37167468Snon { 37267468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 37367468Snon slp->sl_active = 0; 37467468Snon goto out; 37567468Snon } 37667468Snon 37767468Snon slp->sl_powc --; 37867468Snon if (slp->sl_powc < 0) 37967468Snon { 38067468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 38167468Snon slp->sl_flags |= HW_POWDOWN; 38267468Snon (*slp->sl_funcs->scsi_low_power) 38367468Snon (slp, SCSI_LOW_POWDOWN); 38467468Snon } 38567468Snon } 38667468Snon } 38767468Snon 38867468Snonout: 38967468Snon#ifdef __FreeBSD__ 39067468Snon slp->timeout_ch = 39167468Snon#endif 39267468Snon timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); 39367468Snon 39467468Snon splx(s); 39567468Snon return; 39667468Snon 39767468Snonbus_reset: 39867468Snon cb->ccb_error |= TIMEOUTIO; 39967468Snon scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); 40067468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 40167468Snon scsi_low_start(slp); 40267468Snon#ifdef __FreeBSD__ 40367468Snon slp->timeout_ch = 40467468Snon#endif 40567468Snon timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); 40667468Snon 40767468Snon splx(s); 40867468Snon} 40967468Snon 41067468Snon/************************************************************** 41167468Snon * CCB 41267468Snon **************************************************************/ 41367468SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) 41467468SnonGENERIC_CCB(scsi_low, slccb, ccb_chain) 41567468Snon 41667468Snon/************************************************************** 41767468Snon * SCSI INTERFACE (XS) 41867468Snon **************************************************************/ 41967468Snon#define SCSI_LOW_MINPHYS 0x10000 42067468Snon 42167468Snon#ifdef __NetBSD__ 42267468Snonstruct scsipi_device scsi_low_dev = { 42367468Snon NULL, /* Use default error handler */ 42467468Snon NULL, /* have a queue, served by this */ 42567468Snon NULL, /* have no async handler */ 42667468Snon NULL, /* Use default 'done' routine */ 42767468Snon}; 42867468Snon#endif 42967468Snon 43067468Snon#ifdef CAM 43167468Snonstatic void 43267468Snonscsi_low_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) 43367468Snon{ 43467468Snon xpt_free_path(ccb->ccb_h.path); 43567468Snon free(ccb, M_DEVBUF); 43667468Snon#if defined(__FreeBSD__) && __FreeBSD_version < 400001 43767468Snon free(periph, M_DEVBUF); 43867468Snon#endif 43967468Snon} 44067468Snon 44167468Snonstatic void 44267468Snonscsi_low_rescan_bus(struct scsi_low_softc *slp) 44367468Snon{ 44467468Snon struct cam_path *path; 44567468Snon union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK); 44667468Snon#if defined(__FreeBSD__) && __FreeBSD_version < 400001 44767468Snon struct cam_periph *xpt_periph = malloc(sizeof(struct cam_periph), 44867468Snon M_DEVBUF, M_WAITOK); 44967468Snon#endif 45067468Snon cam_status status; 45167468Snon 45267468Snon bzero(ccb, sizeof(union ccb)); 45367468Snon 45467468Snon status = xpt_create_path(&path, xpt_periph, 45567468Snon cam_sim_path(slp->sim), -1, 0); 45667468Snon if (status != CAM_REQ_CMP) 45767468Snon return; 45867468Snon 45967468Snon xpt_setup_ccb(&ccb->ccb_h, path, 5); 46067468Snon ccb->ccb_h.func_code = XPT_SCAN_BUS; 46167468Snon ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; 46267468Snon ccb->crcn.flags = CAM_FLAG_NONE; 46367468Snon xpt_action(ccb); 46467468Snon} 46567468Snon#endif 46667468Snon 46767468Snonint 46867468Snonscsi_low_attach(slp, openings, ntargs, nluns, lunsize) 46967468Snon struct scsi_low_softc *slp; 47067468Snon int openings, ntargs, nluns, lunsize; 47167468Snon{ 47267468Snon struct targ_info *ti; 47367468Snon struct lun_info *li; 47467468Snon#ifdef CAM 47567468Snon struct cam_devq *devq; 47667468Snon#else 47767468Snon struct scsipi_adapter *sap; 47867468Snon#endif 47967468Snon int i, nccb; 48067468Snon 48167468Snon#ifdef CAM 48267468Snon OS_DEPEND(sprintf(slp->sl_xname, "%s%d", 48367468Snon DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev))); 48467468Snon#else 48567468Snon OS_DEPEND(strncpy(slp->sl_xname, DEVPORT_DEVNAME(slp->sl_dev), 16)); 48667468Snon#endif 48767468Snon if (ntargs > SCSI_LOW_NTARGETS) 48867468Snon { 48967468Snon printf("scsi_low: %d targets are too large\n", ntargs); 49067468Snon printf("change kernel options SCSI_LOW_NTARGETS"); 49167468Snon } 49267468Snon 49367468Snon if (lunsize < sizeof(struct lun_info)) 49467468Snon lunsize = sizeof(struct lun_info); 49567468Snon 49667468Snon for (i = 0; i < ntargs; i ++) 49767468Snon { 49867468Snon ti = scsi_low_alloc_ti(slp, i); 49967468Snon ti->ti_lunsize = lunsize; 50067468Snon li = scsi_low_alloc_li(ti, 0, 1); 50167468Snon } 50267468Snon 50367468Snon#ifndef CAM 50467468Snon sap = malloc(sizeof(*sap), M_DEVBUF, M_NOWAIT); 50567468Snon if (sap == NULL) 50667468Snon return ENOMEM; 50767468Snon 50867468Snon memset(sap, 0, sizeof(*sap)); 50967468Snon sap->scsipi_cmd = scsi_low_scsi_cmd; 51067468Snon sap->scsipi_minphys = scsi_low_scsi_minphys; 51167468Snon#ifdef SCSI_LOW_TARGET_OPEN 51267468Snon sap->open_target_lu = scsi_low_target_open; 51367468Snon#endif /* SCSI_LOW_TARGET_OPEN */ 51467468Snon#endif 51567468Snon 51667468Snon if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) 51767468Snon return EINVAL; 51867468Snon 51967468Snon /* initialize queue */ 52067468Snon nccb = openings * (ntargs - 1); 52167468Snon if (nccb >= SCSI_LOW_NCCB || nccb <= 0) 52267468Snon nccb = SCSI_LOW_NCCB; 52367468Snon scsi_low_init_ccbque(nccb); 52467468Snon TAILQ_INIT(&slp->sl_start); 52567468Snon 52667468Snon slp->sl_openings = openings; 52767468Snon slp->sl_ntargs = ntargs; 52867468Snon slp->sl_nluns = nluns; 52967468Snon 53067468Snon#ifdef CAM 53167468Snon /* 53267468Snon * Prepare the scsibus_data area for the upperlevel 53367468Snon * scsi code. 53467468Snon */ 53567468Snon devq = cam_simq_alloc(256/*MAX_START*/); 53667468Snon if (devq == NULL) 53767468Snon return (0); 53867468Snon /* scbus->adapter_link = &slp->sc_link; */ 53967468Snon /* 54067468Snon * ask the adapter what subunits are present 54167468Snon */ 54267468Snon 54367468Snon slp->sim = cam_sim_alloc(scsi_low_scsi_action, scsi_low_poll, 54467468Snon DEVPORT_DEVNAME(slp->sl_dev), slp, 54567468Snon DEVPORT_DEVUNIT(slp->sl_dev), 1, 32/*MAX_TAGS*/, devq); 54667468Snon if (slp->sim == NULL) { 54767468Snon cam_simq_free(devq); 54867468Snon return 0; 54967468Snon } 55067468Snon 55167468Snon if (xpt_bus_register(slp->sim, 0) != CAM_SUCCESS) { 55267468Snon free(slp->sim, M_DEVBUF); 55367468Snon return 0; 55467468Snon } 55567468Snon 55667468Snon if (xpt_create_path(&slp->path, /*periph*/NULL, 55767468Snon cam_sim_path(slp->sim), CAM_TARGET_WILDCARD, 55867468Snon CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 55967468Snon xpt_bus_deregister(cam_sim_path(slp->sim)); 56067468Snon cam_sim_free(slp->sim, /*free_simq*/TRUE); 56167468Snon free(slp->sim, M_DEVBUF); 56267468Snon return 0; 56367468Snon } 56467468Snon#else /* !CAM */ 56567468Snon slp->sl_link.adapter_softc = slp; 56667468Snon slp->sl_link.scsipi_scsi.adapter_target = slp->sl_hostid; 56767468Snon slp->sl_link.scsipi_scsi.max_target = ntargs - 1; 56867468Snon slp->sl_link.scsipi_scsi.max_lun = nluns - 1; 56967468Snon slp->sl_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 57067468Snon slp->sl_link.openings = openings; 57167468Snon slp->sl_link.type = BUS_SCSI; 57267468Snon slp->sl_link.adapter_softc = slp; 57367468Snon slp->sl_link.adapter = sap; 57467468Snon slp->sl_link.device = &scsi_low_dev; 57567468Snon#endif 57667468Snon 57767468Snon /* start watch dog */ 57867468Snon slp->sl_max_retry = SCSI_LOW_MAX_RETRY; 57967468Snon#ifdef __FreeBSD__ 58067468Snon slp->timeout_ch = 58167468Snon#endif 58267468Snon timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); 58367468Snon#ifdef CAM 58467468Snon if (!cold) 58567468Snon scsi_low_rescan_bus(slp); 58667468Snon#endif 58767468Snon 58867468Snon return 0; 58967468Snon} 59067468Snon 59167468Snon#ifndef CAM 59267468Snonstatic void 59367468Snonscsi_low_scsi_minphys(bp) 59467468Snon struct buf *bp; 59567468Snon{ 59667468Snon 59767468Snon if (bp->b_bcount > SCSI_LOW_MINPHYS) 59867468Snon bp->b_bcount = SCSI_LOW_MINPHYS; 59967468Snon minphys(bp); 60067468Snon} 60167468Snon#endif 60267468Snon 60367468Snonint 60467468Snonscsi_low_dettach(slp) 60567468Snon struct scsi_low_softc *slp; 60667468Snon{ 60767468Snon 60871999Sphk if (slp->sl_disc > 0 || TAILQ_FIRST(&slp->sl_start) != NULL) 60967468Snon return EBUSY; 61067468Snon 61167468Snon /* 61267468Snon * scsipi does not have dettach bus fucntion. 61367468Snon * 61467468Snon scsipi_dettach_scsibus(&slp->sl_link); 61567468Snon */ 61667468Snon 61767468Snon#ifdef CAM 61867468Snon xpt_async(AC_LOST_DEVICE, slp->path, NULL); 61967468Snon xpt_free_path(slp->path); 62067468Snon xpt_bus_deregister(cam_sim_path(slp->sim)); 62167468Snon cam_sim_free(slp->sim, /* free_devq */ TRUE); 62267468Snon#endif 62367468Snon 62467468Snon scsi_low_free_ti(slp); 62567468Snon return 0; 62667468Snon} 62767468Snon 62867468Snon#ifdef CAM 62967468Snonstatic void 63067468Snonscsi_low_poll(struct cam_sim *sim) 63167468Snon{ 63267468Snon struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); 63367468Snon (*slp->sl_funcs->scsi_low_poll) (slp); 63467468Snon} 63567468Snon 63667468Snonvoid 63767468Snonscsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb) 63867468Snon{ 63967468Snon struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); 64067468Snon int s, target = (u_int) (ccb->ccb_h.target_id); 64167468Snon struct targ_info *ti; 64267468Snon struct lun_info *li; 64367468Snon struct slccb *cb; 64467468Snon 64567468Snon#if 0 64667468Snon printf("scsi_low_scsi_action() func code %d Target: %d, LUN: %d\n", 64767468Snon ccb->ccb_h.func_code, target, ccb->ccb_h.target_lun); 64867468Snon#endif 64967468Snon switch (ccb->ccb_h.func_code) { 65067468Snon case XPT_SCSI_IO: /* Execute the requested I/O operation */ 65167468Snon if (((cb = scsi_low_get_ccb()) == NULL)) { 65267468Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 65367468Snon xpt_done(ccb); 65467468Snon return; 65567468Snon } 65667468Snon 65767468Snon cb->ccb = ccb; 65867468Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 65967468Snon cb->bp = (struct buf *)NULL; 66067468Snon cb->ti = ti = slp->sl_ti[target]; 66167468Snon cb->li = scsi_low_alloc_li(ti, ccb->ccb_h.target_lun, 1); 66267468Snon cb->ccb_flags = 0; 66367468Snon cb->ccb_rcnt = 0; 66467468Snon 66567468Snon s = splcam(); 66667468Snon 66767468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 66867468Snon 66967468Snon if (slp->sl_nexus == NULL) { 67067468Snon scsi_low_start(slp); 67167468Snon } 67267468Snon 67367468Snon splx(s); 67467468Snon break; 67567468Snon case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 67667468Snon case XPT_EN_LUN: /* Enable LUN as a target */ 67767468Snon case XPT_TARGET_IO: /* Execute target I/O request */ 67867468Snon case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 67967468Snon case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 68067468Snon case XPT_ABORT: /* Abort the specified CCB */ 68167468Snon /* XXX Implement */ 68267468Snon ccb->ccb_h.status = CAM_REQ_INVALID; 68367468Snon xpt_done(ccb); 68467468Snon break; 68567468Snon case XPT_SET_TRAN_SETTINGS: 68667468Snon /* XXX Implement */ 68767468Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 68867468Snon xpt_done(ccb); 68967468Snon break; 69067468Snon case XPT_GET_TRAN_SETTINGS: { 69167468Snon struct ccb_trans_settings *cts; 69267468Snon struct targ_info *ti; 69367468Snon int lun = ccb->ccb_h.target_lun; 69467468Snon /*int s;*/ 69567468Snon 69667468Snon cts = &ccb->cts; 69767468Snon ti = slp->sl_ti[ccb->ccb_h.target_id]; 69867468Snon li = LIST_FIRST(&ti->ti_litab); 69967468Snon if (li != NULL && li->li_lun != lun) 70067468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 70167468Snon if (li->li_lun == lun) 70267468Snon break; 70367468Snon s = splcam(); 70467468Snon if (li != NULL && (cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 70567468Snon if (li->li_cfgflags & SCSI_LOW_DISC) 70667468Snon cts->flags = CCB_TRANS_DISC_ENB; 70767468Snon else 70867468Snon cts->flags = 0; 70967468Snon if (li->li_cfgflags & SCSI_LOW_QTAG) 71067468Snon cts->flags |= CCB_TRANS_TAG_ENB; 71167468Snon 71267468Snon cts->bus_width = 0;/*HN2*/ 71367468Snon 71467468Snon cts->valid = CCB_TRANS_SYNC_RATE_VALID 71567468Snon | CCB_TRANS_SYNC_OFFSET_VALID 71667468Snon | CCB_TRANS_BUS_WIDTH_VALID 71767468Snon | CCB_TRANS_DISC_VALID 71867468Snon | CCB_TRANS_TQ_VALID; 71967468Snon ccb->ccb_h.status = CAM_REQ_CMP; 72067468Snon } else 72167468Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 72267468Snon 72367468Snon splx(s); 72467468Snon xpt_done(ccb); 72567468Snon break; 72667468Snon } 72767468Snon case XPT_CALC_GEOMETRY: { /* not yet HN2 */ 72867468Snon struct ccb_calc_geometry *ccg; 72967468Snon u_int32_t size_mb; 73067468Snon u_int32_t secs_per_cylinder; 73167468Snon int extended; 73267468Snon 73367468Snon extended = 1; 73467468Snon ccg = &ccb->ccg; 73567468Snon size_mb = ccg->volume_size 73667468Snon / ((1024L * 1024L) / ccg->block_size); 73767468Snon 73867468Snon if (size_mb > 1024 && extended) { 73967468Snon ccg->heads = 255; 74067468Snon ccg->secs_per_track = 63; 74167468Snon } else { 74267468Snon ccg->heads = 64; 74367468Snon ccg->secs_per_track = 32; 74467468Snon } 74567468Snon secs_per_cylinder = ccg->heads * ccg->secs_per_track; 74667468Snon ccg->cylinders = ccg->volume_size / secs_per_cylinder; 74767468Snon ccb->ccb_h.status = CAM_REQ_CMP; 74867468Snon xpt_done(ccb); 74967468Snon break; 75067468Snon } 75167468Snon case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 75267468Snon#if 0 75367468Snon scsi_low_bus_reset(slp); 75467468Snon#endif 75567468Snon ccb->ccb_h.status = CAM_REQ_CMP; 75667468Snon xpt_done(ccb); 75767468Snon break; 75867468Snon case XPT_TERM_IO: /* Terminate the I/O process */ 75967468Snon /* XXX Implement */ 76067468Snon ccb->ccb_h.status = CAM_REQ_INVALID; 76167468Snon xpt_done(ccb); 76267468Snon break; 76367468Snon case XPT_PATH_INQ: { /* Path routing inquiry */ 76467468Snon struct ccb_pathinq *cpi = &ccb->cpi; 76567468Snon 76667468Snon cpi->version_num = 1; /* XXX??? */ 76767468Snon cpi->hba_inquiry = PI_SDTR_ABLE; 76867468Snon cpi->target_sprt = 0; 76967468Snon cpi->hba_misc = 0; 77067468Snon cpi->hba_eng_cnt = 0; 77167468Snon cpi->max_target = SCSI_LOW_NTARGETS - 1; 77267468Snon cpi->max_lun = 7; 77367468Snon cpi->initiator_id = 7; /* HOST_SCSI_ID */ 77467468Snon cpi->bus_id = cam_sim_bus(sim); 77567468Snon cpi->base_transfer_speed = 3300; 77667468Snon strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 77767468Snon strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); 77867468Snon strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 77967468Snon cpi->unit_number = cam_sim_unit(sim); 78067468Snon cpi->ccb_h.status = CAM_REQ_CMP; 78167468Snon xpt_done(ccb); 78267468Snon break; 78367468Snon } 78467468Snon default: 78567468Snon printf("scsi_low: non support func_code = %d ", ccb->ccb_h.func_code); 78667468Snon ccb->ccb_h.status = CAM_REQ_INVALID; 78767468Snon xpt_done(ccb); 78867468Snon break; 78967468Snon } 79067468Snon} 79167468Snon#else /* !CAM */ 79267468Snonstatic int 79367468Snonscsi_low_scsi_cmd(xs) 79467468Snon struct scsipi_xfer *xs; 79567468Snon{ 79667468Snon struct scsi_low_softc *slp = xs->sc_link->adapter_softc; 79767468Snon struct targ_info *ti; 79867468Snon struct slccb *cb; 79967468Snon int s, lun, timeo; 80067468Snon 80167468Snon if (slp->sl_cfgflags & CFG_NOATTEN) 80267468Snon { 80367468Snon if (xs->sc_link->scsipi_scsi.lun > 0) 80467468Snon { 80567468Snon xs->error = XS_DRIVER_STUFFUP; 80667468Snon return COMPLETE; 80767468Snon } 80867468Snon } 80967468Snon 81067468Snon if ((cb = scsi_low_get_ccb(xs->flags & SCSI_NOSLEEP)) == NULL) 81167468Snon return TRY_AGAIN_LATER; 81267468Snon 81367468Snon lun = xs->sc_link->scsipi_scsi.lun; 81467468Snon cb->xs = xs; 81567468Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 81667468Snon cb->ti = ti = slp->sl_ti[xs->sc_link->scsipi_scsi.target]; 81767468Snon cb->li = scsi_low_alloc_li(ti, lun, 1); 81867468Snon cb->ccb_flags = 0; 81967468Snon cb->ccb_rcnt = 0; 82067468Snon 82167468Snon s = splbio(); 82267468Snon 82367468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 82467468Snon if (slp->sl_nexus == NULL) 82567468Snon scsi_low_start(slp); 82667468Snon 82767468Snon if ((xs->flags & SCSI_POLL) == 0) 82867468Snon { 82967468Snon splx(s); 83067468Snon return SUCCESSFULLY_QUEUED; 83167468Snon } 83267468Snon 83367468Snon#define SCSI_LOW_POLL_INTERVAL 1000 /* 1 ms */ 83467468Snon timeo = xs->timeout * (1000 / SCSI_LOW_POLL_INTERVAL); 83567468Snon 83667468Snon while ((xs->flags & ITSDONE) == 0 && timeo -- > 0) 83767468Snon { 83867468Snon delay(SCSI_LOW_POLL_INTERVAL); 83967468Snon (*slp->sl_funcs->scsi_low_poll) (slp); 84067468Snon } 84167468Snon 84267468Snon if ((xs->flags & ITSDONE) == 0) 84367468Snon { 84467468Snon cb->ccb_error |= (TIMEOUTIO | ABORTIO); 84567468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 84667468Snon scsi_low_disconnected(slp, ti); 84767468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 84867468Snon } 84967468Snon 85067468Snon scsipi_done(xs); 85167468Snon splx(s); 85267468Snon return COMPLETE; 85367468Snon} 85467468Snon#endif 85567468Snon 85667468Snon/************************************************************** 85767468Snon * Start & Done 85867468Snon **************************************************************/ 85967468Snon#ifdef __NetBSD__ 86067468Snonstatic struct scsipi_start_stop ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; 86167468Snonstatic struct scsipi_test_unit_ready unit_ready_cmd; 86267468Snon#endif 86367468Snon#ifdef __FreeBSD__ 86467468Snonstatic struct scsi_start_stop_unit ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; 86567468Snonstatic struct scsi_test_unit_ready unit_ready_cmd; 86667468Snon#endif 86767468Snonstatic void scsi_low_unit_ready_cmd __P((struct slccb *)); 86867468Snon 86967468Snonstatic void 87067468Snonscsi_low_unit_ready_cmd(cb) 87167468Snon struct slccb *cb; 87267468Snon{ 87367468Snon 87467468Snon cb->ccb_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 87567468Snon cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); 87667468Snon cb->ccb_scp.scp_datalen = 0; 87767468Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 87867468Snon cb->ccb_tcmax = 15; 87967468Snon} 88067468Snon 88167468Snonstatic void 88267468Snonscsi_low_start(slp) 88367468Snon struct scsi_low_softc *slp; 88467468Snon{ 88567468Snon#ifdef CAM 88667468Snon union ccb *ccb; 88767468Snon#else 88867468Snon struct scsipi_xfer *xs; 88967468Snon#endif 89067468Snon struct targ_info *ti; 89167468Snon struct lun_info *li; 89267468Snon struct slccb *cb; 89367468Snon int rv; 89467468Snon 89567468Snon /* check hardware exists ? */ 89667468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 89767468Snon return; 89867468Snon 89967468Snon /* check hardware power up ? */ 90067468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 90167468Snon { 90267468Snon slp->sl_active ++; 90367468Snon if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) 90467468Snon { 90567468Snon if (slp->sl_flags & HW_RESUME) 90667468Snon return; 90767468Snon slp->sl_flags &= ~HW_POWDOWN; 90867468Snon if (slp->sl_funcs->scsi_low_power != NULL) 90967468Snon { 91067468Snon slp->sl_flags |= HW_RESUME; 91167468Snon slp->sl_rstep = 0; 91267468Snon (*slp->sl_funcs->scsi_low_power) 91367468Snon (slp, SCSI_LOW_ENGAGE); 91467468Snon#ifdef __FreeBSD__ 91567468Snon slp->engage_ch = 91667468Snon#endif 91767468Snon timeout(scsi_low_engage, slp, 1); 91867468Snon return; 91967468Snon } 92067468Snon } 92167468Snon } 92267468Snon 92367468Snon /* setup nexus */ 92467468Snon#ifdef SCSI_LOW_DIAGNOSTIC 92567468Snon ti = slp->sl_nexus; 92667468Snon if (ti != NULL) 92767468Snon { 92867468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 92967468Snon panic("%s: inconsistent(target)\n", slp->sl_xname); 93067468Snon } 93167468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 93267468Snon 93371999Sphk for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 93471999Sphk cb = TAILQ_NEXT(cb, ccb_chain)) 93567468Snon { 93667468Snon ti = cb->ti; 93767468Snon li = cb->li; 93867468Snon if (ti->ti_phase == PH_NULL) 93967468Snon goto scsi_low_cmd_start; 94067468Snon if (ti->ti_phase == PH_DISC && li->li_disc < li->li_maxnexus) 94167468Snon goto scsi_low_cmd_start; 94267468Snon } 94367468Snon return; 94467468Snon 94567468Snonscsi_low_cmd_start: 94667468Snon#ifdef CAM 94767468Snon ccb = cb->ccb; 94867468Snon#else 94967468Snon xs = cb->xs; 95067468Snon#endif 95167468Snon#ifdef SCSI_LOW_DIAGNOSTIC 95267468Snon if (ti->ti_nexus != NULL || ti->ti_li != NULL) 95367468Snon { 95467468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 95567468Snon panic("%s: inconsistent(lun or ccb)\n", slp->sl_xname); 95667468Snon } 95767468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 95867468Snon 95967468Snon /* clear all error flag bits (for restart) */ 96067468Snon cb->ccb_error = 0; 96167468Snon 96267468Snon /* setup nexus pointer */ 96367468Snon ti->ti_nexus = cb; 96467468Snon ti->ti_li = li; 96567468Snon slp->sl_nexus = ti; 96667468Snon 96767468Snon /* initialize msgsys */ 96867468Snon scsi_low_init_msgsys(slp, ti); 96967468Snon 97067468Snon /* target lun state check */ 97167468Snon#ifdef CAM 97267468Snon li->li_maxstate = UNIT_OK; 97367468Snon#else 97467468Snon if ((xs->flags & SCSI_POLL) != 0) 97567468Snon li->li_maxstate = UNIT_NEGSTART; 97667468Snon else 97767468Snon li->li_maxstate = UNIT_OK; 97867468Snon#endif 97967468Snon 98067468Snon /* exec cmds */ 98167468Snonscsi_low_cmd_exec: 98267468Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 98367468Snon { 98467468Snon memset(&cb->ccb_sense, 0, sizeof(cb->ccb_sense)); 98567468Snon#ifdef CAM 98667468Snon#else 98767468Snon cb->ccb_sense_cmd.opcode = REQUEST_SENSE; 98867468Snon cb->ccb_sense_cmd.byte2 = (li->li_lun << 5); 98967468Snon cb->ccb_sense_cmd.length = sizeof(cb->ccb_sense); 99067468Snon#endif 99167468Snon cb->ccb_scp.scp_cmd = (u_int8_t *) &cb->ccb_sense_cmd; 99267468Snon cb->ccb_scp.scp_cmdlen = sizeof(cb->ccb_sense_cmd); 99367468Snon cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; 99467468Snon cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); 99567468Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 99667468Snon cb->ccb_tcmax = 15; 99767468Snon } 99867468Snon else if (li->li_state >= li->li_maxstate) 99967468Snon { 100067468Snon#ifdef CAM 100167468Snon cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; 100267468Snon cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; 100367468Snon cb->ccb_scp.scp_data = ccb->csio.data_ptr; 100467468Snon cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; 100567468Snon if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 100667468Snon cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; 100767468Snon else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ 100867468Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 100967468Snon cb->ccb_tcmax = (ccb->ccb_h.timeout >> 10); 101067468Snon#else 101167468Snon cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; 101267468Snon cb->ccb_scp.scp_cmdlen = xs->cmdlen; 101367468Snon cb->ccb_scp.scp_data = xs->data; 101467468Snon cb->ccb_scp.scp_datalen = xs->datalen; 101567468Snon cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? 101667468Snon SCSI_LOW_WRITE : SCSI_LOW_READ; 101767468Snon cb->ccb_tcmax = (xs->timeout >> 10); 101867468Snon#endif 101967468Snon 102067468Snon } 102167468Snon else switch(li->li_state) 102267468Snon { 102367468Snon case UNIT_SLEEP: 102467468Snon scsi_low_unit_ready_cmd(cb); 102567468Snon break; 102667468Snon 102767468Snon case UNIT_START: 102867468Snon cb->ccb_scp.scp_cmd = (u_int8_t *) &ss_cmd; 102967468Snon cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); 103067468Snon cb->ccb_scp.scp_datalen = 0; 103167468Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 103267468Snon cb->ccb_tcmax = 30; 103367468Snon break; 103467468Snon 103567468Snon case UNIT_SYNCH: 103667468Snon if (li->li_maxsynch.offset > 0) 103767468Snon { 103867468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 103967468Snon scsi_low_unit_ready_cmd(cb); 104067468Snon break; 104167468Snon } 104267468Snon li->li_state = UNIT_WIDE; 104367468Snon 104467468Snon case UNIT_WIDE: 104567468Snon#ifdef SCSI_LOW_SUPPORT_WIDE 104667468Snon if (li->li_width > 0) 104767468Snon { 104867468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 104967468Snon scsi_low_unit_ready_cmd(cb); 105067468Snon break; 105167468Snon } 105267468Snon#endif /* SCSI_LOW_SUPPORT_WIDE */ 105367468Snon li->li_state = UNIT_OK; 105467468Snon 105567468Snon case UNIT_OK: 105667468Snon goto scsi_low_cmd_exec; 105767468Snon } 105867468Snon 105967468Snon /* timeout */ 106067468Snon if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 106167468Snon cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 106267468Snon cb->ccb_tc = cb->ccb_tcmax; 106367468Snon 106467468Snon /* setup saved scsi data pointer */ 106567468Snon cb->ccb_sscp = cb->ccb_scp; 106667468Snon 106767468Snon /* setup current scsi pointer */ 106867468Snon slp->sl_scp = cb->ccb_sscp; 106967468Snon slp->sl_error = cb->ccb_error; 107067468Snon 107167468Snon /* selection start */ 107267468Snon slp->sl_selid = ti; 107367468Snon rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); 107467468Snon if (rv == SCSI_LOW_START_OK) 107567468Snon { 107667468Snon#ifdef SCSI_LOW_STATICS 107767468Snon scsi_low_statics.nexus_win ++; 107867468Snon#endif /* SCSI_LOW_STATICS */ 107967468Snon return; 108067468Snon } 108167468Snon 108267468Snon#ifdef SCSI_LOW_STATICS 108367468Snon scsi_low_statics.nexus_fail ++; 108467468Snon#endif /* SCSI_LOW_STATICS */ 108567468Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 108667468Snon scsi_low_clear_nexus(slp, ti); 108767468Snon} 108867468Snon 108967468Snonvoid 109067468Snonscsi_low_clear_nexus(slp, ti) 109167468Snon struct scsi_low_softc *slp; 109267468Snon struct targ_info *ti; 109367468Snon{ 109467468Snon 109567468Snon /* clear all nexus pointer */ 109667468Snon ti->ti_nexus = NULL; 109767468Snon ti->ti_li = NULL; 109867468Snon slp->sl_nexus = NULL; 109967468Snon 110067468Snon /* clear selection assert */ 110167468Snon slp->sl_selid = NULL; 110267468Snon 110367468Snon /* clear nexus data */ 110467468Snon slp->sl_nexus_call = 0; 110567468Snon slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; 110667468Snon} 110767468Snon 110867468Snonstatic int 110967468Snonscsi_low_done(slp, cb) 111067468Snon struct scsi_low_softc *slp; 111167468Snon struct slccb *cb; 111267468Snon{ 111367468Snon#ifdef CAM 111467468Snon union ccb *ccb; 111567468Snon#else 111667468Snon struct scsipi_xfer *xs; 111767468Snon#endif 111867468Snon struct targ_info *ti; 111967468Snon struct lun_info *li; 112067468Snon 112167468Snon ti = cb->ti; 112267468Snon li = cb->li; 112367468Snon#ifdef CAM 112467468Snon ccb = cb->ccb; 112567468Snon#else 112667468Snon xs = cb->xs; 112767468Snon#endif 112867468Snon if (cb->ccb_error == 0) 112967468Snon { 113067468Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 113167468Snon { 113267468Snon cb->ccb_flags &= ~CCB_SENSE; 113367468Snon#ifdef CAM 113467468Snon ccb->csio.sense_data = cb->ccb_sense; 113567468Snon /* ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; */ 113667468Snon ccb->ccb_h.status = CAM_REQ_CMP; 113767468Snon /* ccb->ccb_h.status = CAM_AUTOSNS_VALID|CAM_SCSI_STATUS_ERROR; */ 113867468Snon#else 113967468Snon xs->sense.scsi_sense = cb->ccb_sense; 114067468Snon xs->error = XS_SENSE; 114167468Snon#endif 114267468Snon } 114367468Snon else switch (ti->ti_status) 114467468Snon { 114567468Snon case ST_GOOD: 114667468Snon if (slp->sl_scp.scp_datalen == 0) 114767468Snon { 114867468Snon#ifdef CAM 114967468Snon ccb->ccb_h.status = CAM_REQ_CMP; 115067468Snon#else 115167468Snon xs->error = XS_NOERROR; 115267468Snon#endif 115367468Snon break; 115467468Snon } 115567468Snon 115667468Snon#define SCSIPI_SCSI_CD_COMPLETELY_BUGGY "YES" 115767468Snon#ifdef SCSIPI_SCSI_CD_COMPLETELY_BUGGY 115867468Snon#ifdef CAM 115967468Snon if (/* cb->bp == NULL && */ 116067468Snon slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) 116167468Snon#else 116267468Snon if (xs->bp == NULL && 116367468Snon slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) 116467468Snon#endif 116567468Snon { 116667468Snon#ifdef CAM 116767468Snon ccb->ccb_h.status = CAM_REQ_CMP; 116867468Snon#else 116967468Snon xs->error = XS_NOERROR; 117067468Snon#endif 117167468Snon break; 117267468Snon } 117367468Snon#endif /* SCSIPI_SCSI_CD_COMPLETELY_BUGGY */ 117467468Snon 117567468Snon cb->ccb_error |= PDMAERR; 117667468Snon#ifdef CAM 117767468Snon ccb->ccb_h.status = CAM_REQ_CMP_ERR; 117867468Snon#else 117967468Snon xs->error = XS_DRIVER_STUFFUP; 118067468Snon#endif 118167468Snon break; 118267468Snon 118367468Snon case ST_CHKCOND: 118467468Snon case ST_MET: 118567468Snon cb->ccb_flags |= CCB_SENSE; 118667468Snon#ifdef CAM 118767468Snon ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 118867468Snon#else 118967468Snon xs->error = XS_SENSE; 119067468Snon#endif 119167468Snon goto retry; 119267468Snon 119367468Snon case ST_BUSY: 119467468Snon cb->ccb_error |= BUSYERR; 119567468Snon#ifdef CAM 119667468Snon ccb->ccb_h.status = CAM_BUSY; /* SCSI_STATUS_ERROR; */ 119767468Snon#else 119867468Snon xs->error = XS_BUSY; 119967468Snon#endif 120067468Snon break; 120167468Snon 120267468Snon default: 120367468Snon cb->ccb_error |= FATALIO; 120467468Snon#ifdef CAM 120567468Snon ccb->ccb_h.status = CAM_REQ_CMP_ERR; 120667468Snon#else 120767468Snon xs->error = XS_DRIVER_STUFFUP; 120867468Snon#endif 120967468Snon break; 121067468Snon } 121167468Snon } 121267468Snon else 121367468Snon { 121467468Snon cb->ccb_flags &= ~CCB_SENSE; 121567468Snon if (ti->ti_phase == PH_SELSTART) 121667468Snon { 121767468Snon#ifdef CAM 121867468Snon ccb->ccb_h.status = CAM_CMD_TIMEOUT; 121967468Snon#else 122067468Snon xs->error = XS_TIMEOUT; 122167468Snon#endif 122267468Snon slp->sl_error |= SELTIMEOUTIO; 122367468Snon if (li->li_state == UNIT_SLEEP) 122467468Snon cb->ccb_error |= ABORTIO; 122567468Snon } 122667468Snon else 122767468Snon { 122867468Snon#ifdef CAM 122967468Snon ccb->ccb_h.status = CAM_REQ_CMP_ERR; 123067468Snon#else 123167468Snon xs->error = XS_DRIVER_STUFFUP; 123267468Snon#endif 123367468Snon } 123467468Snon 123567468Snon if ((cb->ccb_error & ABORTIO) != 0) 123667468Snon { 123767468Snon cb->ccb_rcnt = slp->sl_max_retry; 123867468Snon#ifdef CAM 123967468Snon ccb->ccb_h.status = CAM_REQ_ABORTED; 124067468Snon#endif 124167468Snon } 124267468Snon } 124367468Snon 124467468Snon /* target state check */ 124567468Snon if (li->li_state < li->li_maxstate) 124667468Snon { 124767468Snon if (cb->ccb_rcnt < slp->sl_max_retry) 124867468Snon { 124967468Snon li->li_state ++; 125067468Snon cb->ccb_rcnt = 0; 125167468Snon goto retry; 125267468Snon } 125367468Snon } 125467468Snon 125567468Snon /* internal retry check */ 125667468Snon#ifdef CAM 125767468Snon if (ccb->ccb_h.status == CAM_REQ_CMP) 125867468Snon { 125967468Snon ccb->csio.resid = 0; 126067468Snon } 126167468Snon else 126267468Snon { 126367468Snon#if 0 126467468Snon if (ccb->ccb_h.status != CAM_AUTOSENSE_FAIL && 126567468Snon cb->ccb_rcnt < slp->sl_max_retry) 126667468Snon goto retry; 126767468Snon#endif 126867468Snon#else 126967468Snon if (xs->error == XS_NOERROR) 127067468Snon { 127167468Snon xs->resid = 0; 127267468Snon } 127367468Snon else 127467468Snon { 127567468Snon if (xs->error != XS_SENSE && 127667468Snon cb->ccb_rcnt < slp->sl_max_retry) 127767468Snon goto retry; 127867468Snon#endif 127967468Snon 128067468Snon#ifndef CAM 128167468Snon#ifdef SCSI_LOW_WARNINGS 128267468Snon if (xs->bp != NULL) 128367468Snon { 128467468Snon scsi_low_print(slp, ti); 128567468Snon printf("%s: WARNING: File system IO abort\n", 128667468Snon slp->sl_xname); 128767468Snon } 128867468Snon#endif /* SCSI_LOW_WARNINGS */ 128967468Snon#endif 129067468Snon } 129167468Snon 129267468Snon#ifdef CAM 129367468Snon ccb->csio.scsi_status = ti->ti_status; 129467468Snon xpt_done(ccb); 129567468Snon#else 129667468Snon xs->flags |= ITSDONE; 129767468Snon if ((xs->flags & SCSI_POLL) == 0) 129867468Snon scsipi_done(xs); 129967468Snon#endif 130067468Snon 130167468Snon /* free our target */ 130267468Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 130367468Snon scsi_low_free_ccb(cb); 130467468Snon return SCSI_LOW_DONE_COMPLETE; 130567468Snon 130667468Snonretry: 130767468Snon cb->ccb_rcnt ++; 130871999Sphk if (TAILQ_FIRST(&slp->sl_start) != cb) 130967468Snon { 131067468Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 131167468Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 131267468Snon } 131367468Snon return SCSI_LOW_DONE_RETRY; 131467468Snon} 131567468Snon 131667468Snon/************************************************************** 131767468Snon * Reset 131867468Snon **************************************************************/ 131967468Snonstatic void 132067468Snonscsi_low_clear_ccb(cb) 132167468Snon struct slccb *cb; 132267468Snon{ 132367468Snon 132467468Snon cb->ccb_flags &= ~CCB_SENSE; 132567468Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 132667468Snon} 132767468Snon 132867468Snonstatic void 132967468Snonscsi_low_reset_nexus(slp, fdone) 133067468Snon struct scsi_low_softc *slp; 133167468Snon int fdone; 133267468Snon{ 133367468Snon struct targ_info *ti; 133467468Snon struct lun_info *li; 133567468Snon struct slccb *cb, *ncb; 133667468Snon 133767468Snon /* current nexus */ 133867468Snon ti = slp->sl_nexus; 133967468Snon if (ti != NULL && (cb = ti->ti_nexus) != NULL) 134067468Snon { 134167468Snon scsi_low_clear_ccb(cb); 134267468Snon if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) 134367468Snon { 134467468Snon cb->ccb_error |= FATALIO; 134567468Snon scsi_low_done(slp, cb); 134667468Snon } 134767468Snon } 134867468Snon 134967468Snon /* disconnected nexus */ 135071999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 135171999Sphk ti = TAILQ_NEXT(ti, ti_chain)) 135267468Snon { 135371999Sphk for (cb = TAILQ_FIRST(&ti->ti_discq); cb != NULL; cb = ncb) 135467468Snon { 135571999Sphk ncb = TAILQ_NEXT(cb, ccb_chain); 135667468Snon TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); 135767468Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 135867468Snon scsi_low_clear_ccb(cb); 135967468Snon if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) 136067468Snon { 136167468Snon cb->ccb_error |= FATALIO; 136267468Snon scsi_low_done(slp, cb); 136367468Snon } 136467468Snon } 136567468Snon 136667468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 136767468Snon li = LIST_NEXT(li, lun_chain)) 136867468Snon { 136967468Snon li->li_state = UNIT_SLEEP; 137067468Snon li->li_disc = 0; 137167468Snon ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li)); 137267468Snon scsi_low_calcf(ti, li); 137367468Snon } 137467468Snon 137567468Snon scsi_low_init_msgsys(slp, ti); 137667468Snon scsi_low_clear_nexus(slp, ti); 137767468Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 137867468Snon } 137967468Snon 138067468Snon slp->sl_flags &= ~HW_PDMASTART; 138167468Snon slp->sl_disc = 0; 138267468Snon} 138367468Snon 138467468Snon/* misc */ 138567468Snonstatic int tw_pos; 138667468Snonstatic char tw_chars[] = "|/-\\"; 138767468Snon 138867468Snonstatic void 138967468Snonscsi_low_twiddle_wait(void) 139067468Snon{ 139167468Snon 139267468Snon cnputc('\b'); 139367468Snon cnputc(tw_chars[tw_pos++]); 139467468Snon tw_pos %= (sizeof(tw_chars) - 1); 139567468Snon delay(TWIDDLEWAIT); 139667468Snon} 139767468Snon 139867468Snonvoid 139967468Snonscsi_low_bus_reset(slp) 140067468Snon struct scsi_low_softc *slp; 140167468Snon{ 140267468Snon int i; 140367468Snon 140467468Snon (*slp->sl_funcs->scsi_low_bus_reset) (slp); 140567468Snon 140667468Snon printf("%s: try to reset scsi bus ", slp->sl_xname); 140767468Snon for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) 140867468Snon scsi_low_twiddle_wait(); 140967468Snon cnputc('\b'); 141067468Snon printf("\n"); 141167468Snon} 141267468Snon 141367468Snonint 141467468Snonscsi_low_restart(slp, flags, s) 141567468Snon struct scsi_low_softc *slp; 141667468Snon int flags; 141767468Snon u_char *s; 141867468Snon{ 141967468Snon int error; 142067468Snon 142167468Snon if (s != NULL) 142267468Snon printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s); 142367468Snon 142467468Snon if ((error = scsi_low_init(slp, flags)) != 0) 142567468Snon return error; 142667468Snon 142767468Snon scsi_low_start(slp); 142867468Snon return 0; 142967468Snon} 143067468Snon 143167468Snon/************************************************************** 143267468Snon * disconnect and reselect 143367468Snon **************************************************************/ 143467468Snon#define MSGCMD_LUN(msg) (msg & 0x07) 143567468Snon 143667468Snonstatic struct lun_info * 143767468Snonscsi_low_establish_lun(ti, lun) 143867468Snon struct targ_info *ti; 143967468Snon int lun; 144067468Snon{ 144167468Snon struct lun_info *li; 144267468Snon 144367468Snon li = scsi_low_alloc_li(ti, lun, 0); 144467468Snon if (li == NULL) 144567468Snon return li; 144667468Snon 144767468Snon ti->ti_li = li; 144867468Snon return li; 144967468Snon} 145067468Snon 145167468Snonstatic struct slccb * 145267468Snonscsi_low_establish_ccb(ti, li, tag) 145367468Snon struct targ_info *ti; 145467468Snon struct lun_info *li; 145567468Snon scsi_low_tag_t tag; 145667468Snon{ 145767468Snon struct scsi_low_softc *slp = ti->ti_sc; 145867468Snon struct slccb *cb; 145967468Snon 146067468Snon /* 146167468Snon * Search ccb matching with lun and tag. 146267468Snon */ 146371999Sphk cb = TAILQ_FIRST(&ti->ti_discq); 146471999Sphk for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) 146567468Snon if (cb->li == li && cb->ccb_tag == tag) 146667468Snon goto found; 146767468Snon return cb; 146867468Snon 146967468Snon /* 147067468Snon * establish our ccb nexus 147167468Snon */ 147267468Snonfound: 147367468Snon TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); 147467468Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 147567468Snon ti->ti_nexus = cb; 147667468Snon 147767468Snon slp->sl_scp = cb->ccb_sscp; 147867468Snon slp->sl_error |= cb->ccb_error; 147967468Snon 148067468Snon slp->sl_disc --; 148167468Snon li->li_disc --; 148267468Snon 148367468Snon /* inform "ccb nexus established" to the host driver */ 148467468Snon slp->sl_nexus_call = 1; 148567468Snon (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); 148667468Snon return cb; 148767468Snon} 148867468Snon 148967468Snonstruct targ_info * 149067468Snonscsi_low_reselected(slp, targ) 149167468Snon struct scsi_low_softc *slp; 149267468Snon u_int targ; 149367468Snon{ 149467468Snon struct targ_info *ti; 149567468Snon u_char *s; 149667468Snon 149767468Snon /* 149867468Snon * Check select vs reselected collision. 149967468Snon */ 150067468Snon 150167468Snon if ((ti = slp->sl_selid) != NULL) 150267468Snon { 150367468Snon scsi_low_clear_nexus(slp, ti); 150467468Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 150567468Snon#ifdef SCSI_LOW_STATICS 150667468Snon scsi_low_statics.nexus_conflict ++; 150767468Snon#endif /* SCSI_LOW_STATICS */ 150867468Snon } 150967468Snon else if (slp->sl_nexus != NULL) 151067468Snon { 151167468Snon s = "host busy"; 151267468Snon goto world_restart; 151367468Snon } 151467468Snon 151567468Snon /* 151667468Snon * Check a valid target id asserted ? 151767468Snon */ 151867468Snon if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) 151967468Snon { 152067468Snon s = "scsi id illegal"; 152167468Snon goto world_restart; 152267468Snon } 152367468Snon 152467468Snon /* 152567468Snon * Check the target scsi status. 152667468Snon */ 152767468Snon ti = slp->sl_ti[targ]; 152867468Snon if (ti->ti_phase != PH_DISC) 152967468Snon { 153067468Snon s = "phase mismatch"; 153167468Snon goto world_restart; 153267468Snon } 153367468Snon 153467468Snon /* 153567468Snon * Setup lun and init msgsys 153667468Snon */ 153767468Snon slp->sl_error = 0; 153867468Snon scsi_low_init_msgsys(slp, ti); 153967468Snon 154067468Snon /* 154167468Snon * Establish our target nexus 154267468Snon * Remark: ccb and scsi pointer not yet restored 154367468Snon * if lun != SCSI_LOW_UNKLUN. 154467468Snon */ 154567468Snon SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); 154667468Snon slp->sl_nexus = ti; 154767468Snon#ifdef SCSI_LOW_STATICS 154867468Snon scsi_low_statics.nexus_reselected ++; 154967468Snon#endif /* SCSI_LOW_STATICS */ 155067468Snon return ti; 155167468Snon 155267468Snonworld_restart: 155367468Snon printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); 155467468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 155567468Snon "reselect: scsi world confused"); 155667468Snon return NULL; 155767468Snon} 155867468Snon 155967468Snonint 156067468Snonscsi_low_disconnected(slp, ti) 156167468Snon struct scsi_low_softc *slp; 156267468Snon struct targ_info *ti; 156367468Snon{ 156467468Snon struct slccb *cb = ti->ti_nexus; 156567468Snon 156667468Snon /* check phase completion */ 156767468Snon switch (slp->sl_msgphase) 156867468Snon { 156967468Snon case MSGPH_DISC: 157067468Snon if (cb != NULL) 157167468Snon { 157267468Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 157367468Snon TAILQ_INSERT_TAIL(&ti->ti_discq, cb, ccb_chain); 157467468Snon cb->ccb_error |= slp->sl_error; 157567468Snon cb->li->li_disc ++; 157667468Snon slp->sl_disc ++; 157767468Snon } 157867468Snon SCSI_LOW_SETUP_PHASE(ti, PH_DISC); 157967468Snon#ifdef SCSI_LOW_STATICS 158067468Snon scsi_low_statics.nexus_disconnected ++; 158167468Snon#endif /* SCSI_LOW_STATICS */ 158267468Snon break; 158367468Snon 158467468Snon case MSGPH_NULL: 158567468Snon slp->sl_error |= FATALIO; 158667468Snon 158767468Snon case MSGPH_CMDC: 158867468Snon if (cb != NULL) 158967468Snon { 159067468Snon cb->ccb_error |= slp->sl_error; 159167468Snon scsi_low_done(slp, cb); 159267468Snon } 159367468Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 159467468Snon break; 159567468Snon } 159667468Snon 159767468Snon scsi_low_clear_nexus(slp, ti); 159867468Snon scsi_low_start(slp); 159967468Snon return 1; 160067468Snon} 160167468Snon 160267468Snon/************************************************************** 160367468Snon * cmd out pointer setup 160467468Snon **************************************************************/ 160567468Snonint 160667468Snonscsi_low_cmd(slp, ti) 160767468Snon struct scsi_low_softc *slp; 160867468Snon struct targ_info *ti; 160967468Snon{ 161067468Snon struct slccb *cb = ti->ti_nexus; 161167468Snon 161267468Snon if (cb == NULL) 161367468Snon { 161467468Snon /* 161567468Snon * no slccb, abort! 161667468Snon */ 161767468Snon slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 161867468Snon slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); 161967468Snon slp->sl_scp.scp_datalen = 0; 162067468Snon slp->sl_scp.scp_direction = SCSI_LOW_READ; 162167468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); 162267468Snon scsi_low_info(slp, ti, "CMDOUT: slccb nexus not found"); 162367468Snon } 162467468Snon else if (slp->sl_nexus_call == 0) 162567468Snon { 162667468Snon slp->sl_nexus_call = 1; 162767468Snon (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); 162867468Snon } 162967468Snon return 0; 163067468Snon} 163167468Snon 163267468Snon/************************************************************** 163367468Snon * data out pointer setup 163467468Snon **************************************************************/ 163567468Snonint 163667468Snonscsi_low_data(slp, ti, bp, direction) 163767468Snon struct scsi_low_softc *slp; 163867468Snon struct targ_info *ti; 163967468Snon struct buf **bp; 164067468Snon int direction; 164167468Snon{ 164267468Snon struct slccb *cb = ti->ti_nexus; 164367468Snon 164467468Snon if (cb == NULL) 164567468Snon { 164667468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); 164767468Snon scsi_low_info(slp, ti, "DATA PHASE: slccb nexus not found"); 164867468Snon return EINVAL; 164967468Snon } 165067468Snon 165167468Snon if (direction != cb->ccb_scp.scp_direction) 165267468Snon { 165367468Snon scsi_low_info(slp, ti, "DATA PHASE: xfer direction mismatch"); 165467468Snon return EINVAL; 165567468Snon } 165667468Snon 165767468Snon#ifdef CAM 165867468Snon *bp = NULL; /* (cb->ccb == NULL) ? NULL : cb->bp; */ 165967468Snon#else 166067468Snon *bp = (cb->xs == NULL) ? NULL : cb->xs->bp; 166167468Snon#endif 166267468Snon return 0; 166367468Snon} 166467468Snon 166567468Snon/************************************************************** 166667468Snon * MSG_SYS 166767468Snon **************************************************************/ 166867468Snon#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} 166967468Snon#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) 167067468Snon#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) 167167468Snon#define MSGIN_DATA_LAST 0x30 167267468Snon 167367468Snonstatic int scsi_low_errfunc_synch __P((struct targ_info *, u_int)); 167467468Snonstatic int scsi_low_errfunc_wide __P((struct targ_info *, u_int)); 167567468Snonstatic int scsi_low_errfunc_identify __P((struct targ_info *, u_int)); 167667468Snon 167767468Snonstatic int scsi_low_msgfunc_synch __P((struct targ_info *)); 167867468Snonstatic int scsi_low_msgfunc_wide __P((struct targ_info *)); 167967468Snonstatic int scsi_low_msgfunc_identify __P((struct targ_info *)); 168067468Snonstatic int scsi_low_msgfunc_user __P((struct targ_info *)); 168167468Snonstatic int scsi_low_msgfunc_abort __P((struct targ_info *)); 168267468Snon 168367468Snonstruct scsi_low_msgout_data { 168467468Snon u_int md_flags; 168567468Snon u_int8_t md_msg; 168667468Snon int (*md_msgfunc) __P((struct targ_info *)); 168767468Snon int (*md_errfunc) __P((struct targ_info *, u_int)); 168867468Snon}; 168967468Snon 169067468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = { 169167468Snon/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_abort, NULL}, 169267468Snon/* 1 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL}, 169367468Snon/* 2 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL}, 169467468Snon/* 3 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL}, 169567468Snon/* 4 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL}, 169667468Snon/* 5 */ {SCSI_LOW_MSG_IDENTIFY, 0, scsi_low_msgfunc_identify, scsi_low_errfunc_identify}, 169767468Snon/* 6 */ {SCSI_LOW_MSG_SYNCH, 0, scsi_low_msgfunc_synch, scsi_low_errfunc_synch}, 169867468Snon/* 7 */ {SCSI_LOW_MSG_WIDE, 0, scsi_low_msgfunc_wide, scsi_low_errfunc_wide}, 169967468Snon/* 8 */ {SCSI_LOW_MSG_USER, 0, scsi_low_msgfunc_user, NULL}, 170067468Snon/* 9 */ {SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL}, 170167468Snon/* 10 */ {SCSI_LOW_MSG_ALL, 0}, 170267468Snon}; 170367468Snon 170467468Snonstatic int scsi_low_msginfunc_ext __P((struct targ_info *)); 170567468Snonstatic int scsi_low_synch __P((struct targ_info *)); 170667468Snonstatic int scsi_low_msginfunc_msg_reject __P((struct targ_info *)); 170767468Snonstatic int scsi_low_msginfunc_rejop __P((struct targ_info *)); 170867468Snonstatic int scsi_low_msginfunc_rdp __P((struct targ_info *)); 170967468Snonstatic int scsi_low_msginfunc_sdp __P((struct targ_info *)); 171067468Snonstatic int scsi_low_msginfunc_disc __P((struct targ_info *)); 171167468Snonstatic int scsi_low_msginfunc_cc __P((struct targ_info *)); 171267468Snonstatic int scsi_low_msginfunc_parity __P((struct targ_info *)); 171367468Snonstatic int scsi_low_msginfunc_noop __P((struct targ_info *)); 171467468Snonstatic void scsi_low_retry_phase __P((struct targ_info *)); 171567468Snon 171667468Snonstruct scsi_low_msgin_data { 171767468Snon u_int md_len; 171867468Snon int (*md_msgfunc) __P((struct targ_info *)); 171967468Snon}; 172067468Snon 172167468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = { 172267468Snon/* 0 */ {1, scsi_low_msginfunc_cc}, 172367468Snon/* 1 */ {2, scsi_low_msginfunc_ext}, 172467468Snon/* 2 */ {1, scsi_low_msginfunc_sdp}, 172567468Snon/* 3 */ {1, scsi_low_msginfunc_rdp}, 172667468Snon/* 4 */ {1, scsi_low_msginfunc_disc}, 172767468Snon/* 5 */ {1, scsi_low_msginfunc_rejop}, 172867468Snon/* 6 */ {1, scsi_low_msginfunc_rejop}, 172967468Snon/* 7 */ {1, scsi_low_msginfunc_msg_reject}, 173067468Snon/* 8 */ {1, scsi_low_msginfunc_noop}, 173167468Snon/* 9 */ {1, scsi_low_msginfunc_parity}, 173267468Snon/* a */ {1, scsi_low_msginfunc_rejop}, 173367468Snon/* b */ {1, scsi_low_msginfunc_rejop}, 173467468Snon/* c */ {1, scsi_low_msginfunc_rejop}, 173567468Snon/* d */ {2, scsi_low_msginfunc_rejop}, 173667468Snon/* e */ {1, scsi_low_msginfunc_rejop}, 173767468Snon/* f */ {1, scsi_low_msginfunc_rejop}, 173867468Snon/* 0x10 */ {1, scsi_low_msginfunc_rejop}, 173967468Snon/* 0x11 */ {1, scsi_low_msginfunc_rejop}, 174067468Snon/* 0x12 */ {1, scsi_low_msginfunc_rejop}, 174167468Snon/* 0x13 */ {1, scsi_low_msginfunc_rejop}, 174267468Snon/* 0x14 */ {1, scsi_low_msginfunc_rejop}, 174367468Snon/* 0x15 */ {1, scsi_low_msginfunc_rejop}, 174467468Snon/* 0x16 */ {1, scsi_low_msginfunc_rejop}, 174567468Snon/* 0x17 */ {1, scsi_low_msginfunc_rejop}, 174667468Snon/* 0x18 */ {1, scsi_low_msginfunc_rejop}, 174767468Snon/* 0x19 */ {1, scsi_low_msginfunc_rejop}, 174867468Snon/* 0x1a */ {1, scsi_low_msginfunc_rejop}, 174967468Snon/* 0x1b */ {1, scsi_low_msginfunc_rejop}, 175067468Snon/* 0x1c */ {1, scsi_low_msginfunc_rejop}, 175167468Snon/* 0x1d */ {1, scsi_low_msginfunc_rejop}, 175267468Snon/* 0x1e */ {1, scsi_low_msginfunc_rejop}, 175367468Snon/* 0x1f */ {1, scsi_low_msginfunc_rejop}, 175467468Snon/* 0x20 */ {2, scsi_low_msginfunc_rejop}, 175567468Snon/* 0x21 */ {2, scsi_low_msginfunc_rejop}, 175667468Snon/* 0x22 */ {2, scsi_low_msginfunc_rejop}, 175767468Snon/* 0x23 */ {2, scsi_low_msginfunc_rejop}, 175867468Snon/* 0x24 */ {2, scsi_low_msginfunc_rejop}, 175967468Snon/* 0x25 */ {2, scsi_low_msginfunc_rejop}, 176067468Snon/* 0x26 */ {2, scsi_low_msginfunc_rejop}, 176167468Snon/* 0x27 */ {2, scsi_low_msginfunc_rejop}, 176267468Snon/* 0x28 */ {2, scsi_low_msginfunc_rejop}, 176367468Snon/* 0x29 */ {2, scsi_low_msginfunc_rejop}, 176467468Snon/* 0x2a */ {2, scsi_low_msginfunc_rejop}, 176567468Snon/* 0x2b */ {2, scsi_low_msginfunc_rejop}, 176667468Snon/* 0x2c */ {2, scsi_low_msginfunc_rejop}, 176767468Snon/* 0x2d */ {2, scsi_low_msginfunc_rejop}, 176867468Snon/* 0x2e */ {2, scsi_low_msginfunc_rejop}, 176967468Snon/* 0x2f */ {2, scsi_low_msginfunc_rejop}, 177067468Snon/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ 177167468Snon}; 177267468Snon 177367468Snonstatic void 177467468Snonscsi_low_init_msgsys(slp, ti) 177567468Snon struct scsi_low_softc *slp; 177667468Snon struct targ_info *ti; 177767468Snon{ 177867468Snon 177967468Snon ti->ti_msginptr = 0; 178067468Snon ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; 178167468Snon ti->ti_tflags &= ~TARG_ASSERT_ATN; 178267468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 178367468Snon} 178467468Snon 178567468Snon/************************************************************** 178667468Snon * msgout 178767468Snon **************************************************************/ 178867468Snonstatic int 178967468Snonscsi_low_msgfunc_synch(ti) 179067468Snon struct targ_info *ti; 179167468Snon{ 179267468Snon struct lun_info *li = ti->ti_li; 179367468Snon int ptr = ti->ti_msgoutlen; 179467468Snon 179567468Snon if (li == NULL) 179667468Snon { 179767468Snon scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); 179867468Snon return EINVAL; 179967468Snon } 180067468Snon 180167468Snon ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; 180267468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; 180367468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; 180467468Snon ti->ti_msgoutstr[ptr + 3] = li->li_maxsynch.period; 180567468Snon ti->ti_msgoutstr[ptr + 4] = li->li_maxsynch.offset; 180667468Snon return MSG_EXTEND_SYNCHLEN + 2; 180767468Snon} 180867468Snon 180967468Snonstatic int 181067468Snonscsi_low_msgfunc_wide(ti) 181167468Snon struct targ_info *ti; 181267468Snon{ 181367468Snon struct lun_info *li = ti->ti_li; 181467468Snon int ptr = ti->ti_msgoutlen; 181567468Snon 181667468Snon if (li == NULL) 181767468Snon { 181867468Snon scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); 181967468Snon return EINVAL; 182067468Snon } 182167468Snon 182267468Snon ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; 182367468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; 182467468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; 182567468Snon ti->ti_msgoutstr[ptr + 3] = li->li_width; 182667468Snon return MSG_EXTEND_WIDELEN + 2; 182767468Snon} 182867468Snon 182967468Snonstatic int 183067468Snonscsi_low_msgfunc_identify(ti) 183167468Snon struct targ_info *ti; 183267468Snon{ 183367468Snon int ptr = ti->ti_msgoutlen;; 183467468Snon 183567468Snon if (ti->ti_li == NULL) 183667468Snon { 183767468Snon ti->ti_msgoutstr[ptr + 0] = 0x80; 183867468Snon scsi_low_info(ti->ti_sc, ti, "MSGOUT: lun unknown"); 183967468Snon scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); 184067468Snon } 184167468Snon else 184267468Snon { 184367468Snon ti->ti_msgoutstr[ptr + 0] = ID_MSG_SETUP(ti); 184467468Snon } 184567468Snon return 1; 184667468Snon} 184767468Snon 184867468Snonstatic int 184967468Snonscsi_low_msgfunc_user(ti) 185067468Snon struct targ_info *ti; 185167468Snon{ 185267468Snon#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT 185367468Snon struct slccb *cb = ti->ti_nexus; 185467468Snon int ptr = ti->ti_msgoutlen;; 185567468Snon 185667468Snon if (ti->ti_nexus == NULL) 185767468Snon { 185867468Snon ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; 185967468Snon return 1; 186067468Snon } 186167468Snon else 186267468Snon { 186367468Snon bcopy(cb->msgout, ti->ti_msgoutstr + ptr, SCSI_LOW_MAX_MSGLEN); 186467468Snon return cb->msgoutlen; 186567468Snon } 186667468Snon#else /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ 186767468Snon return 0; 186867468Snon#endif /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ 186967468Snon} 187067468Snon 187167468Snonstatic int 187267468Snonscsi_low_msgfunc_abort(ti) 187367468Snon struct targ_info *ti; 187467468Snon{ 187567468Snon struct scsi_low_softc *slp = ti->ti_sc; 187667468Snon 187767468Snon /* The target should releases bus */ 187867468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 187967468Snon slp->sl_error |= /* ABORTIO */ FATALIO; 188067468Snon return 1; 188167468Snon} 188267468Snon 188367468Snon/* 188467468Snon * The following functions are called when targets give unexpected 188567468Snon * responces in msgin (after msgout). 188667468Snon */ 188767468Snonstatic int 188867468Snonscsi_low_errfunc_identify(ti, msgflags) 188967468Snon struct targ_info *ti; 189067468Snon u_int msgflags; 189167468Snon{ 189267468Snon struct lun_info *li = ti->ti_li; 189367468Snon 189467468Snon li->li_flags &= ~SCSI_LOW_DISC; 189567468Snon return 0; 189667468Snon} 189767468Snon 189867468Snonstatic int 189967468Snonscsi_low_errfunc_synch(ti, msgflags) 190067468Snon struct targ_info *ti; 190167468Snon u_int msgflags; 190267468Snon{ 190367468Snon 190467468Snon /* XXX: 190567468Snon * illegal behavior, however 190667468Snon * there are buggy devices! 190767468Snon */ 190867468Snon MSGIN_PERIOD(ti) = 0; 190967468Snon MSGIN_OFFSET(ti) = 0; 191067468Snon scsi_low_synch(ti); 191167468Snon return 0; 191267468Snon} 191367468Snon 191467468Snonstatic int 191567468Snonscsi_low_errfunc_wide(ti, msgflags) 191667468Snon struct targ_info *ti; 191767468Snon u_int msgflags; 191867468Snon{ 191967468Snon struct lun_info *li = ti->ti_li; 192067468Snon 192167468Snon li->li_width = 0; 192267468Snon return 0; 192367468Snon} 192467468Snon 192567468Snonint 192667468Snonscsi_low_msgout(slp, ti) 192767468Snon struct scsi_low_softc *slp; 192867468Snon struct targ_info *ti; 192967468Snon{ 193067468Snon struct scsi_low_msgout_data *mdp; 193167468Snon int len = 0; 193267468Snon 193367468Snon /* STEP I. 193467468Snon * Scsi phase changes. 193567468Snon * Previously msgs asserted are accepted by our target or 193667468Snon * processed by scsi_low_msgin. 193767468Snon * Thus clear all saved informations. 193867468Snon */ 193967468Snon if (ti->ti_ophase != ti->ti_phase) 194067468Snon { 194167468Snon ti->ti_omsgflags = 0; 194267468Snon ti->ti_emsgflags = 0; 194367468Snon } 194467468Snon 194567468Snon /* STEP II. 194667468Snon * We did not assert attention, however still our target required 194767468Snon * msgs. Resend previous msgs. 194867468Snon */ 194967468Snon if (ti->ti_ophase == PH_MSGOUT && !(ti->ti_tflags & TARG_ASSERT_ATN)) 195067468Snon { 195167468Snon ti->ti_msgflags |= ti->ti_omsgflags; 195267468Snon#ifdef SCSI_LOW_DIAGNOSTIC 195367468Snon printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); 195467468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 195567468Snon } 195667468Snon 195767468Snon /* 195867468Snon * OK. clear flags. 195967468Snon */ 196067468Snon ti->ti_tflags &= ~TARG_ASSERT_ATN; 196167468Snon 196267468Snon /* STEP III. 196367468Snon * We have no msgs. send MSG_LOOP (OK?) 196467468Snon */ 196567468Snon if (scsi_low_is_msgout_continue(ti) == 0) 196667468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); 196767468Snon 196867468Snon /* STEP IV. 196967468Snon * Process all msgs 197067468Snon */ 197167468Snon ti->ti_msgoutlen = 0; 197267468Snon mdp = &scsi_low_msgout_data[0]; 197367468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 197467468Snon { 197567468Snon if ((ti->ti_msgflags & mdp->md_flags) != 0) 197667468Snon { 197767468Snon ti->ti_omsgflags |= mdp->md_flags; 197867468Snon ti->ti_msgflags &= ~mdp->md_flags; 197967468Snon ti->ti_emsgflags = mdp->md_flags; 198067468Snon 198167468Snon ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; 198267468Snon if (mdp->md_msgfunc != NULL) 198367468Snon len = (*mdp->md_msgfunc) (ti); 198467468Snon else 198567468Snon len = 1; 198667468Snon 198767468Snon ti->ti_msgoutlen += len; 198867468Snon if ((slp->sl_cfgflags & CFG_MSGUNIFY) == 0 || 198967468Snon ti->ti_msgflags == 0) 199067468Snon break; 199167468Snon if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) 199267468Snon break; 199367468Snon } 199467468Snon } 199567468Snon 199667468Snon if (scsi_low_is_msgout_continue(ti) != 0) 199767468Snon { 199867468Snon#ifdef SCSI_LOW_DIAGNOSTIC 199967468Snon printf("SCSI_LOW_ATTENTION(msgout): 0x%x\n", ti->ti_msgflags); 200067468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 200167468Snon scsi_low_attention(slp, ti); 200267468Snon } 200367468Snon 200467468Snon /* 200567468Snon * OK. advance old phase. 200667468Snon */ 200767468Snon ti->ti_ophase = ti->ti_phase; 200867468Snon return ti->ti_msgoutlen; 200967468Snon} 201067468Snon 201167468Snon/************************************************************** 201267468Snon * msgin 201367468Snon **************************************************************/ 201467468Snonstatic int 201567468Snonscsi_low_msginfunc_noop(ti) 201667468Snon struct targ_info *ti; 201767468Snon{ 201867468Snon 201967468Snon return 0; 202067468Snon} 202167468Snon 202267468Snonstatic int 202367468Snonscsi_low_msginfunc_rejop(ti) 202467468Snon struct targ_info *ti; 202567468Snon{ 202667468Snon struct scsi_low_softc *slp = ti->ti_sc; 202767468Snon u_int8_t msg = ti->ti_msgin[0]; 202867468Snon 202967468Snon printf("%s: MSGIN: msg 0x%x reject\n", slp->sl_xname, (u_int) msg); 203067468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 203167468Snon return 0; 203267468Snon} 203367468Snon 203467468Snonstatic int 203567468Snonscsi_low_msginfunc_cc(ti) 203667468Snon struct targ_info *ti; 203767468Snon{ 203867468Snon struct scsi_low_softc *slp = ti->ti_sc; 203967468Snon 204067468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 204167468Snon return 0; 204267468Snon} 204367468Snon 204467468Snonstatic int 204567468Snonscsi_low_msginfunc_disc(ti) 204667468Snon struct targ_info *ti; 204767468Snon{ 204867468Snon struct scsi_low_softc *slp = ti->ti_sc; 204967468Snon 205067468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); 205167468Snon return 0; 205267468Snon} 205367468Snon 205467468Snonstatic int 205567468Snonscsi_low_msginfunc_sdp(ti) 205667468Snon struct targ_info *ti; 205767468Snon{ 205867468Snon struct scsi_low_softc *slp = ti->ti_sc; 205967468Snon 206067468Snon if (ti->ti_nexus != NULL) 206167468Snon ti->ti_nexus->ccb_sscp = slp->sl_scp; 206267468Snon else 206367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 206467468Snon return 0; 206567468Snon} 206667468Snon 206767468Snonstatic int 206867468Snonscsi_low_msginfunc_rdp(ti) 206967468Snon struct targ_info *ti; 207067468Snon{ 207167468Snon struct scsi_low_softc *slp = ti->ti_sc; 207267468Snon 207367468Snon if (ti->ti_nexus != NULL) 207467468Snon slp->sl_scp = ti->ti_nexus->ccb_sscp; 207567468Snon else 207667468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 207767468Snon return 0; 207867468Snon} 207967468Snon 208067468Snonstatic int 208167468Snonscsi_low_synch(ti) 208267468Snon struct targ_info *ti; 208367468Snon{ 208467468Snon struct scsi_low_softc *slp = ti->ti_sc; 208567468Snon struct lun_info *li = ti->ti_li; 208671508Sjhb u_int period = 0, offset = 0; 208771508Sjhb#ifdef SCSI_LOW_INFORM 208871508Sjhb u_int speed; 208971508Sjhb#endif 209067468Snon u_char *s; 209167468Snon int error; 209267468Snon 209367468Snon if (MSGIN_PERIOD(ti) >= li->li_maxsynch.period && 209467468Snon MSGIN_OFFSET(ti) <= li->li_maxsynch.offset) 209567468Snon { 209667468Snon if ((offset = MSGIN_OFFSET(ti)) != 0) 209767468Snon period = MSGIN_PERIOD(ti); 209867468Snon s = offset ? "synchronous" : "async"; 209967468Snon } 210067468Snon else 210167468Snon { 210267468Snon /* XXX: 210367468Snon * Target seems to be brain damaged. 210467468Snon * Force async transfer. 210567468Snon */ 210667468Snon li->li_maxsynch.period = 0; 210767468Snon li->li_maxsynch.offset = 0; 210867468Snon printf("%s: target brain damaged. async transfer\n", 210967468Snon slp->sl_xname); 211067468Snon return EINVAL; 211167468Snon } 211267468Snon 211367468Snon li->li_maxsynch.period = period; 211467468Snon li->li_maxsynch.offset = offset; 211567468Snon 211667468Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); 211767468Snon if (error != 0) 211867468Snon { 211967468Snon /* XXX: 212067468Snon * Current period and offset are not acceptable 212167468Snon * for our adapter. 212267468Snon * The adapter changes max synch and max offset. 212367468Snon */ 212467468Snon printf("%s: synch neg failed. retry synch msg neg ...\n", 212567468Snon slp->sl_xname); 212667468Snon return error; 212767468Snon } 212867468Snon 212967468Snon#ifdef SCSI_LOW_INFORM 213067468Snon /* inform data */ 213167468Snon printf("%s(%d:%d): <%s> offset %d period %dns ", 213267468Snon slp->sl_xname, ti->ti_id, li->li_lun, s, offset, period * 4); 213367468Snon if (period != 0) 213467468Snon { 213567468Snon speed = 1000 * 10 / (period * 4); 213667468Snon printf("%d.%d M/s", speed / 10, speed % 10); 213767468Snon } 213867468Snon printf("\n"); 213967468Snon#endif 214067468Snon 214167468Snon return 0; 214267468Snon} 214367468Snon 214467468Snonstatic int 214567468Snonscsi_low_msginfunc_ext(ti) 214667468Snon struct targ_info *ti; 214767468Snon{ 214867468Snon struct scsi_low_softc *slp = ti->ti_sc; 214967468Snon struct slccb *cb = ti->ti_nexus; 215067468Snon struct lun_info *li = ti->ti_li; 215167468Snon int count, retry; 215267468Snon u_int32_t *ptr; 215367468Snon 215467468Snon if (ti->ti_msginptr == 2) 215567468Snon { 215667468Snon ti->ti_msginlen = ti->ti_msgin[1] + 2; 215767468Snon return 0; 215867468Snon } 215967468Snon 216067468Snon switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) 216167468Snon { 216267468Snon case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): 216367468Snon if (cb == NULL) 216467468Snon break; 216567468Snon 216667468Snon ptr = (u_int32_t *)(&ti->ti_msgin[3]); 216767468Snon count = (int) htonl((long) (*ptr)); 216867468Snon if(slp->sl_scp.scp_datalen - count < 0 || 216967468Snon slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) 217067468Snon break; 217167468Snon 217267468Snon slp->sl_scp.scp_datalen -= count; 217367468Snon slp->sl_scp.scp_data += count; 217467468Snon return 0; 217567468Snon 217667468Snon case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): 217767468Snon if (li == NULL) 217867468Snon break; 217967468Snon 218067468Snon retry = scsi_low_synch(ti); 218167468Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) 218267468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 218367468Snon return 0; 218467468Snon 218567468Snon case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): 218667468Snon if (li == NULL) 218767468Snon break; 218867468Snon 218967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 219067468Snon return 0; 219167468Snon 219267468Snon default: 219367468Snon break; 219467468Snon } 219567468Snon 219667468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 219767468Snon return EINVAL; 219867468Snon} 219967468Snon 220067468Snonstatic void 220167468Snonscsi_low_retry_phase(ti) 220267468Snon struct targ_info *ti; 220367468Snon{ 220467468Snon 220567468Snon switch (ti->ti_sphase) 220667468Snon { 220767468Snon case PH_MSGOUT: 220867468Snon ti->ti_msgflags |= ti->ti_omsgflags; 220967468Snon break; 221067468Snon 221167468Snon default: 221267468Snon break; 221367468Snon } 221467468Snon} 221567468Snon 221667468Snonstatic int 221767468Snonscsi_low_msginfunc_parity(ti) 221867468Snon struct targ_info *ti; 221967468Snon{ 222067468Snon struct scsi_low_softc *slp = ti->ti_sc; 222167468Snon 222267468Snon if (ti->ti_sphase != PH_MSGOUT) 222367468Snon slp->sl_error |= PARITYERR; 222467468Snon scsi_low_retry_phase(ti); 222567468Snon return 0; 222667468Snon} 222767468Snon 222867468Snonstatic int 222967468Snonscsi_low_msginfunc_msg_reject(ti) 223067468Snon struct targ_info *ti; 223167468Snon{ 223267468Snon struct scsi_low_softc *slp = ti->ti_sc; 223367468Snon struct lun_info *li = ti->ti_li; 223467468Snon struct scsi_low_msgout_data *mdp; 223567468Snon u_int msgflags; 223667468Snon 223767468Snon if (li == NULL) 223867468Snon { 223967468Snon /* not yet lun nexus established! */ 224067468Snon goto out; 224167468Snon } 224267468Snon 224367468Snon switch (ti->ti_sphase) 224467468Snon { 224567468Snon case PH_CMD: 224667468Snon slp->sl_error |= CMDREJECT; 224767468Snon break; 224867468Snon 224967468Snon case PH_MSGOUT: 225067468Snon if (ti->ti_emsgflags == 0) 225167468Snon break; 225267468Snon 225367468Snon msgflags = SCSI_LOW_MSG_REJECT; 225467468Snon mdp = &scsi_low_msgout_data[0]; 225567468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 225667468Snon { 225767468Snon if ((ti->ti_emsgflags & mdp->md_flags) != 0) 225867468Snon { 225967468Snon ti->ti_emsgflags &= ~mdp->md_flags; 226067468Snon if (mdp->md_errfunc != NULL) 226167468Snon (*mdp->md_errfunc) (ti, msgflags); 226267468Snon break; 226367468Snon } 226467468Snon } 226567468Snon break; 226667468Snon 226767468Snon default: 226867468Snon break; 226967468Snon } 227067468Snon 227167468Snonout: 227267468Snon scsi_low_info(slp, ti, "msg rejected"); 227367468Snon slp->sl_error |= MSGERR; 227467468Snon return 0; 227567468Snon} 227667468Snon 227767468Snonvoid 227867468Snonscsi_low_msgin(slp, ti, c) 227967468Snon struct scsi_low_softc *slp; 228067468Snon struct targ_info *ti; 228167468Snon u_int8_t c; 228267468Snon{ 228367468Snon struct scsi_low_msgin_data *sdp; 228467468Snon struct lun_info *li; 228567468Snon u_int8_t msg; 228667468Snon 228767468Snon /* 228867468Snon * Phase changes, clear the pointer. 228967468Snon */ 229067468Snon if (ti->ti_ophase != ti->ti_phase) 229167468Snon { 229267468Snon ti->ti_sphase = ti->ti_ophase; 229367468Snon ti->ti_ophase = ti->ti_phase; 229467468Snon MSGINPTR_CLR(ti); 229567468Snon#ifdef SCSI_LOW_DIAGNOSTIC 229667468Snon ti->ti_msgin_hist_pointer = 0; 229767468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 229867468Snon } 229967468Snon 230067468Snon /* 230167468Snon * Store a current messages byte into buffer and 230267468Snon * wait for the completion of the current msg. 230367468Snon */ 230467468Snon ti->ti_msgin[ti->ti_msginptr ++] = c; 230567468Snon if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) 230667468Snon { 230767468Snon ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; 230867468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 230967468Snon } 231067468Snon 231167468Snon /* 231267468Snon * Calculate messages length. 231367468Snon */ 231467468Snon msg = ti->ti_msgin[0]; 231567468Snon if (msg < MSGIN_DATA_LAST) 231667468Snon sdp = &scsi_low_msgin_data[msg]; 231767468Snon else 231867468Snon sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; 231967468Snon 232067468Snon if (ti->ti_msginlen == 0) 232167468Snon { 232267468Snon ti->ti_msginlen = sdp->md_len; 232367468Snon#ifdef SCSI_LOW_DIAGNOSTIC 232467468Snon if (ti->ti_msgin_hist_pointer < MSGIN_HISTORY_LEN) 232567468Snon { 232667468Snon ti->ti_msgin_history[ti->ti_msgin_hist_pointer] = msg; 232767468Snon ti->ti_msgin_hist_pointer ++; 232867468Snon } 232967468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 233067468Snon } 233167468Snon 233267468Snon /* 233367468Snon * Check comletion. 233467468Snon */ 233567468Snon if (ti->ti_msginptr < ti->ti_msginlen) 233667468Snon return; 233767468Snon 233867468Snon /* 233967468Snon * Do process. 234067468Snon */ 234167468Snon if ((msg & MSG_IDENTIFY) == 0) 234267468Snon { 234367468Snon (void) ((*sdp->md_msgfunc) (ti)); 234467468Snon } 234567468Snon else 234667468Snon { 234767468Snon li = ti->ti_li; 234867468Snon if (li == NULL) 234967468Snon { 235067468Snon li = scsi_low_establish_lun(ti, MSGCMD_LUN(msg)); 235167468Snon if (li == NULL) 235267468Snon goto badlun; 235367468Snon } 235467468Snon 235567468Snon if (ti->ti_nexus == NULL) 235667468Snon { 235767468Snon /* XXX: 235867468Snon * move the following functions to 235967468Snon * tag queue msg process in the future. 236067468Snon */ 236167468Snon if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) 236267468Snon goto badlun; 236367468Snon } 236467468Snon 236567468Snon if (MSGCMD_LUN(msg) != li->li_lun) 236667468Snon goto badlun; 236767468Snon } 236867468Snon 236967468Snon /* 237067468Snon * Msg process completed, reset msin pointer and assert ATN if desired. 237167468Snon */ 237267468Snon if (ti->ti_msginptr >= ti->ti_msginlen) 237367468Snon { 237467468Snon ti->ti_sphase = ti->ti_phase; 237567468Snon MSGINPTR_CLR(ti); 237667468Snon 237767468Snon if (scsi_low_is_msgout_continue(ti) != 0) 237867468Snon { 237967468Snon#ifdef SCSI_LOW_DIAGNOSTIC 238067468Snon printf("SCSI_LOW_ATTETION(msgin): 0x%x\n", 238167468Snon ti->ti_msgflags); 238267468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 238367468Snon scsi_low_attention(slp, ti); 238467468Snon } 238567468Snon } 238667468Snon return; 238767468Snon 238867468Snonbadlun: 238967468Snon scsi_low_info(slp, ti, "MSGIN: identify lun mismatch"); 239067468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 239167468Snon} 239267468Snon 239367468Snon/************************************************************** 239467468Snon * Qurik setup 239567468Snon **************************************************************/ 239667468Snon#define MAXOFFSET 0x10 239767468Snon 239867468Snonstatic void 239967468Snonscsi_low_calcf(ti, li) 240067468Snon struct targ_info *ti; 240167468Snon struct lun_info *li; 240267468Snon{ 240367468Snon u_int period; 240467468Snon u_int8_t offset; 240567468Snon struct scsi_low_softc *slp = ti->ti_sc; 240667468Snon 240767468Snon li->li_flags &= ~SCSI_LOW_DISC; 240867468Snon if ((slp->sl_cfgflags & CFG_NODISC) == 0 && 240967468Snon#ifdef SDEV_NODISC 241067468Snon (li->li_quirks & SDEV_NODISC) == 0 && 241167468Snon#endif /* SDEV_NODISC */ 241267468Snon (li->li_cfgflags & SCSI_LOW_DISC) != 0) 241367468Snon li->li_flags |= SCSI_LOW_DISC; 241467468Snon 241567468Snon li->li_flags |= SCSI_LOW_NOPARITY; 241667468Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && 241767468Snon#ifdef SDEV_NOPARITY 241867468Snon (li->li_quirks & SDEV_NOPARITY) == 0 && 241967468Snon#endif /* SDEV_NOPARITY */ 242067468Snon (li->li_cfgflags & SCSI_LOW_NOPARITY) == 0) 242167468Snon li->li_flags &= ~SCSI_LOW_NOPARITY; 242267468Snon 242367468Snon li->li_flags &= ~SCSI_LOW_SYNC; 242467468Snon if ((li->li_cfgflags & SCSI_LOW_SYNC) && 242567468Snon (slp->sl_cfgflags & CFG_ASYNC) == 0) 242667468Snon { 242767468Snon offset = SCSI_LOW_OFFSET(li->li_cfgflags); 242867468Snon if (offset > li->li_maxsynch.offset) 242967468Snon offset = li->li_maxsynch.offset; 243067468Snon li->li_flags |= SCSI_LOW_SYNC; 243167468Snon } 243267468Snon else 243367468Snon offset = 0; 243467468Snon 243567468Snon if (offset > 0) 243667468Snon { 243767468Snon period = SCSI_LOW_PERIOD(li->li_cfgflags); 243867468Snon if (period > SCSI_LOW_MAX_SYNCH_SPEED) 243967468Snon period = SCSI_LOW_MAX_SYNCH_SPEED; 244067468Snon if (period != 0) 244167468Snon period = 1000 * 10 / (period * 4); 244267468Snon if (period < li->li_maxsynch.period) 244367468Snon period = li->li_maxsynch.period; 244467468Snon } 244567468Snon else 244667468Snon period = 0; 244767468Snon 244867468Snon li->li_maxsynch.offset = offset; 244967468Snon li->li_maxsynch.period = period; 245067468Snon} 245167468Snon 245267468Snon#ifdef SCSI_LOW_TARGET_OPEN 245367468Snonstatic int 245467468Snonscsi_low_target_open(link, cf) 245567468Snon struct scsipi_link *link; 245667468Snon struct cfdata *cf; 245767468Snon{ 245867468Snon u_int target = link->scsipi_scsi.target; 245967468Snon u_int lun = link->scsipi_scsi.lun; 246067468Snon struct scsi_low_softc *slp; 246167468Snon struct targ_info *ti; 246267468Snon struct lun_info *li; 246367468Snon 246467468Snon slp = (struct scsi_low_softc *) link->adapter_softc; 246567468Snon ti = slp->sl_ti[target]; 246667468Snon li = scsi_low_alloc_li(ti, lun, 0); 246767468Snon if (li == NULL) 246867468Snon return 0; 246967468Snon 247067468Snon li->li_quirks = (u_int) link->quirks; 247167468Snon li->li_cfgflags = cf->cf_flags; 247267468Snon if (li->li_state > UNIT_SYNCH) 247367468Snon li->li_state = UNIT_SYNCH; 247467468Snon 247567468Snon scsi_low_calcf(ti, li); 247667468Snon 247767468Snon printf("%s(%d:%d): max period(%dns) max offset(%d) flags 0x%b\n", 247867468Snon slp->sl_xname, target, lun, 247967468Snon li->li_maxsynch.period * 4, 248067468Snon li->li_maxsynch.offset, 248167468Snon li->li_flags, SCSI_LOW_BITS); 248267468Snon return 0; 248367468Snon} 248467468Snon#endif /* SCSI_LOW_TARGET_OPEN */ 248567468Snon 248667468Snon/********************************************************** 248767468Snon * DEBUG SECTION 248867468Snon **********************************************************/ 248967468Snonstatic void 249067468Snonscsi_low_info(slp, ti, s) 249167468Snon struct scsi_low_softc *slp; 249267468Snon struct targ_info *ti; 249367468Snon u_char *s; 249467468Snon{ 249567468Snon 249667468Snon printf("%s: SCSI_LOW: %s\n", slp->sl_xname, s); 249767468Snon if (ti == NULL) 249867468Snon { 249971999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 250071999Sphk ti = TAILQ_NEXT(ti, ti_chain)) 250167468Snon scsi_low_print(slp, ti); 250267468Snon } 250367468Snon else 250467468Snon scsi_low_print(slp, ti); 250567468Snon 250667468Snon} 250767468Snon 250867468Snonstatic u_char *phase[] = 250967468Snon{ 251067468Snon "FREE", "ARBSTART", "SELSTART", "SELECTED", 251167468Snon "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" 251267468Snon}; 251367468Snon 251467468Snonvoid 251567468Snonscsi_low_print(slp, ti) 251667468Snon struct scsi_low_softc *slp; 251767468Snon struct targ_info *ti; 251867468Snon{ 251967468Snon struct slccb *cb = NULL; 252067468Snon 252167468Snon if (ti == NULL) 252267468Snon ti = slp->sl_nexus; 252367468Snon if (ti != NULL) 252467468Snon cb = ti->ti_nexus; 252567468Snon 252667468Snon printf("%s: TARGET(0x%lx) T_NEXUS(0x%lx) C_NEXUS(0x%lx) NDISCS(%d)\n", 252767468Snon slp->sl_xname, (u_long) ti, (u_long) slp->sl_nexus, 252867468Snon (u_long) cb, slp->sl_disc); 252967468Snon 253067468Snon /* target stat */ 253167468Snon if (ti != NULL) 253267468Snon { 253367468Snon struct sc_p *sp = &slp->sl_scp; 253467468Snon struct lun_info *li = ti->ti_li; 253567468Snon u_int flags = 0; 253667468Snon int lun = -1; 253767468Snon 253867468Snon if (li != NULL) 253967468Snon { 254067468Snon lun = li->li_lun; 254167468Snon flags = li->li_flags; 254267468Snon } 254367468Snon 254467468Snon printf("%s(%d:%d) ph<%s> => ph<%s>\n", slp->sl_xname, 254567468Snon ti->ti_id, lun, phase[(int) ti->ti_ophase], 254667468Snon phase[(int) ti->ti_phase]); 254767468Snon 254867468Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] STATUSIN: 0x%x T_FLAGS: 0x%x\n", 254967468Snon (u_int) (ti->ti_msginptr), 255067468Snon (u_int) (ti->ti_msgin[0]), 255167468Snon (u_int) (ti->ti_msgin[1]), 255267468Snon (u_int) (ti->ti_msgin[2]), 255367468Snon (u_int) (ti->ti_msgin[3]), 255467468Snon (u_int) (ti->ti_msgin[4]), 255567468Snon ti->ti_status, ti->ti_tflags); 255667468Snon#ifdef SCSI_LOW_DIAGNOSTIC 255767468Snonprintf("MSGIN HISTORY: (%d) [0x%x] => [0x%x] => [0x%x] => [0x%x] => [0x%x]\n", 255867468Snon ti->ti_msgin_hist_pointer, 255967468Snon (u_int) (ti->ti_msgin_history[0]), 256067468Snon (u_int) (ti->ti_msgin_history[1]), 256167468Snon (u_int) (ti->ti_msgin_history[2]), 256267468Snon (u_int) (ti->ti_msgin_history[3]), 256367468Snon (u_int) (ti->ti_msgin_history[4])); 256467468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 256567468Snon 256667468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", 256767468Snon (u_int) ti->ti_msgflags, 256867468Snon (u_int) (ti->ti_msgoutstr[0]), 256967468Snon (u_int) (ti->ti_msgoutstr[1]), 257067468Snon (u_int) (ti->ti_msgoutstr[2]), 257167468Snon (u_int) (ti->ti_msgoutstr[3]), 257267468Snon (u_int) (ti->ti_msgoutstr[4]), 257367468Snon ti->ti_msgoutlen, 257467468Snon flags, SCSI_LOW_BITS); 257567468Snon 257667468Snonprintf("SCP: datalen 0x%x dataaddr 0x%lx ", 257767468Snon sp->scp_datalen, 257867468Snon (u_long) sp->scp_data); 257967468Snon 258067468Snon if (cb != NULL) 258167468Snon { 258267468Snonprintf("CCB: cmdlen %x cmdaddr %lx cmd[0] %x datalen %x", 258367468Snon cb->ccb_scp.scp_cmdlen, 258467468Snon (u_long) cb->ccb_scp.scp_cmd, 258567468Snon (u_int) cb->ccb_scp.scp_cmd[0], 258667468Snon cb->ccb_scp.scp_datalen); 258767468Snon } 258867468Snon printf("\n"); 258967468Snon } 259067468Snon printf("error flags %b\n", slp->sl_error, SCSI_LOW_ERRORBITS); 259167468Snon} 2592