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