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