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