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