Home | History | Annotate | Line # | Download | only in boot
siop.c revision 1.10
      1  1.10    andvar /*	$NetBSD: siop.c,v 1.10 2022/05/23 19:21:30 andvar Exp $	*/
      2   1.1  kiyohara /*
      3   1.1  kiyohara  * Copyright (c) 2010 KIYOHARA Takashi
      4   1.1  kiyohara  * All rights reserved.
      5   1.1  kiyohara  *
      6   1.1  kiyohara  * Redistribution and use in source and binary forms, with or without
      7   1.1  kiyohara  * modification, are permitted provided that the following conditions
      8   1.1  kiyohara  * are met:
      9   1.1  kiyohara  * 1. Redistributions of source code must retain the above copyright
     10   1.1  kiyohara  *    notice, this list of conditions and the following disclaimer.
     11   1.1  kiyohara  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1  kiyohara  *    notice, this list of conditions and the following disclaimer in the
     13   1.1  kiyohara  *    documentation and/or other materials provided with the distribution.
     14   1.1  kiyohara  *
     15   1.1  kiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16   1.1  kiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17   1.1  kiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18   1.1  kiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     19   1.1  kiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20   1.1  kiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21   1.1  kiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22   1.1  kiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     23   1.1  kiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     24   1.1  kiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25   1.1  kiyohara  * POSSIBILITY OF SUCH DAMAGE.
     26   1.1  kiyohara  */
     27   1.1  kiyohara 
     28   1.1  kiyohara #include <lib/libsa/stand.h>
     29   1.1  kiyohara #include <lib/libkern/libkern.h>
     30   1.1  kiyohara 
     31   1.1  kiyohara #include <dev/microcode/siop/siop.out>
     32   1.1  kiyohara 
     33   1.1  kiyohara #include "boot.h"
     34   1.1  kiyohara #include "sdvar.h"
     35   1.1  kiyohara 
     36   1.4       phx #ifdef DEBUG
     37   1.4       phx #define DPRINTF(x)	printf x
     38   1.4       phx #else
     39   1.4       phx #define DPRINTF(x)
     40   1.4       phx #endif
     41   1.4       phx 
     42   1.1  kiyohara #define ALLOC(T, A)	\
     43   1.1  kiyohara 		(T *)(((uint32_t)alloc(sizeof(T) + (A)) + (A)) & ~((A) - 1))
     44   1.1  kiyohara #define VTOPHYS(va)	(uint32_t)(va)
     45   1.1  kiyohara #define DEVTOV(pa)	(uint32_t)(pa)
     46   1.1  kiyohara #define wbinv(adr, siz)	_wbinv(VTOPHYS(adr), (uint32_t)(siz))
     47   1.1  kiyohara #define inv(adr, siz)	_inv(VTOPHYS(adr), (uint32_t)(siz))
     48   1.1  kiyohara 
     49   1.1  kiyohara /* 53c810 supports little endian */
     50   1.1  kiyohara #define htoc32(x)	htole32(x)
     51   1.1  kiyohara #define ctoh32(x)	le32toh(x)
     52   1.1  kiyohara 
     53   1.1  kiyohara static void siop_pci_reset(int);
     54   1.1  kiyohara 
     55   1.1  kiyohara static void siop_setuptables(struct siop_adapter *, struct siop_xfer *,
     56   1.1  kiyohara 			     struct scsi_xfer *);
     57   1.1  kiyohara static void siop_ma(struct siop_adapter *, struct scsi_xfer *);
     58   1.1  kiyohara static void siop_sdp(struct siop_adapter *, struct siop_xfer *,
     59   1.1  kiyohara 		     struct scsi_xfer *, int);
     60   1.1  kiyohara static void siop_update_resid(struct siop_adapter *, struct siop_xfer *,
     61   1.1  kiyohara 			      struct scsi_xfer *, int);
     62   1.1  kiyohara 
     63   1.1  kiyohara static int siop_intr(struct siop_adapter *);
     64   1.1  kiyohara static void siop_scsicmd_end(struct siop_adapter *, struct scsi_xfer *);
     65   1.1  kiyohara static int siop_scsi_request(struct siop_adapter *, struct scsi_xfer *);
     66   1.1  kiyohara static void siop_start(struct siop_adapter *, struct scsi_xfer *);
     67   1.1  kiyohara static void siop_xfer_setup(struct siop_xfer *, void *);
     68   1.1  kiyohara 
     69   1.1  kiyohara static int siop_add_reselsw(struct siop_adapter *, int, int);
     70   1.1  kiyohara static void siop_update_scntl3(struct siop_adapter *, int, int);
     71   1.1  kiyohara 
     72   1.1  kiyohara static int _scsi_inquire(struct siop_adapter *, int, int, int, char *);
     73   1.1  kiyohara static void scsi_request_sense(struct siop_adapter *, struct scsi_xfer *);
     74   1.1  kiyohara static int scsi_interpret_sense(struct siop_adapter *, struct scsi_xfer *);
     75   1.1  kiyohara static int scsi_probe(struct siop_adapter *);
     76   1.1  kiyohara 
     77   1.1  kiyohara static struct siop_adapter adapt;
     78   1.1  kiyohara 
     79   1.1  kiyohara 
     80   1.1  kiyohara static void
     81   1.1  kiyohara siop_pci_reset(int addr)
     82   1.1  kiyohara {
     83   1.1  kiyohara 	int dmode, ctest5;
     84   1.1  kiyohara 	const int maxburst = 4;			/* 53c810 */
     85   1.1  kiyohara 
     86   1.1  kiyohara 	dmode = readb(addr + SIOP_DMODE);
     87   1.1  kiyohara 
     88   1.1  kiyohara 	ctest5 = readb(addr + SIOP_CTEST5);
     89   1.1  kiyohara 	writeb(addr + SIOP_CTEST4, readb(addr + SIOP_CTEST4) & ~CTEST4_BDIS);
     90   1.1  kiyohara 	ctest5 &= ~CTEST5_BBCK;
     91   1.1  kiyohara 	ctest5 |= (maxburst - 1) & CTEST5_BBCK;
     92   1.1  kiyohara 	writeb(addr + SIOP_CTEST5, ctest5);
     93   1.1  kiyohara 
     94   1.1  kiyohara 	dmode |= DMODE_ERL;
     95   1.1  kiyohara 	dmode &= ~DMODE_BL_MASK;
     96   1.1  kiyohara 	dmode |= ((maxburst - 1) << DMODE_BL_SHIFT) & DMODE_BL_MASK;
     97   1.1  kiyohara 	writeb(addr + SIOP_DMODE, dmode);
     98   1.1  kiyohara }
     99   1.1  kiyohara 
    100   1.1  kiyohara 
    101   1.1  kiyohara static void
    102   1.1  kiyohara siop_setuptables(struct siop_adapter *adp, struct siop_xfer *xfer,
    103   1.1  kiyohara 		 struct scsi_xfer *xs)
    104   1.1  kiyohara {
    105   1.1  kiyohara 	int msgoffset = 1;
    106   1.1  kiyohara 
    107   1.1  kiyohara 	xfer->siop_tables.id =
    108   1.1  kiyohara 	    htoc32((adp->clock_div << 24) | (xs->target << 16));
    109   1.1  kiyohara 	memset(xfer->siop_tables.msg_out, 0, sizeof(xfer->siop_tables.msg_out));
    110   1.1  kiyohara 	/* request sense doesn't disconnect */
    111   1.1  kiyohara 	if (xs->cmd->opcode == SCSI_REQUEST_SENSE)
    112   1.1  kiyohara 		xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 0);
    113   1.1  kiyohara 	else
    114   1.1  kiyohara 		xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 1);
    115   1.1  kiyohara 
    116   1.1  kiyohara 	xfer->siop_tables.t_msgout.count = htoc32(msgoffset);
    117   1.1  kiyohara 	xfer->siop_tables.status =
    118   1.1  kiyohara 	    htoc32(SCSI_SIOP_NOSTATUS); /* set invalid status */
    119   1.1  kiyohara 
    120   1.1  kiyohara 	xfer->siop_tables.cmd.count = htoc32(xs->cmdlen);
    121   1.1  kiyohara 	xfer->siop_tables.cmd.addr = htoc32(local_to_PCI((u_long)xs->cmd));
    122   1.1  kiyohara 	if (xs->datalen != 0) {
    123   1.1  kiyohara 		xfer->siop_tables.data[0].count = htoc32(xs->datalen);
    124   1.1  kiyohara 		xfer->siop_tables.data[0].addr =
    125   1.1  kiyohara 		    htoc32(local_to_PCI((u_long)xs->data));
    126   1.1  kiyohara 	}
    127   1.1  kiyohara }
    128   1.1  kiyohara 
    129   1.1  kiyohara static void
    130   1.1  kiyohara siop_ma(struct siop_adapter *adp, struct scsi_xfer *xs)
    131   1.1  kiyohara {
    132   1.1  kiyohara 	int offset, dbc;
    133   1.1  kiyohara 
    134   1.1  kiyohara 	/*
    135   1.1  kiyohara 	 * compute how much of the current table didn't get handled when
    136   1.1  kiyohara 	 * a phase mismatch occurs
    137   1.1  kiyohara 	 */
    138   1.1  kiyohara 	if (xs->datalen == 0)
    139   1.1  kiyohara 	    return; /* no valid data transfer */
    140   1.1  kiyohara 
    141   1.1  kiyohara 	offset = readb(adp->addr + SIOP_SCRATCHA + 1);
    142   1.1  kiyohara 	if (offset >= SIOP_NSG) {
    143   1.1  kiyohara 		printf("bad offset in siop_sdp (%d)\n", offset);
    144   1.1  kiyohara 		return;
    145   1.1  kiyohara 	}
    146   1.1  kiyohara 	dbc = readl(adp->addr + SIOP_DBC) & 0x00ffffff;
    147   1.1  kiyohara 	xs->resid = dbc;
    148   1.1  kiyohara }
    149   1.1  kiyohara 
    150   1.1  kiyohara static void
    151   1.4       phx siop_clearfifo(struct siop_adapter *adp)
    152   1.4       phx {
    153   1.4       phx 	int timo = 0;
    154   1.4       phx 	uint8_t ctest3 = readb(adp->addr + SIOP_CTEST3);
    155   1.4       phx 
    156   1.4       phx 	DPRINTF(("DMA FIFO not empty!\n"));
    157   1.4       phx 	writeb(adp->addr + SIOP_CTEST3, ctest3 | CTEST3_CLF);
    158   1.4       phx 	while ((readb(adp->addr + SIOP_CTEST3) & CTEST3_CLF) != 0) {
    159   1.4       phx 		delay(1);
    160   1.4       phx 		if (++timo > 1000) {
    161   1.4       phx 			printf("Clear FIFO failed!\n");
    162   1.4       phx 			writeb(adp->addr + SIOP_CTEST3,
    163   1.4       phx 			    readb(adp->addr + SIOP_CTEST3) & ~CTEST3_CLF);
    164   1.4       phx 			return;
    165   1.4       phx 		}
    166   1.4       phx 	}
    167   1.4       phx }
    168   1.4       phx 
    169   1.4       phx static void
    170   1.1  kiyohara siop_sdp(struct siop_adapter *adp, struct siop_xfer *xfer, struct scsi_xfer *xs,
    171   1.1  kiyohara 	 int offset)
    172   1.1  kiyohara {
    173   1.1  kiyohara 
    174   1.1  kiyohara 	if (xs->datalen == 0)
    175   1.1  kiyohara 	    return; /* no data pointers to save */
    176   1.1  kiyohara 
    177   1.1  kiyohara 	/*
    178   1.1  kiyohara 	 * offset == SIOP_NSG may be a valid condition if we get a Save data
    179   1.1  kiyohara 	 * pointer when the xfer is done. Just ignore the Save data pointer
    180   1.1  kiyohara 	 * in this case
    181   1.1  kiyohara 	 */
    182   1.1  kiyohara 	if (offset == SIOP_NSG)
    183   1.1  kiyohara 		return;
    184   1.1  kiyohara 	/*
    185   1.1  kiyohara 	 * Save data pointer. We do this by adjusting the tables to point
    186   1.7   msaitoh 	 * at the begginning of the data not yet transferred.
    187   1.7   msaitoh 	 * offset points to the first table with untransferred data.
    188   1.1  kiyohara 	 */
    189   1.1  kiyohara 
    190   1.1  kiyohara 	/*
    191   1.9    andvar 	 * before doing that we decrease resid from the amount of data which
    192   1.7   msaitoh 	 * has been transferred.
    193   1.1  kiyohara 	 */
    194   1.1  kiyohara 	siop_update_resid(adp, xfer, xs, offset);
    195   1.1  kiyohara 
    196   1.1  kiyohara #if 0
    197   1.1  kiyohara 	/*
    198   1.1  kiyohara 	 * First let see if we have a resid from a phase mismatch. If so,
    199   1.7   msaitoh 	 * we have to adjst the table at offset to remove transferred data.
    200   1.1  kiyohara 	 */
    201   1.1  kiyohara 	if (siop_cmd->flags & CMDFL_RESID) {
    202   1.1  kiyohara 		scr_table_t *table;
    203   1.1  kiyohara 
    204   1.1  kiyohara 		siop_cmd->flags &= ~CMDFL_RESID;
    205   1.1  kiyohara 		table = &xfer->siop_tables.data[offset];
    206   1.7   msaitoh 		/* "cut" already transferred data from this table */
    207   1.1  kiyohara 		table->addr =
    208   1.1  kiyohara 		    htoc32(ctoh32(table->addr) + ctoh32(table->count) -
    209   1.1  kiyohara 							siop_cmd->resid);
    210   1.1  kiyohara 		table->count = htoc32(siop_cmd->resid);
    211   1.1  kiyohara 	}
    212   1.1  kiyohara #endif
    213   1.1  kiyohara 
    214   1.1  kiyohara 	/*
    215   1.7   msaitoh 	 * now we can remove entries which have been transferred.
    216  1.10    andvar 	 * We just move the entries with data left at the beginning of the
    217   1.1  kiyohara 	 * tables
    218   1.1  kiyohara 	 */
    219   1.1  kiyohara 	memmove(xfer->siop_tables.data, &xfer->siop_tables.data[offset],
    220   1.1  kiyohara 	    (SIOP_NSG - offset) * sizeof(scr_table_t));
    221   1.1  kiyohara }
    222   1.1  kiyohara 
    223   1.1  kiyohara static void
    224   1.1  kiyohara siop_update_resid(struct siop_adapter *adp, struct siop_xfer *xfer,
    225   1.1  kiyohara 		  struct scsi_xfer *xs, int offset)
    226   1.1  kiyohara {
    227   1.1  kiyohara 	int i;
    228   1.1  kiyohara 
    229   1.1  kiyohara 	if (xs->datalen == 0)
    230   1.1  kiyohara 	    return; /* no data to transfer */
    231   1.1  kiyohara 
    232   1.1  kiyohara 	/*
    233   1.1  kiyohara 	 * update resid. First account for the table entries which have
    234   1.1  kiyohara 	 * been fully completed.
    235   1.1  kiyohara 	 */
    236   1.1  kiyohara 	for (i = 0; i < offset; i++)
    237   1.1  kiyohara 		xs->resid -= ctoh32(xfer->siop_tables.data[i].count);
    238   1.1  kiyohara #if 0
    239   1.1  kiyohara 	/*
    240   1.1  kiyohara 	 * if CMDFL_RESID is set, the last table (pointed by offset) is a
    241   1.1  kiyohara 	 * partial transfers. If not, offset points to the entry folloing
    242   1.1  kiyohara 	 * the last full transfer.
    243   1.1  kiyohara 	 */
    244   1.1  kiyohara 	if (siop_cmd->flags & CMDFL_RESID) {
    245   1.1  kiyohara 		scr_table_t *table = &xfer->siop_tables.data[offset];
    246   1.1  kiyohara 
    247   1.1  kiyohara 		xs->resid -= ctoh32(table->count) - xs->resid;
    248   1.1  kiyohara 	}
    249   1.1  kiyohara #endif
    250   1.1  kiyohara }
    251   1.1  kiyohara 
    252   1.1  kiyohara 
    253   1.1  kiyohara #define CALL_SCRIPT(ent)	writel(adp->addr + SIOP_DSP, scriptaddr + ent);
    254   1.1  kiyohara 
    255   1.1  kiyohara static int
    256   1.1  kiyohara siop_intr(struct siop_adapter *adp)
    257   1.1  kiyohara {
    258   1.1  kiyohara 	struct siop_xfer *siop_xfer = NULL;
    259   1.1  kiyohara 	struct scsi_xfer *xs = NULL;
    260   1.1  kiyohara 	u_long scriptaddr = local_to_PCI((u_long)adp->script);
    261   1.1  kiyohara 	int offset, target, lun, tag, restart = 0, need_reset = 0;
    262   1.1  kiyohara 	uint32_t dsa, irqcode;
    263   1.1  kiyohara 	uint16_t sist;
    264   1.1  kiyohara 	uint8_t dstat, sstat1, istat;
    265   1.1  kiyohara 
    266   1.1  kiyohara 	istat = readb(adp->addr + SIOP_ISTAT);
    267   1.1  kiyohara 	if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
    268   1.1  kiyohara 		return 0;
    269   1.1  kiyohara 	if (istat & ISTAT_INTF) {
    270   1.1  kiyohara 		printf("INTRF\n");
    271   1.1  kiyohara 		writeb(adp->addr + SIOP_ISTAT, ISTAT_INTF);
    272   1.1  kiyohara 	}
    273   1.1  kiyohara 	if ((istat & (ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
    274   1.1  kiyohara 	    (ISTAT_DIP | ISTAT_ABRT))
    275   1.1  kiyohara 		/* clear abort */
    276   1.1  kiyohara 		writeb(adp->addr + SIOP_ISTAT, 0);
    277   1.1  kiyohara 	/* use DSA to find the current siop_cmd */
    278   1.1  kiyohara 	dsa = readl(adp->addr + SIOP_DSA);
    279   1.1  kiyohara 	if (dsa >= local_to_PCI((u_long)adp->xfer) &&
    280   1.1  kiyohara 	    dsa < local_to_PCI((u_long)adp->xfer) + SIOP_TABLE_SIZE) {
    281   1.1  kiyohara 		dsa -= local_to_PCI((u_long)adp->xfer);
    282   1.1  kiyohara 		siop_xfer = adp->xfer;
    283   1.1  kiyohara 		_inv((u_long)siop_xfer, sizeof(*siop_xfer));
    284   1.1  kiyohara 
    285   1.1  kiyohara 		xs = adp->xs;
    286   1.1  kiyohara 	}
    287   1.1  kiyohara 
    288   1.1  kiyohara 	if (istat & ISTAT_DIP)
    289   1.1  kiyohara 		dstat = readb(adp->addr + SIOP_DSTAT);
    290   1.1  kiyohara 	if (istat & ISTAT_SIP) {
    291   1.1  kiyohara 		if (istat & ISTAT_DIP)
    292   1.1  kiyohara 			delay(10);
    293   1.1  kiyohara 		/*
    294   1.1  kiyohara 		 * Can't read sist0 & sist1 independently, or we have to
    295   1.1  kiyohara 		 * insert delay
    296   1.1  kiyohara 		 */
    297   1.1  kiyohara 		sist = readw(adp->addr + SIOP_SIST0);
    298   1.1  kiyohara 		sstat1 = readb(adp->addr + SIOP_SSTAT1);
    299   1.1  kiyohara 
    300   1.1  kiyohara 		if ((sist & SIST0_MA) && need_reset == 0) {
    301   1.1  kiyohara 			if (siop_xfer) {
    302   1.1  kiyohara 				int scratcha0;
    303   1.1  kiyohara 
    304   1.1  kiyohara 				dstat = readb(adp->addr + SIOP_DSTAT);
    305   1.1  kiyohara 				/*
    306   1.1  kiyohara 				 * first restore DSA, in case we were in a S/G
    307   1.1  kiyohara 				 * operation.
    308   1.1  kiyohara 				 */
    309   1.1  kiyohara 				writel(adp->addr + SIOP_DSA,
    310   1.1  kiyohara 				    local_to_PCI((u_long)siop_xfer));
    311   1.1  kiyohara 				scratcha0 = readb(adp->addr + SIOP_SCRATCHA);
    312   1.1  kiyohara 				switch (sstat1 & SSTAT1_PHASE_MASK) {
    313   1.1  kiyohara 				case SSTAT1_PHASE_STATUS:
    314   1.1  kiyohara 				/*
    315   1.1  kiyohara 				 * previous phase may be aborted for any reason
    316   1.1  kiyohara 				 * ( for example, the target has less data to
    317   1.1  kiyohara 				 * transfer than requested). Compute resid and
    318   1.1  kiyohara 				 * just go to status, the command should
    319   1.1  kiyohara 				 * terminate.
    320   1.1  kiyohara 				 */
    321   1.1  kiyohara 					if (scratcha0 & A_flag_data)
    322   1.1  kiyohara 						siop_ma(adp, xs);
    323   1.1  kiyohara 					else if ((dstat & DSTAT_DFE) == 0)
    324   1.4       phx 						siop_clearfifo(adp);
    325   1.1  kiyohara 					CALL_SCRIPT(Ent_status);
    326   1.1  kiyohara 					return 1;
    327   1.1  kiyohara 				case SSTAT1_PHASE_MSGIN:
    328   1.1  kiyohara 				/*
    329   1.1  kiyohara 				 * target may be ready to disconnect
    330   1.1  kiyohara 				 * Compute resid which would be used later
    331   1.1  kiyohara 				 * if a save data pointer is needed.
    332   1.1  kiyohara 				 */
    333   1.1  kiyohara 					if (scratcha0 & A_flag_data)
    334   1.1  kiyohara 						siop_ma(adp, xs);
    335   1.1  kiyohara 					else if ((dstat & DSTAT_DFE) == 0)
    336   1.4       phx 						siop_clearfifo(adp);
    337   1.1  kiyohara 					writeb(adp->addr + SIOP_SCRATCHA,
    338   1.1  kiyohara 					    scratcha0 & ~A_flag_data);
    339   1.1  kiyohara 					CALL_SCRIPT(Ent_msgin);
    340   1.1  kiyohara 					return 1;
    341   1.1  kiyohara 				}
    342   1.1  kiyohara 				printf("unexpected phase mismatch %d\n",
    343   1.1  kiyohara 				    sstat1 & SSTAT1_PHASE_MASK);
    344   1.1  kiyohara 			} else
    345   1.1  kiyohara 				printf("phase mismatch without command\n");
    346   1.1  kiyohara 			need_reset = 1;
    347   1.1  kiyohara 		}
    348   1.1  kiyohara 		if (sist & (SIST1_STO << 8)) {
    349   1.1  kiyohara 			/* selection time out, assume there's no device here */
    350   1.1  kiyohara 			if (siop_xfer) {
    351   1.1  kiyohara 				xs->error = XS_SELTIMEOUT;
    352   1.1  kiyohara 				goto end;
    353   1.1  kiyohara 			} else
    354   1.1  kiyohara 				printf("selection timeout without command\n");
    355   1.1  kiyohara 		}
    356   1.1  kiyohara 
    357   1.1  kiyohara 		/* Else it's an unhandled exception (for now). */
    358   1.1  kiyohara 		printf("unhandled scsi interrupt,"
    359   1.1  kiyohara 		    " sist=0x%x sstat1=0x%x DSA=0x%x DSP=0x%lx\n",
    360   1.1  kiyohara 		    sist, sstat1, dsa,
    361   1.1  kiyohara 		    readl(adp->addr + SIOP_DSP) - scriptaddr);
    362   1.1  kiyohara 		if (siop_xfer) {
    363   1.1  kiyohara 			xs->error = XS_SELTIMEOUT;
    364   1.1  kiyohara 			goto end;
    365   1.1  kiyohara 		}
    366   1.1  kiyohara 		need_reset = 1;
    367   1.1  kiyohara 	}
    368   1.1  kiyohara 	if (need_reset) {
    369   1.1  kiyohara reset:
    370   1.1  kiyohara 		printf("XXXXX: fatal error, need reset the bus...\n");
    371   1.1  kiyohara 		return 1;
    372   1.1  kiyohara 	}
    373   1.1  kiyohara 
    374   1.1  kiyohara //scintr:
    375   1.1  kiyohara 	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
    376   1.1  kiyohara 		irqcode = readl(adp->addr + SIOP_DSPS);
    377   1.1  kiyohara 		/*
    378   1.1  kiyohara 		 * no command, or an inactive command is only valid for a
    379   1.1  kiyohara 		 * reselect interrupt
    380   1.1  kiyohara 		 */
    381   1.1  kiyohara 		if ((irqcode & 0x80) == 0) {
    382   1.1  kiyohara 			if (siop_xfer == NULL) {
    383   1.1  kiyohara 				printf(
    384   1.1  kiyohara 				    "script interrupt 0x%x with invalid DSA\n",
    385   1.1  kiyohara 				    irqcode);
    386   1.1  kiyohara 				goto reset;
    387   1.1  kiyohara 			}
    388   1.1  kiyohara 		}
    389   1.1  kiyohara 		switch(irqcode) {
    390   1.1  kiyohara 		case A_int_err:
    391   1.1  kiyohara 			printf("error, DSP=0x%lx\n",
    392   1.1  kiyohara 			    readl(adp->addr + SIOP_DSP) - scriptaddr);
    393   1.1  kiyohara 			if (xs) {
    394   1.1  kiyohara 				xs->error = XS_SELTIMEOUT;
    395   1.1  kiyohara 				goto end;
    396   1.1  kiyohara 			} else {
    397   1.1  kiyohara 				goto reset;
    398   1.1  kiyohara 			}
    399   1.1  kiyohara 		case A_int_reseltarg:
    400   1.1  kiyohara 			printf("reselect with invalid target\n");
    401   1.1  kiyohara 			goto reset;
    402   1.1  kiyohara 		case A_int_resellun:
    403   1.1  kiyohara 			target = readb(adp->addr + SIOP_SCRATCHA) & 0xf;
    404   1.1  kiyohara 			lun = readb(adp->addr + SIOP_SCRATCHA + 1);
    405   1.1  kiyohara 			tag = readb(adp->addr + SIOP_SCRATCHA + 2);
    406   1.1  kiyohara 			if (target != adp->xs->target ||
    407   1.1  kiyohara 			    lun != adp->xs->lun ||
    408   1.1  kiyohara 			    tag != 0) {
    409   1.1  kiyohara 				printf("unknwon resellun:"
    410   1.1  kiyohara 				    " target %d lun %d tag %d\n",
    411   1.1  kiyohara 				    target, lun, tag);
    412   1.1  kiyohara 				goto reset;
    413   1.1  kiyohara 			}
    414   1.1  kiyohara 			siop_xfer = adp->xfer;
    415   1.1  kiyohara 			dsa = local_to_PCI((u_long)siop_xfer);
    416   1.1  kiyohara 			writel(adp->addr + SIOP_DSP,
    417   1.1  kiyohara 			    dsa + sizeof(struct siop_common_xfer) +
    418   1.1  kiyohara 			    Ent_ldsa_reload_dsa);
    419   1.1  kiyohara 			_wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
    420   1.1  kiyohara 			return 1;
    421   1.1  kiyohara 		case A_int_reseltag:
    422   1.1  kiyohara 			printf("reselect with invalid tag\n");
    423   1.1  kiyohara 			goto reset;
    424   1.1  kiyohara 		case A_int_disc:
    425   1.1  kiyohara 			offset = readb(adp->addr + SIOP_SCRATCHA + 1);
    426   1.1  kiyohara 			siop_sdp(adp, siop_xfer, xs, offset);
    427   1.1  kiyohara #if 0
    428   1.1  kiyohara 			/* we start again with no offset */
    429   1.1  kiyohara 			siop_cmd->saved_offset = SIOP_NOOFFSET;
    430   1.1  kiyohara #endif
    431   1.1  kiyohara 			_wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
    432   1.1  kiyohara 			CALL_SCRIPT(Ent_script_sched);
    433   1.1  kiyohara 			return 1;
    434   1.1  kiyohara 		case A_int_resfail:
    435   1.1  kiyohara 			printf("reselect failed\n");
    436   1.1  kiyohara 			return  1;
    437   1.1  kiyohara 		case A_int_done:
    438   1.1  kiyohara 			if (xs == NULL) {
    439   1.1  kiyohara 				printf("done without command, DSA=0x%lx\n",
    440   1.1  kiyohara 				    local_to_PCI((u_long)adp->xfer));
    441   1.1  kiyohara 				return 1;
    442   1.1  kiyohara 			}
    443   1.1  kiyohara 			/* update resid.  */
    444   1.1  kiyohara 			offset = readb(adp->addr + SIOP_SCRATCHA + 1);
    445   1.1  kiyohara #if 0
    446   1.1  kiyohara 			/*
    447   1.1  kiyohara 			 * if we got a disconnect between the last data phase
    448   1.1  kiyohara 			 * and the status phase, offset will be 0. In this
    449   1.1  kiyohara 			 * case, siop_cmd->saved_offset will have the proper
    450   1.1  kiyohara 			 * value if it got updated by the controller
    451   1.1  kiyohara 			 */
    452   1.1  kiyohara 			if (offset == 0 &&
    453   1.1  kiyohara 			    siop_cmd->saved_offset != SIOP_NOOFFSET)
    454   1.1  kiyohara 				offset = siop_cmd->saved_offset;
    455   1.1  kiyohara #endif
    456   1.1  kiyohara 			siop_update_resid(adp, siop_xfer, xs, offset);
    457   1.1  kiyohara 			goto end;
    458   1.1  kiyohara 		default:
    459   1.1  kiyohara 			printf("unknown irqcode %x\n", irqcode);
    460   1.1  kiyohara 			if (xs) {
    461   1.1  kiyohara 				xs->error = XS_SELTIMEOUT;
    462   1.1  kiyohara 				goto end;
    463   1.1  kiyohara 			}
    464   1.1  kiyohara 			goto reset;
    465   1.1  kiyohara 		}
    466   1.1  kiyohara 		return 1;
    467   1.1  kiyohara 	}
    468   1.1  kiyohara 	/* We just should't get there */
    469   1.1  kiyohara 	panic("siop_intr: I shouldn't be there !");
    470   1.1  kiyohara 
    471   1.1  kiyohara 	return 1;
    472   1.1  kiyohara 
    473   1.1  kiyohara end:
    474   1.1  kiyohara 	/*
    475   1.1  kiyohara 	 * restart the script now if command completed properly
    476   1.1  kiyohara 	 * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
    477   1.1  kiyohara 	 * queue
    478   1.1  kiyohara 	 */
    479   1.1  kiyohara 	xs->status = ctoh32(siop_xfer->siop_tables.status);
    480   1.1  kiyohara 	if (xs->status == SCSI_OK)
    481   1.1  kiyohara 		writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
    482   1.1  kiyohara 	else
    483   1.1  kiyohara 		restart = 1;
    484   1.1  kiyohara 	siop_scsicmd_end(adp, xs);
    485   1.1  kiyohara 	if (restart)
    486   1.1  kiyohara 		writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
    487   1.1  kiyohara 
    488   1.1  kiyohara 	return 1;
    489   1.1  kiyohara }
    490   1.1  kiyohara 
    491   1.1  kiyohara static void
    492   1.1  kiyohara siop_scsicmd_end(struct siop_adapter *adp, struct scsi_xfer *xs)
    493   1.1  kiyohara {
    494   1.1  kiyohara 
    495   1.1  kiyohara 	switch(xs->status) {
    496   1.1  kiyohara 	case SCSI_OK:
    497   1.1  kiyohara 		xs->error = XS_NOERROR;
    498   1.1  kiyohara 		break;
    499   1.1  kiyohara 	case SCSI_BUSY:
    500   1.1  kiyohara 	case SCSI_CHECK:
    501   1.1  kiyohara 	case SCSI_QUEUE_FULL:
    502   1.1  kiyohara 		xs->error = XS_BUSY;
    503   1.1  kiyohara 		break;
    504   1.1  kiyohara 	case SCSI_SIOP_NOCHECK:
    505   1.1  kiyohara 		/*
    506   1.1  kiyohara 		 * don't check status, xs->error is already valid
    507   1.1  kiyohara 		 */
    508   1.1  kiyohara 		break;
    509   1.1  kiyohara 	case SCSI_SIOP_NOSTATUS:
    510   1.1  kiyohara 		/*
    511   1.1  kiyohara 		 * the status byte was not updated, cmd was
    512   1.1  kiyohara 		 * aborted
    513   1.1  kiyohara 		 */
    514   1.1  kiyohara 		xs->error = XS_SELTIMEOUT;
    515   1.1  kiyohara 		break;
    516   1.1  kiyohara 	default:
    517   1.1  kiyohara 		printf("invalid status code %d\n", xs->status);
    518   1.1  kiyohara 		xs->error = XS_DRIVER_STUFFUP;
    519   1.1  kiyohara 	}
    520   1.1  kiyohara 	_inv((u_long)xs->cmd, xs->cmdlen);
    521   1.1  kiyohara 	if (xs->datalen != 0)
    522   1.1  kiyohara 		_inv((u_long)xs->data, xs->datalen);
    523   1.1  kiyohara 	xs->xs_status = XS_STS_DONE;
    524   1.1  kiyohara }
    525   1.1  kiyohara 
    526   1.1  kiyohara static int
    527   1.1  kiyohara siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
    528   1.1  kiyohara {
    529   1.1  kiyohara 	void *xfer = adp->xfer;
    530   1.1  kiyohara 	int timo, error;
    531   1.1  kiyohara 
    532   1.1  kiyohara 	if (adp->sel_t != xs->target) {
    533   1.1  kiyohara 		const int free_lo = __arraycount(siop_script);
    534   1.1  kiyohara 		int i;
    535   1.1  kiyohara 		void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
    536   1.1  kiyohara 
    537   1.1  kiyohara 		if (adp->sel_t != -1)
    538   1.1  kiyohara 			adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
    539   1.1  kiyohara 			    htoc32(0x800c00ff);
    540   1.1  kiyohara 
    541   1.1  kiyohara 		for (i = 0; i < __arraycount(lun_switch); i++)
    542   1.1  kiyohara 			adp->script[free_lo + i] = htoc32(lun_switch[i]);
    543   1.1  kiyohara 		adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
    544   1.1  kiyohara 		    htoc32(scriptaddr + Ent_lunsw_return);
    545   1.1  kiyohara 
    546   1.1  kiyohara 		siop_add_reselsw(adp, xs->target, free_lo);
    547   1.1  kiyohara 
    548   1.1  kiyohara 		adp->sel_t = xs->target;
    549   1.1  kiyohara 	}
    550   1.1  kiyohara 
    551   1.1  kiyohara restart:
    552   1.1  kiyohara 
    553   1.1  kiyohara 	siop_setuptables(adp, xfer, xs);
    554   1.1  kiyohara 
    555   1.1  kiyohara 	/* load the DMA maps */
    556   1.1  kiyohara 	if (xs->datalen != 0)
    557   1.1  kiyohara 		_inv((u_long)xs->data, xs->datalen);
    558   1.1  kiyohara 	_wbinv((u_long)xs->cmd, xs->cmdlen);
    559   1.1  kiyohara 
    560   1.1  kiyohara 	_wbinv((u_long)xfer, sizeof(struct siop_xfer));
    561   1.1  kiyohara 	siop_start(adp, xs);
    562   1.1  kiyohara 
    563   1.1  kiyohara 	adp->xs = xs;
    564   1.1  kiyohara 	timo = 0;
    565   1.1  kiyohara 	while (!(xs->xs_status & XS_STS_DONE)) {
    566   1.1  kiyohara 		delay(1000);
    567   1.1  kiyohara 		siop_intr(adp);
    568   1.1  kiyohara 
    569   1.1  kiyohara 		if (timo++ > 3000) {		/* XXXX: 3sec */
    570   1.1  kiyohara 			printf("%s: timeout\n", __func__);
    571   1.1  kiyohara 			return ETIMEDOUT;
    572   1.1  kiyohara 		}
    573   1.1  kiyohara 	}
    574   1.1  kiyohara 
    575   1.1  kiyohara 	if (xs->error != XS_NOERROR) {
    576   1.1  kiyohara 		if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
    577   1.1  kiyohara 			scsi_request_sense(adp, xs);
    578   1.1  kiyohara 
    579   1.1  kiyohara 		switch (xs->error) {
    580   1.1  kiyohara 		case XS_SENSE:
    581   1.1  kiyohara 		case XS_SHORTSENSE:
    582   1.1  kiyohara 			error = scsi_interpret_sense(adp, xs);
    583   1.1  kiyohara 			break;
    584   1.1  kiyohara 		case XS_RESOURCE_SHORTAGE:
    585   1.1  kiyohara 			printf("adapter resource shortage\n");
    586   1.1  kiyohara 
    587   1.1  kiyohara 			/* FALLTHROUGH */
    588   1.1  kiyohara 		case XS_BUSY:
    589   1.1  kiyohara 			error = EBUSY;
    590   1.1  kiyohara 			break;
    591   1.1  kiyohara 		case XS_REQUEUE:
    592   1.1  kiyohara 			printf("XXXX: requeue...\n");
    593   1.1  kiyohara 			error = ERESTART;
    594   1.1  kiyohara 			break;
    595   1.1  kiyohara 		case XS_SELTIMEOUT:
    596   1.1  kiyohara 		case XS_TIMEOUT:
    597   1.1  kiyohara 			error = EIO;
    598   1.1  kiyohara 			break;
    599   1.1  kiyohara 		case XS_RESET:
    600   1.1  kiyohara 			error = EIO;
    601   1.1  kiyohara 			break;
    602   1.1  kiyohara 		case XS_DRIVER_STUFFUP:
    603   1.1  kiyohara 			printf("generic HBA error\n");
    604   1.1  kiyohara 			error = EIO;
    605   1.1  kiyohara 			break;
    606   1.1  kiyohara 		default:
    607   1.1  kiyohara 			printf("invalid return code from adapter: %d\n",
    608   1.1  kiyohara 			    xs->error);
    609   1.1  kiyohara 			error = EIO;
    610   1.1  kiyohara 			break;
    611   1.1  kiyohara 		}
    612   1.1  kiyohara 		if (error == ERESTART) {
    613   1.1  kiyohara 			xs->error = XS_NOERROR;
    614   1.1  kiyohara 			xs->status = SCSI_OK;
    615   1.1  kiyohara 			xs->xs_status &= ~XS_STS_DONE;
    616   1.1  kiyohara 			goto restart;
    617   1.1  kiyohara 		}
    618   1.1  kiyohara 		return error;
    619   1.1  kiyohara 	}
    620   1.1  kiyohara 	return 0;
    621   1.1  kiyohara }
    622   1.1  kiyohara 
    623   1.1  kiyohara static void
    624   1.1  kiyohara siop_start(struct siop_adapter *adp, struct scsi_xfer *xs)
    625   1.1  kiyohara {
    626   1.1  kiyohara 	struct siop_xfer *siop_xfer = adp->xfer;
    627   1.1  kiyohara 	uint32_t dsa, *script = adp->script;
    628   1.5       phx 	int slot;
    629   1.1  kiyohara 	void *scriptaddr = (void *)local_to_PCI((u_long)script);
    630   1.1  kiyohara 	const int siop_common_xfer_size = sizeof(struct siop_common_xfer);
    631   1.1  kiyohara 
    632   1.1  kiyohara 	/*
    633   1.1  kiyohara 	 * The queue management here is a bit tricky: the script always looks
    634   1.1  kiyohara 	 * at the slot from first to last, so if we always use the first
    635   1.1  kiyohara 	 * free slot commands can stay at the tail of the queue ~forever.
    636   1.1  kiyohara 	 * The algorithm used here is to restart from the head when we know
    637   1.1  kiyohara 	 * that the queue is empty, and only add commands after the last one.
    638   1.1  kiyohara 	 * When we're at the end of the queue wait for the script to clear it.
    639   1.1  kiyohara 	 * The best thing to do here would be to implement a circular queue,
    640   1.1  kiyohara 	 * but using only 53c720 features this can be "interesting".
    641   1.1  kiyohara 	 * A mid-way solution could be to implement 2 queues and swap orders.
    642   1.1  kiyohara 	 */
    643   1.1  kiyohara 	slot = adp->currschedslot;
    644   1.1  kiyohara 	/*
    645   1.1  kiyohara 	 * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
    646   1.1  kiyohara 	 * free. As this is the last used slot, all previous slots are free,
    647   1.1  kiyohara 	 * we can restart from 0.
    648   1.1  kiyohara 	 */
    649   1.1  kiyohara 	if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
    650   1.1  kiyohara 	    0x80000000) {
    651   1.1  kiyohara 		slot = adp->currschedslot = 0;
    652   1.1  kiyohara 	} else {
    653   1.1  kiyohara 		slot++;
    654   1.1  kiyohara 	}
    655   1.1  kiyohara 	/*
    656   1.1  kiyohara 	 * find a free scheduler slot and load it.
    657   1.1  kiyohara 	 */
    658   1.1  kiyohara #define SIOP_NSLOTS	0x40
    659   1.1  kiyohara 	for (; slot < SIOP_NSLOTS; slot++) {
    660   1.1  kiyohara 		/*
    661   1.1  kiyohara 		 * If cmd if 0x80000000 the slot is free
    662   1.1  kiyohara 		 */
    663   1.1  kiyohara 		if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
    664   1.1  kiyohara 		    0x80000000)
    665   1.1  kiyohara 			break;
    666   1.1  kiyohara 	}
    667   1.1  kiyohara 	if (slot == SIOP_NSLOTS) {
    668   1.1  kiyohara 		/*
    669   1.1  kiyohara 		 * no more free slot, no need to continue. freeze the queue
    670   1.1  kiyohara 		 * and requeue this command.
    671   1.1  kiyohara 		 */
    672   1.1  kiyohara 		printf("no mode free slot\n");
    673   1.1  kiyohara 		return;
    674   1.1  kiyohara 	}
    675   1.1  kiyohara 
    676   1.1  kiyohara 	/* patch scripts with DSA addr */
    677   1.1  kiyohara 	dsa = local_to_PCI((u_long)siop_xfer);
    678   1.1  kiyohara 
    679   1.1  kiyohara 	/* CMD script: MOVE MEMORY addr */
    680   1.1  kiyohara 	siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
    681   1.1  kiyohara 	    htoc32(scriptaddr + Ent_script_sched_slot0 + slot * 8);
    682   1.1  kiyohara 	_wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
    683   1.1  kiyohara 	/* scheduler slot: JUMP ldsa_select */
    684   1.1  kiyohara 	script[(Ent_script_sched_slot0 / 4) + slot * 2 + 1] =
    685   1.1  kiyohara 	    htoc32(dsa + siop_common_xfer_size + Ent_ldsa_select);
    686   1.1  kiyohara 	/*
    687   1.1  kiyohara 	 * Change JUMP cmd so that this slot will be handled
    688   1.1  kiyohara 	 */
    689   1.1  kiyohara 	script[(Ent_script_sched_slot0 / 4) + slot * 2] = htoc32(0x80080000);
    690   1.1  kiyohara 	adp->currschedslot = slot;
    691   1.1  kiyohara 
    692   1.1  kiyohara 	/* make sure SCRIPT processor will read valid data */
    693   1.1  kiyohara 	_wbinv((u_long)script, SIOP_SCRIPT_SIZE);
    694   1.1  kiyohara 	/* Signal script it has some work to do */
    695   1.1  kiyohara 	writeb(adp->addr + SIOP_ISTAT, ISTAT_SIGP);
    696   1.1  kiyohara 	/* and wait for IRQ */
    697   1.1  kiyohara }
    698   1.1  kiyohara 
    699   1.1  kiyohara static void
    700   1.1  kiyohara siop_xfer_setup(struct siop_xfer *xfer, void *scriptaddr)
    701   1.1  kiyohara {
    702   1.1  kiyohara 	const int off_msg_in = offsetof(struct siop_common_xfer, msg_in);
    703   1.1  kiyohara 	const int off_status = offsetof(struct siop_common_xfer, status);
    704   1.1  kiyohara 	uint32_t dsa, *scr;
    705   1.1  kiyohara 	int i;
    706   1.1  kiyohara 
    707   1.1  kiyohara 	memset(xfer, 0, sizeof(*xfer));
    708   1.1  kiyohara 	dsa = local_to_PCI((u_long)xfer);
    709   1.1  kiyohara 	xfer->siop_tables.t_msgout.count = htoc32(1);
    710   1.1  kiyohara 	xfer->siop_tables.t_msgout.addr = htoc32(dsa);
    711   1.1  kiyohara 	xfer->siop_tables.t_msgin.count = htoc32(1);
    712   1.1  kiyohara 	xfer->siop_tables.t_msgin.addr = htoc32(dsa + off_msg_in);
    713   1.1  kiyohara 	xfer->siop_tables.t_extmsgin.count = htoc32(2);
    714   1.1  kiyohara 	xfer->siop_tables.t_extmsgin.addr = htoc32(dsa + off_msg_in + 1);
    715   1.1  kiyohara 	xfer->siop_tables.t_extmsgdata.addr = htoc32(dsa + off_msg_in + 3);
    716   1.1  kiyohara 	xfer->siop_tables.t_status.count = htoc32(1);
    717   1.1  kiyohara 	xfer->siop_tables.t_status.addr = htoc32(dsa + off_status);
    718   1.1  kiyohara 
    719   1.1  kiyohara 	/* The select/reselect script */
    720   1.1  kiyohara 	scr = xfer->resel;
    721   1.1  kiyohara 	for (i = 0; i < __arraycount(load_dsa); i++)
    722   1.1  kiyohara 		scr[i] = htoc32(load_dsa[i]);
    723   1.1  kiyohara 
    724   1.1  kiyohara 	/*
    725   1.1  kiyohara 	 * 0x78000000 is a 'move data8 to reg'. data8 is the second
    726   1.1  kiyohara 	 * octet, reg offset is the third.
    727   1.1  kiyohara 	 */
    728   1.1  kiyohara 	scr[Ent_rdsa0 / 4] = htoc32(0x78100000 | ((dsa & 0x000000ff) <<  8));
    729   1.1  kiyohara 	scr[Ent_rdsa1 / 4] = htoc32(0x78110000 | ( dsa & 0x0000ff00       ));
    730   1.1  kiyohara 	scr[Ent_rdsa2 / 4] = htoc32(0x78120000 | ((dsa & 0x00ff0000) >>  8));
    731   1.1  kiyohara 	scr[Ent_rdsa3 / 4] = htoc32(0x78130000 | ((dsa & 0xff000000) >> 16));
    732   1.1  kiyohara 	scr[E_ldsa_abs_reselected_Used[0]] =
    733   1.1  kiyohara 	    htoc32(scriptaddr + Ent_reselected);
    734   1.1  kiyohara 	scr[E_ldsa_abs_reselect_Used[0]] = htoc32(scriptaddr + Ent_reselect);
    735   1.1  kiyohara 	scr[E_ldsa_abs_selected_Used[0]] = htoc32(scriptaddr + Ent_selected);
    736   1.1  kiyohara 	scr[E_ldsa_abs_data_Used[0]] =
    737   1.1  kiyohara 	    htoc32(dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data);
    738   1.1  kiyohara 	/* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
    739   1.1  kiyohara 	scr[Ent_ldsa_data / 4] = htoc32(0x80000000);
    740   1.1  kiyohara }
    741   1.1  kiyohara 
    742   1.1  kiyohara static int
    743   1.1  kiyohara siop_add_reselsw(struct siop_adapter *adp, int target, int lunsw_off)
    744   1.1  kiyohara {
    745   1.1  kiyohara 	uint32_t *script = adp->script;
    746   1.1  kiyohara 	int reseloff;
    747   1.1  kiyohara 	void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
    748   1.1  kiyohara 
    749   1.1  kiyohara 	/*
    750   1.1  kiyohara 	 * add an entry to resel switch
    751   1.1  kiyohara 	 */
    752   1.1  kiyohara 	reseloff = Ent_resel_targ0 / 4 + target * 2;
    753   1.1  kiyohara 	if ((ctoh32(script[reseloff]) & 0xff) != 0xff) {
    754   1.1  kiyohara 		/* it's not free */
    755   1.1  kiyohara 		printf("siop: resel switch full\n");
    756   1.1  kiyohara 		return EBUSY;
    757   1.1  kiyohara 	}
    758   1.1  kiyohara 
    759   1.1  kiyohara 	/* JUMP abs_foo, IF target | 0x80; */
    760   1.1  kiyohara 	script[reseloff + 0] = htoc32(0x800c0080 | target);
    761   1.1  kiyohara 	script[reseloff + 1] =
    762   1.1  kiyohara 	    htoc32(scriptaddr + lunsw_off * 4 + Ent_lun_switch_entry);
    763   1.1  kiyohara 
    764   1.1  kiyohara 	siop_update_scntl3(adp, target, lunsw_off);
    765   1.1  kiyohara 	return 0;
    766   1.1  kiyohara }
    767   1.1  kiyohara 
    768   1.1  kiyohara static void
    769   1.1  kiyohara siop_update_scntl3(struct siop_adapter *adp, int target, int lunsw_off)
    770   1.1  kiyohara {
    771   1.1  kiyohara 	uint32_t *script = adp->script;
    772   1.1  kiyohara 
    773   1.1  kiyohara 	/* MOVE target->id >> 24 TO SCNTL3 */
    774   1.1  kiyohara 	script[lunsw_off + (Ent_restore_scntl3 / 4)] =
    775   1.1  kiyohara 	    htoc32(0x78030000 | ((adp->clock_div >> 16) & 0x0000ff00));
    776   1.1  kiyohara 	/* MOVE target->id >> 8 TO SXFER */
    777   1.1  kiyohara 	script[lunsw_off + (Ent_restore_scntl3 / 4) + 2] =
    778   1.1  kiyohara 	    htoc32(0x78050000 | (0x000000000 & 0x0000ff00));
    779   1.1  kiyohara 	_wbinv((u_long)script, SIOP_SCRIPT_SIZE);
    780   1.1  kiyohara }
    781   1.1  kiyohara 
    782   1.1  kiyohara 
    783   1.1  kiyohara /*
    784   1.1  kiyohara  * SCSI functions
    785   1.1  kiyohara  */
    786   1.1  kiyohara 
    787   1.1  kiyohara static int
    788   1.1  kiyohara _scsi_inquire(struct siop_adapter *adp, int t, int l, int buflen, char *buf)
    789   1.1  kiyohara {
    790   1.1  kiyohara 	struct scsipi_inquiry *cmd = (struct scsipi_inquiry *)adp->cmd;
    791   1.1  kiyohara 	struct scsipi_inquiry_data *inqbuf =
    792   1.1  kiyohara 	    (struct scsipi_inquiry_data *)adp->data;
    793   1.1  kiyohara 	struct scsi_xfer xs;
    794   1.1  kiyohara 	int error;
    795   1.1  kiyohara 
    796   1.1  kiyohara 	memset(cmd, 0, sizeof(*cmd));
    797   1.1  kiyohara 	cmd->opcode = INQUIRY;
    798   1.1  kiyohara 	cmd->length = SCSIPI_INQUIRY_LENGTH_SCSI2;
    799   1.1  kiyohara 	memset(inqbuf, 0, sizeof(*inqbuf));
    800   1.1  kiyohara 
    801   1.1  kiyohara 	memset(&xs, 0, sizeof(xs));
    802   1.1  kiyohara 	xs.target = t;
    803   1.1  kiyohara 	xs.lun = l;
    804   1.1  kiyohara 	xs.cmdlen = sizeof(*cmd);
    805   1.1  kiyohara 	xs.cmd = (void *)cmd;
    806   1.1  kiyohara 	xs.datalen = SCSIPI_INQUIRY_LENGTH_SCSI2;
    807   1.1  kiyohara 	xs.data = (void *)inqbuf;
    808   1.1  kiyohara 
    809   1.1  kiyohara 	xs.error = XS_NOERROR;
    810   1.1  kiyohara 	xs.resid = xs.datalen;
    811   1.1  kiyohara 	xs.status = SCSI_OK;
    812   1.1  kiyohara 
    813   1.1  kiyohara 	error = siop_scsi_request(adp, &xs);
    814   1.1  kiyohara 	if (error != 0)
    815   1.1  kiyohara 		return error;
    816   1.1  kiyohara 
    817   1.1  kiyohara 	memcpy(buf, inqbuf, buflen);
    818   1.1  kiyohara 	return 0;
    819   1.1  kiyohara }
    820   1.1  kiyohara 
    821   1.1  kiyohara static void
    822   1.1  kiyohara scsi_request_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
    823   1.1  kiyohara {
    824   1.1  kiyohara 	struct scsi_request_sense *cmd = adp->sense;
    825   1.1  kiyohara 	struct scsi_sense_data *data = (struct scsi_sense_data *)adp->data;
    826   1.1  kiyohara 	struct scsi_xfer sense;
    827   1.1  kiyohara 	int error;
    828   1.1  kiyohara 
    829   1.1  kiyohara 	memset(cmd, 0, sizeof(struct scsi_request_sense));
    830   1.1  kiyohara 	cmd->opcode = SCSI_REQUEST_SENSE;
    831   1.1  kiyohara 	cmd->length = sizeof(struct scsi_sense_data);
    832   1.1  kiyohara 	memset(data, 0, sizeof(struct scsi_sense_data));
    833   1.1  kiyohara 
    834   1.1  kiyohara 	memset(&sense, 0, sizeof(sense));
    835   1.1  kiyohara 	sense.target = xs->target;
    836   1.1  kiyohara 	sense.lun = xs->lun;
    837   1.1  kiyohara 	sense.cmdlen = sizeof(struct scsi_request_sense);
    838   1.1  kiyohara 	sense.cmd = (void *)cmd;
    839   1.1  kiyohara 	sense.datalen = sizeof(struct scsi_sense_data);
    840   1.1  kiyohara 	sense.data = (void *)data;
    841   1.1  kiyohara 
    842   1.1  kiyohara 	sense.error = XS_NOERROR;
    843   1.1  kiyohara 	sense.resid = sense.datalen;
    844   1.1  kiyohara 	sense.status = SCSI_OK;
    845   1.1  kiyohara 
    846   1.1  kiyohara 	error = siop_scsi_request(adp, &sense);
    847   1.1  kiyohara 	switch (error) {
    848   1.1  kiyohara 	case 0:
    849   1.1  kiyohara 		/* we have a valid sense */
    850   1.1  kiyohara 		xs->error = XS_SENSE;
    851   1.1  kiyohara 		return;
    852   1.1  kiyohara 	case EINTR:
    853   1.1  kiyohara 		/* REQUEST_SENSE interrupted by bus reset. */
    854   1.1  kiyohara 		xs->error = XS_RESET;
    855   1.1  kiyohara 		return;
    856   1.1  kiyohara 	case EIO:
    857   1.8    andvar 		 /* request sense couldn't be performed */
    858   1.1  kiyohara 		/*
    859   1.1  kiyohara 		 * XXX this isn't quite right but we don't have anything
    860   1.1  kiyohara 		 * better for now
    861   1.1  kiyohara 		 */
    862   1.1  kiyohara 		xs->error = XS_DRIVER_STUFFUP;
    863   1.1  kiyohara 		return;
    864   1.1  kiyohara 	default:
    865   1.1  kiyohara 		 /* Notify that request sense failed. */
    866   1.1  kiyohara 		xs->error = XS_DRIVER_STUFFUP;
    867   1.1  kiyohara 		printf("request sense failed with error %d\n", error);
    868   1.1  kiyohara 		return;
    869   1.1  kiyohara 	}
    870   1.1  kiyohara }
    871   1.1  kiyohara 
    872   1.1  kiyohara /*
    873   1.1  kiyohara  * scsi_interpret_sense:
    874   1.1  kiyohara  *
    875   1.1  kiyohara  *	Look at the returned sense and act on the error, determining
    876   1.1  kiyohara  *	the unix error number to pass back.  (0 = report no error)
    877   1.1  kiyohara  *
    878   1.1  kiyohara  *	NOTE: If we return ERESTART, we are expected to haved
    879   1.1  kiyohara  *	thawed the device!
    880   1.1  kiyohara  *
    881   1.1  kiyohara  *	THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
    882   1.1  kiyohara  */
    883   1.1  kiyohara static int
    884   1.1  kiyohara scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
    885   1.1  kiyohara {
    886   1.1  kiyohara 	struct scsi_sense_data *sense;
    887   1.1  kiyohara 	u_int8_t key;
    888   1.1  kiyohara 	int error;
    889   1.1  kiyohara 	uint32_t info;
    890   1.1  kiyohara 	static const char *error_mes[] = {
    891   1.1  kiyohara 		"soft error (corrected)",
    892   1.1  kiyohara 		"not ready", "medium error",
    893   1.1  kiyohara 		"non-media hardware failure", "illegal request",
    894   1.1  kiyohara 		"unit attention", "readonly device",
    895   1.1  kiyohara 		"no data found", "vendor unique",
    896   1.1  kiyohara 		"copy aborted", "command aborted",
    897   1.1  kiyohara 		"search returned equal", "volume overflow",
    898   1.1  kiyohara 		"verify miscompare", "unknown error key"
    899   1.1  kiyohara 	};
    900   1.1  kiyohara 
    901   1.1  kiyohara 	sense = (struct scsi_sense_data *)xs->data;
    902   1.1  kiyohara 
    903   1.4       phx 	DPRINTF((" sense debug information:\n"));
    904   1.4       phx 	DPRINTF(("\tcode 0x%x valid %d\n",
    905   1.4       phx 		SSD_RCODE(sense->response_code),
    906   1.4       phx 		sense->response_code & SSD_RCODE_VALID ? 1 : 0));
    907   1.4       phx 	DPRINTF(("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
    908   1.4       phx 		sense->segment,
    909   1.4       phx 		SSD_SENSE_KEY(sense->flags),
    910   1.4       phx 		sense->flags & SSD_ILI ? 1 : 0,
    911   1.4       phx 		sense->flags & SSD_EOM ? 1 : 0,
    912   1.4       phx 		sense->flags & SSD_FILEMARK ? 1 : 0));
    913   1.4       phx 	DPRINTF(("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d "
    914   1.4       phx 		"extra bytes\n",
    915   1.4       phx 		sense->info[0],
    916   1.4       phx 		sense->info[1],
    917   1.4       phx 		sense->info[2],
    918   1.4       phx 		sense->info[3],
    919   1.4       phx 		sense->extra_len));
    920   1.4       phx 
    921   1.1  kiyohara 	switch (SSD_RCODE(sense->response_code)) {
    922   1.1  kiyohara 
    923   1.1  kiyohara 		/*
    924   1.1  kiyohara 		 * Old SCSI-1 and SASI devices respond with
    925   1.1  kiyohara 		 * codes other than 70.
    926   1.1  kiyohara 		 */
    927   1.1  kiyohara 	case 0x00:		/* no error (command completed OK) */
    928   1.1  kiyohara 		return 0;
    929   1.1  kiyohara 	case 0x04:		/* drive not ready after it was selected */
    930   1.1  kiyohara 		if (adp->sd->sc_flags & FLAGS_REMOVABLE)
    931   1.1  kiyohara 			adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
    932   1.1  kiyohara 		/* XXX - display some sort of error here? */
    933   1.1  kiyohara 		return EIO;
    934   1.1  kiyohara 	case 0x20:		/* invalid command */
    935   1.1  kiyohara 		return EINVAL;
    936   1.1  kiyohara 	case 0x25:		/* invalid LUN (Adaptec ACB-4000) */
    937   1.1  kiyohara 		return EACCES;
    938   1.1  kiyohara 
    939   1.1  kiyohara 		/*
    940   1.1  kiyohara 		 * If it's code 70, use the extended stuff and
    941   1.1  kiyohara 		 * interpret the key
    942   1.1  kiyohara 		 */
    943   1.1  kiyohara 	case 0x71:		/* delayed error */
    944   1.1  kiyohara 		key = SSD_SENSE_KEY(sense->flags);
    945   1.1  kiyohara 		printf(" DEFERRED ERROR, key = 0x%x\n", key);
    946   1.1  kiyohara 		/* FALLTHROUGH */
    947   1.1  kiyohara 	case 0x70:
    948   1.1  kiyohara 		if ((sense->response_code & SSD_RCODE_VALID) != 0)
    949   1.1  kiyohara 			info = _4btol(sense->info);
    950   1.1  kiyohara 		else
    951   1.1  kiyohara 			info = 0;
    952   1.1  kiyohara 		key = SSD_SENSE_KEY(sense->flags);
    953   1.1  kiyohara 
    954   1.1  kiyohara 		switch (key) {
    955   1.1  kiyohara 		case SKEY_NO_SENSE:
    956   1.1  kiyohara 		case SKEY_RECOVERED_ERROR:
    957   1.1  kiyohara 			if (xs->resid == xs->datalen && xs->datalen) {
    958   1.1  kiyohara 				/*
    959   1.1  kiyohara 				 * Why is this here?
    960   1.1  kiyohara 				 */
    961   1.1  kiyohara 				xs->resid = 0;	/* not short read */
    962   1.1  kiyohara 			}
    963   1.1  kiyohara 		case SKEY_EQUAL:
    964   1.1  kiyohara 			error = 0;
    965   1.1  kiyohara 			break;
    966   1.1  kiyohara 		case SKEY_NOT_READY:
    967   1.1  kiyohara 			if (adp->sd->sc_flags & FLAGS_REMOVABLE)
    968   1.1  kiyohara 				adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
    969   1.1  kiyohara 			if (sense->asc == 0x3A) {
    970   1.1  kiyohara 				error = ENODEV; /* Medium not present */
    971   1.1  kiyohara 			} else
    972   1.1  kiyohara 				error = EIO;
    973   1.1  kiyohara 			break;
    974   1.1  kiyohara 		case SKEY_ILLEGAL_REQUEST:
    975   1.1  kiyohara 			error = EINVAL;
    976   1.1  kiyohara 			break;
    977   1.1  kiyohara 		case SKEY_UNIT_ATTENTION:
    978   1.1  kiyohara 			if (sense->asc == 0x29 &&
    979   1.1  kiyohara 			    sense->ascq == 0x00) {
    980   1.1  kiyohara 				/* device or bus reset */
    981   1.1  kiyohara 				return ERESTART;
    982   1.1  kiyohara 			}
    983   1.1  kiyohara 			if (adp->sd->sc_flags & FLAGS_REMOVABLE)
    984   1.1  kiyohara 				adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
    985   1.1  kiyohara 			if (!(adp->sd->sc_flags & FLAGS_REMOVABLE))
    986   1.1  kiyohara 				return ERESTART;
    987   1.1  kiyohara 			error = EIO;
    988   1.1  kiyohara 			break;
    989   1.1  kiyohara 		case SKEY_DATA_PROTECT:
    990   1.1  kiyohara 			error = EROFS;
    991   1.1  kiyohara 			break;
    992   1.1  kiyohara 		case SKEY_BLANK_CHECK:
    993   1.1  kiyohara 			error = 0;
    994   1.1  kiyohara 			break;
    995   1.1  kiyohara 		case SKEY_ABORTED_COMMAND:
    996   1.6      maxv 			/* XXX XXX initialize 'error' */
    997   1.1  kiyohara 			break;
    998   1.1  kiyohara 		case SKEY_VOLUME_OVERFLOW:
    999   1.1  kiyohara 			error = ENOSPC;
   1000   1.1  kiyohara 			break;
   1001   1.1  kiyohara 		default:
   1002   1.1  kiyohara 			error = EIO;
   1003   1.1  kiyohara 			break;
   1004   1.1  kiyohara 		}
   1005   1.1  kiyohara 
   1006   1.1  kiyohara 		/* Print brief(er) sense information */
   1007   1.1  kiyohara 		printf("%s", error_mes[key - 1]);
   1008   1.1  kiyohara 		if ((sense->response_code & SSD_RCODE_VALID) != 0) {
   1009   1.1  kiyohara 			switch (key) {
   1010   1.1  kiyohara 			case SKEY_NOT_READY:
   1011   1.1  kiyohara 			case SKEY_ILLEGAL_REQUEST:
   1012   1.1  kiyohara 			case SKEY_UNIT_ATTENTION:
   1013   1.1  kiyohara 			case SKEY_DATA_PROTECT:
   1014   1.1  kiyohara 				break;
   1015   1.1  kiyohara 			case SKEY_BLANK_CHECK:
   1016   1.1  kiyohara 				printf(", requested size: %d (decimal)",
   1017   1.1  kiyohara 				    info);
   1018   1.1  kiyohara 				break;
   1019   1.1  kiyohara 			case SKEY_ABORTED_COMMAND:
   1020   1.1  kiyohara 				printf(", cmd 0x%x, info 0x%x",
   1021   1.1  kiyohara 				    xs->cmd->opcode, info);
   1022   1.1  kiyohara 				break;
   1023   1.1  kiyohara 			default:
   1024   1.1  kiyohara 				printf(", info = %d (decimal)", info);
   1025   1.1  kiyohara 			}
   1026   1.1  kiyohara 		}
   1027   1.1  kiyohara 		if (sense->extra_len != 0) {
   1028   1.1  kiyohara 			int n;
   1029   1.1  kiyohara 			printf(", data =");
   1030   1.1  kiyohara 			for (n = 0; n < sense->extra_len; n++)
   1031   1.1  kiyohara 				printf(" %x", sense->csi[n]);
   1032   1.1  kiyohara 		}
   1033   1.1  kiyohara 		printf("\n");
   1034   1.1  kiyohara 		return error;
   1035   1.1  kiyohara 
   1036   1.1  kiyohara 	/*
   1037   1.1  kiyohara 	 * Some other code, just report it
   1038   1.1  kiyohara 	 */
   1039   1.1  kiyohara 	default:
   1040   1.1  kiyohara 		printf("Sense Error Code 0x%x",
   1041   1.1  kiyohara 			SSD_RCODE(sense->response_code));
   1042   1.1  kiyohara 		if ((sense->response_code & SSD_RCODE_VALID) != 0) {
   1043   1.1  kiyohara 			struct scsi_sense_data_unextended *usense =
   1044   1.1  kiyohara 			    (struct scsi_sense_data_unextended *)sense;
   1045   1.1  kiyohara 			printf(" at block no. %d (decimal)",
   1046   1.1  kiyohara 			    _3btol(usense->block));
   1047   1.1  kiyohara 		}
   1048   1.1  kiyohara 		printf("\n");
   1049   1.1  kiyohara 		return EIO;
   1050   1.1  kiyohara 	}
   1051   1.1  kiyohara }
   1052   1.1  kiyohara 
   1053   1.1  kiyohara static int
   1054   1.1  kiyohara scsi_probe(struct siop_adapter *adp)
   1055   1.1  kiyohara {
   1056   1.1  kiyohara 	struct scsipi_inquiry_data *inqbuf;
   1057   1.1  kiyohara 	int found, t, l;
   1058   1.1  kiyohara 	uint8_t device;
   1059   1.1  kiyohara 	char buf[SCSIPI_INQUIRY_LENGTH_SCSI2],
   1060   1.1  kiyohara 	    product[sizeof(inqbuf->product) + 1];
   1061   1.1  kiyohara 
   1062   1.1  kiyohara 	found = 0;
   1063   1.1  kiyohara 	for (t = 0; t < 8; t++) {
   1064   1.1  kiyohara 		if (t == adp->id)
   1065   1.1  kiyohara 			continue;
   1066   1.1  kiyohara 		for (l = 0; l < 8; l++) {
   1067   1.1  kiyohara 			if (_scsi_inquire(adp, t, l, sizeof(buf), buf) != 0)
   1068   1.1  kiyohara 				continue;
   1069   1.1  kiyohara 
   1070   1.1  kiyohara 			inqbuf = (struct scsipi_inquiry_data *)buf;
   1071   1.1  kiyohara 			device = inqbuf->device & SID_TYPE;
   1072   1.1  kiyohara 			if (device == T_NODEVICE)
   1073   1.1  kiyohara 				continue;
   1074   1.1  kiyohara 			if (device != T_DIRECT &&
   1075   1.1  kiyohara 			    device != T_OPTICAL &&
   1076   1.1  kiyohara 			    device != T_SIMPLE_DIRECT)
   1077   1.1  kiyohara 				continue;
   1078   1.1  kiyohara 
   1079   1.1  kiyohara 			memset(product, 0, sizeof(product));
   1080   1.1  kiyohara 			strncpy(product, inqbuf->product, sizeof(product) - 1);
   1081   1.3  kiyohara 			printf("/dev/disk/scsi/0%d%d: <%s>\n", t, l, product);
   1082   1.1  kiyohara 			found++;
   1083   1.1  kiyohara 		}
   1084   1.1  kiyohara 	}
   1085   1.1  kiyohara 	return found;
   1086   1.1  kiyohara }
   1087   1.1  kiyohara 
   1088   1.1  kiyohara int
   1089   1.1  kiyohara scsi_inquire(struct sd_softc *sd, int buflen, void *buf)
   1090   1.1  kiyohara {
   1091   1.1  kiyohara 	struct siop_adapter *adp;
   1092   1.1  kiyohara 	int error;
   1093   1.1  kiyohara 
   1094   1.1  kiyohara 	if (sd->sc_bus != 0)
   1095   1.1  kiyohara 		return ENOTSUP;
   1096   1.1  kiyohara 	if (adapt.addr == 0)
   1097   1.1  kiyohara 		return ENOENT;
   1098   1.1  kiyohara 	adp = &adapt;
   1099   1.1  kiyohara 
   1100   1.1  kiyohara 	adp->sd = sd;
   1101   1.1  kiyohara 	error = _scsi_inquire(adp, sd->sc_target, sd->sc_lun, buflen, buf);
   1102   1.1  kiyohara 	adp->sd = NULL;
   1103   1.1  kiyohara 
   1104   1.1  kiyohara 	return error;
   1105   1.1  kiyohara }
   1106   1.1  kiyohara 
   1107   1.1  kiyohara /*
   1108   1.1  kiyohara  * scsi_mode_sense
   1109   1.1  kiyohara  *	get a sense page from a device
   1110   1.1  kiyohara  */
   1111   1.1  kiyohara 
   1112   1.1  kiyohara int
   1113   1.1  kiyohara scsi_mode_sense(struct sd_softc *sd, int byte2, int page,
   1114   1.1  kiyohara 		  struct scsi_mode_parameter_header_6 *data, int len)
   1115   1.1  kiyohara {
   1116   1.1  kiyohara 	struct scsi_mode_sense_6 cmd;
   1117   1.1  kiyohara 
   1118   1.1  kiyohara 	memset(&cmd, 0, sizeof(cmd));
   1119   1.1  kiyohara 	cmd.opcode = SCSI_MODE_SENSE_6;
   1120   1.1  kiyohara 	cmd.byte2 = byte2;
   1121   1.1  kiyohara 	cmd.page = page;
   1122   1.1  kiyohara 	cmd.length = len & 0xff;
   1123   1.1  kiyohara 
   1124   1.1  kiyohara 	return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len);
   1125   1.1  kiyohara }
   1126   1.1  kiyohara 
   1127   1.1  kiyohara int
   1128   1.1  kiyohara scsi_command(struct sd_softc *sd, void *cmd, int cmdlen, void *data,
   1129   1.1  kiyohara 	     int datalen)
   1130   1.1  kiyohara {
   1131   1.1  kiyohara 	struct siop_adapter *adp;
   1132   1.1  kiyohara 	struct scsi_xfer xs;
   1133   1.1  kiyohara 	int error;
   1134   1.1  kiyohara 
   1135   1.1  kiyohara 	if (sd->sc_bus != 0)
   1136   1.1  kiyohara 		return ENOTSUP;
   1137   1.1  kiyohara 	if (adapt.addr == 0)
   1138   1.1  kiyohara 		return ENOENT;
   1139   1.1  kiyohara 	adp = &adapt;
   1140   1.1  kiyohara 
   1141   1.1  kiyohara 	memcpy(adp->cmd, cmd, cmdlen);
   1142   1.1  kiyohara 	adp->sd = sd;
   1143   1.1  kiyohara 
   1144   1.1  kiyohara 	memset(&xs, 0, sizeof(xs));
   1145   1.1  kiyohara 	xs.target = sd->sc_target;
   1146   1.1  kiyohara 	xs.lun = sd->sc_lun;
   1147   1.1  kiyohara 	xs.cmdlen = cmdlen;
   1148   1.1  kiyohara 	xs.cmd = adp->cmd;
   1149   1.1  kiyohara 	xs.datalen = datalen;
   1150   1.1  kiyohara 	xs.data = adp->data;
   1151   1.1  kiyohara 
   1152   1.1  kiyohara 	xs.error = XS_NOERROR;
   1153   1.1  kiyohara 	xs.resid = datalen;
   1154   1.1  kiyohara 	xs.status = SCSI_OK;
   1155   1.1  kiyohara 
   1156   1.1  kiyohara 	error = siop_scsi_request(adp, &xs);
   1157   1.1  kiyohara 	adp->sd = NULL;
   1158   1.1  kiyohara 	if (error != 0)
   1159   1.1  kiyohara 		return error;
   1160   1.1  kiyohara 
   1161   1.1  kiyohara 	if (datalen > 0)
   1162   1.1  kiyohara 		memcpy(data, adp->data, datalen);
   1163   1.1  kiyohara 	return 0;
   1164   1.1  kiyohara }
   1165   1.1  kiyohara 
   1166   1.1  kiyohara /*
   1167   1.1  kiyohara  * Initialize the device.
   1168   1.1  kiyohara  */
   1169   1.1  kiyohara int
   1170   1.1  kiyohara siop_init(int bus, int dev, int func)
   1171   1.1  kiyohara {
   1172   1.1  kiyohara 	struct siop_adapter tmp;
   1173   1.1  kiyohara 	struct siop_xfer *xfer;
   1174   1.1  kiyohara 	struct scsipi_generic *cmd;
   1175   1.1  kiyohara 	struct scsi_request_sense *sense;
   1176   1.1  kiyohara 	uint32_t reg;
   1177   1.1  kiyohara 	u_long addr;
   1178   1.1  kiyohara 	uint32_t *script;
   1179   1.1  kiyohara 	int slot, id, i;
   1180   1.1  kiyohara 	void *scriptaddr;
   1181   1.1  kiyohara 	u_char *data;
   1182   1.1  kiyohara 	const int clock_div = 3;		/* 53c810 */
   1183   1.1  kiyohara 
   1184   1.1  kiyohara 	slot = PCISlotnum(bus, dev, func);
   1185   1.1  kiyohara 	if (slot == -1)
   1186   1.1  kiyohara 		return ENOENT;
   1187   1.1  kiyohara 
   1188   1.1  kiyohara 	addr = PCIAddress(slot, 1, PCI_MAPREG_TYPE_MEM);
   1189   1.1  kiyohara 	if (addr == 0xffffffff)
   1190   1.1  kiyohara 		return EINVAL;
   1191   1.1  kiyohara 	enablePCI(slot, 0, 1, 1);
   1192   1.1  kiyohara 
   1193   1.1  kiyohara 	script = ALLOC(uint32_t, SIOP_SCRIPT_SIZE);
   1194   1.1  kiyohara 	if (script == NULL)
   1195   1.1  kiyohara 		return ENOMEM;
   1196   1.1  kiyohara 	scriptaddr = (void *)local_to_PCI((u_long)script);
   1197   1.1  kiyohara 	cmd = ALLOC(struct scsipi_generic, SIOP_SCSI_COMMAND_SIZE);
   1198   1.1  kiyohara 	if (cmd == NULL)
   1199   1.1  kiyohara 		return ENOMEM;
   1200   1.1  kiyohara 	sense = ALLOC(struct scsi_request_sense, SIOP_SCSI_COMMAND_SIZE);
   1201   1.1  kiyohara 	if (sense == NULL)
   1202   1.1  kiyohara 		return ENOMEM;
   1203   1.1  kiyohara 	data = ALLOC(u_char, SIOP_SCSI_DATA_SIZE);
   1204   1.1  kiyohara 	if (data == NULL)
   1205   1.1  kiyohara 		return ENOMEM;
   1206   1.1  kiyohara 	xfer = ALLOC(struct siop_xfer, sizeof(struct siop_xfer));
   1207   1.1  kiyohara 	if (xfer == NULL)
   1208   1.1  kiyohara 		return ENOMEM;
   1209   1.1  kiyohara 	siop_xfer_setup(xfer, scriptaddr);
   1210   1.1  kiyohara 
   1211   1.1  kiyohara 	id = readb(addr + SIOP_SCID) & SCID_ENCID_MASK;
   1212   1.1  kiyohara 
   1213   1.1  kiyohara 	/* reset bus */
   1214   1.1  kiyohara 	reg = readb(addr + SIOP_SCNTL1);
   1215   1.1  kiyohara 	writeb(addr + SIOP_SCNTL1, reg | SCNTL1_RST);
   1216   1.1  kiyohara 	delay(100);
   1217   1.1  kiyohara 	writeb(addr + SIOP_SCNTL1, reg);
   1218   1.1  kiyohara 
   1219   1.1  kiyohara 	/* reset the chip */
   1220   1.1  kiyohara 	writeb(addr + SIOP_ISTAT, ISTAT_SRST);
   1221   1.1  kiyohara 	delay(1000);
   1222   1.1  kiyohara 	writeb(addr + SIOP_ISTAT, 0);
   1223   1.1  kiyohara 
   1224   1.1  kiyohara 	/* init registers */
   1225   1.1  kiyohara 	writeb(addr + SIOP_SCNTL0, SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
   1226   1.1  kiyohara 	writeb(addr + SIOP_SCNTL1, 0);
   1227   1.1  kiyohara 	writeb(addr + SIOP_SCNTL3, clock_div);
   1228   1.1  kiyohara 	writeb(addr + SIOP_SXFER, 0);
   1229   1.1  kiyohara 	writeb(addr + SIOP_DIEN, 0xff);
   1230   1.1  kiyohara 	writeb(addr + SIOP_SIEN0, 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
   1231   1.1  kiyohara 	writeb(addr + SIOP_SIEN1, 0xff & ~(SIEN1_HTH | SIEN1_GEN));
   1232   1.1  kiyohara 	writeb(addr + SIOP_STEST2, 0);
   1233   1.1  kiyohara 	writeb(addr + SIOP_STEST3, STEST3_TE);
   1234   1.1  kiyohara 	writeb(addr + SIOP_STIME0, (0xb << STIME0_SEL_SHIFT));
   1235   1.1  kiyohara 	writeb(addr + SIOP_SCID, id | SCID_RRE);
   1236   1.1  kiyohara 	writeb(addr + SIOP_RESPID0, 1 << id);
   1237   1.1  kiyohara 	writeb(addr + SIOP_DCNTL, DCNTL_COM);
   1238   1.1  kiyohara 
   1239   1.1  kiyohara 	/* BeBox uses PCIC */
   1240   1.1  kiyohara 	writeb(addr + SIOP_STEST1, STEST1_SCLK);
   1241   1.1  kiyohara 
   1242   1.1  kiyohara 	siop_pci_reset(addr);
   1243   1.1  kiyohara 
   1244   1.1  kiyohara 	/* copy and patch the script */
   1245   1.1  kiyohara 	for (i = 0; i < __arraycount(siop_script); i++)
   1246   1.1  kiyohara 		script[i] = htoc32(siop_script[i]);
   1247   1.1  kiyohara 	for (i = 0; i < __arraycount(E_abs_msgin_Used); i++)
   1248   1.1  kiyohara 		script[E_abs_msgin_Used[i]] =
   1249   1.1  kiyohara 		    htoc32(scriptaddr + Ent_msgin_space);
   1250   1.1  kiyohara 
   1251   1.1  kiyohara 	/* start script */
   1252   1.1  kiyohara 	_wbinv((u_long)script, SIOP_SCRIPT_SIZE);
   1253   1.1  kiyohara 	writel(addr + SIOP_DSP, (int)scriptaddr + Ent_reselect);
   1254   1.1  kiyohara 
   1255   1.1  kiyohara 	memset(&tmp, 0, sizeof(tmp));
   1256   1.1  kiyohara 	tmp.id = id;
   1257   1.1  kiyohara 	tmp.clock_div = clock_div;
   1258   1.1  kiyohara 	tmp.addr = addr;
   1259   1.1  kiyohara 	tmp.script = script;
   1260   1.1  kiyohara 	tmp.xfer = xfer;
   1261   1.1  kiyohara 	tmp.cmd = cmd;
   1262   1.1  kiyohara 	tmp.sense = sense;
   1263   1.1  kiyohara 	tmp.data = data;
   1264   1.1  kiyohara 	tmp.currschedslot = 0;
   1265   1.1  kiyohara 	tmp.sel_t = -1;
   1266   1.1  kiyohara 
   1267   1.1  kiyohara 	if (scsi_probe(&tmp) == 0)
   1268   1.1  kiyohara 		return ENXIO;
   1269   1.1  kiyohara 	adapt = tmp;
   1270   1.1  kiyohara 	return 0;
   1271   1.1  kiyohara }
   1272