Home | History | Annotate | Line # | Download | only in common
scsi.c revision 1.4
      1 /*	$NetBSD: scsi.c,v 1.4 2003/08/07 16:27:42 agc Exp $	*/
      2 
      3 /*
      4  * This is reported to fix some odd failures when disklabeling
      5  * SCSI disks in SYS_INST.
      6  */
      7 #define SLOWSCSI
      8 
      9 /*
     10  * Copyright (c) 1990, 1993
     11  *	The Regents of the University of California.  All rights reserved.
     12  *
     13  * This code is derived from software contributed to Berkeley by
     14  * Van Jacobson of Lawrence Berkeley Laboratory and the Systems
     15  * Programming Group of the University of Utah Computer Science Department.
     16  *
     17  * Redistribution and use in source and binary forms, with or without
     18  * modification, are permitted provided that the following conditions
     19  * are met:
     20  * 1. Redistributions of source code must retain the above copyright
     21  *    notice, this list of conditions and the following disclaimer.
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in the
     24  *    documentation and/or other materials provided with the distribution.
     25  * 3. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  * from: Utah $Hdr: scsi.c 1.3 90/01/27$
     42  *
     43  *	@(#)scsi.c	8.1 (Berkeley) 6/10/93
     44  */
     45 /*
     46  * Copyright (c) 1988 University of Utah.
     47  *
     48  * This code is derived from software contributed to Berkeley by
     49  * Van Jacobson of Lawrence Berkeley Laboratory and the Systems
     50  * Programming Group of the University of Utah Computer Science Department.
     51  *
     52  * Redistribution and use in source and binary forms, with or without
     53  * modification, are permitted provided that the following conditions
     54  * are met:
     55  * 1. Redistributions of source code must retain the above copyright
     56  *    notice, this list of conditions and the following disclaimer.
     57  * 2. Redistributions in binary form must reproduce the above copyright
     58  *    notice, this list of conditions and the following disclaimer in the
     59  *    documentation and/or other materials provided with the distribution.
     60  * 3. All advertising materials mentioning features or use of this software
     61  *    must display the following acknowledgement:
     62  *	This product includes software developed by the University of
     63  *	California, Berkeley and its contributors.
     64  * 4. Neither the name of the University nor the names of its contributors
     65  *    may be used to endorse or promote products derived from this software
     66  *    without specific prior written permission.
     67  *
     68  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     69  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     70  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     71  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     72  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     73  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     74  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     75  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     76  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     77  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     78  * SUCH DAMAGE.
     79  *
     80  * from: Utah $Hdr: scsi.c 1.3 90/01/27$
     81  *
     82  *	@(#)scsi.c	8.1 (Berkeley) 6/10/93
     83  */
     84 
     85 /*
     86  * SCSI bus driver for standalone programs.
     87  */
     88 
     89 #include <sys/param.h>
     90 #include <sys/reboot.h>
     91 
     92 #include <lib/libsa/stand.h>
     93 
     94 #define _IOCTL_
     95 
     96 #include <hp300/stand/common/device.h>
     97 #include <hp300/stand/common/scsireg.h>
     98 #include <hp300/stand/common/scsivar.h>
     99 #include <hp300/stand/common/samachdep.h>
    100 
    101 struct	scsi_softc scsi_softc[NSCSI];
    102 
    103 void scsireset();
    104 int scsi_cmd_wait = 50000;	/* use the "real" driver init_wait value */
    105 int scsi_data_wait = 50000;	/* use the "real" driver init_wait value */
    106 
    107 scsiinit()
    108 {
    109 	extern struct hp_hw sc_table[];
    110 	register struct hp_hw *hw;
    111 	register struct scsi_softc *hs;
    112 	register int i, addr;
    113 	static int waitset = 0;
    114 
    115 	i = 0;
    116 	for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) {
    117 		if (!HW_ISSCSI(hw))
    118 			continue;
    119 		hs = &scsi_softc[i];
    120 		hs->sc_addr = hw->hw_kva;
    121 		scsireset(i);
    122 		if (howto & RB_ASKNAME)
    123 			printf("scsi%d at sc%d\n", i, hw->hw_sc);
    124 		hw->hw_pa = (caddr_t) i;	/* XXX for autoconfig */
    125 		hs->sc_alive = 1;
    126 		i++;
    127 	}
    128 	/*
    129 	 * Adjust the wait values
    130 	 */
    131 	if (!waitset) {
    132 		scsi_cmd_wait *= cpuspeed;
    133 		scsi_data_wait *= cpuspeed;
    134 		waitset = 1;
    135 	}
    136 }
    137 
    138 scsialive(unit)
    139 	register int unit;
    140 {
    141 	if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
    142 		return (0);
    143 	return (1);
    144 }
    145 
    146 void
    147 scsireset(unit)
    148 	register int unit;
    149 {
    150 	volatile register struct scsidevice *hd;
    151 	register struct scsi_softc *hs;
    152 	u_int i;
    153 
    154 	hs = &scsi_softc[unit];
    155 	hd = (struct scsidevice *)hs->sc_addr;
    156 	hd->scsi_id = 0xFF;
    157 	DELAY(100);
    158 	/*
    159 	 * Disable interrupts then reset the FUJI chip.
    160 	 */
    161 	hd->scsi_csr  = 0;
    162 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
    163 	hd->scsi_scmd = 0;
    164 	hd->scsi_tmod = 0;
    165 	hd->scsi_pctl = 0;
    166 	hd->scsi_temp = 0;
    167 	hd->scsi_tch  = 0;
    168 	hd->scsi_tcm  = 0;
    169 	hd->scsi_tcl  = 0;
    170 	hd->scsi_ints = 0;
    171 
    172 	/*
    173 	 * Configure the FUJI chip with its SCSI address, all
    174 	 * interrupts enabled & appropriate parity.
    175 	 */
    176 	i = (~hd->scsi_hconf) & 0x7;
    177 	hs->sc_scsi_addr = 1 << i;
    178 	hd->scsi_bdid = i;
    179 	if (hd->scsi_hconf & HCONF_PARITY)
    180 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
    181 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
    182 				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
    183 	else
    184 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
    185 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
    186 				SCTL_INTR_ENAB;
    187 	hd->scsi_sctl &=~ SCTL_DISABLE;
    188 }
    189 
    190 
    191 int
    192 scsiabort(hs, hd)
    193 	register struct scsi_softc *hs;
    194 	volatile register struct scsidevice *hd;
    195 {
    196 	printf("scsi%d error: scsiabort\n", hs - scsi_softc);
    197 
    198 	scsireset(hs - scsi_softc);
    199 	DELAY(1000000);
    200 }
    201 
    202 static int
    203 issue_select(hd, target, our_addr)
    204 	volatile register struct scsidevice *hd;
    205 	u_char target, our_addr;
    206 {
    207 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
    208 		return (1);
    209 
    210 	if (hd->scsi_ints & INTS_DISCON)
    211 		hd->scsi_ints = INTS_DISCON;
    212 
    213 	hd->scsi_pctl = 0;
    214 	hd->scsi_temp = (1 << target) | our_addr;
    215 	/* select timeout is hardcoded to 2ms */
    216 	hd->scsi_tch = 0;
    217 	hd->scsi_tcm = 32;
    218 	hd->scsi_tcl = 4;
    219 
    220 	hd->scsi_scmd = SCMD_SELECT;
    221 	return (0);
    222 }
    223 
    224 static int
    225 wait_for_select(hd)
    226 	volatile register struct scsidevice *hd;
    227 {
    228 	register int wait;
    229 	u_char ints;
    230 
    231 	wait = scsi_data_wait;
    232 	while ((ints = hd->scsi_ints) == 0) {
    233 		if (--wait < 0)
    234 			return (1);
    235 		DELAY(1);
    236 	}
    237 	hd->scsi_ints = ints;
    238 	return (!(hd->scsi_ssts & SSTS_INITIATOR));
    239 }
    240 
    241 static int
    242 ixfer_start(hd, len, phase, wait)
    243 	volatile register struct scsidevice *hd;
    244 	int len;
    245 	u_char phase;
    246 	register int wait;
    247 {
    248 
    249 	hd->scsi_tch = len >> 16;
    250 	hd->scsi_tcm = len >> 8;
    251 	hd->scsi_tcl = len;
    252 	hd->scsi_pctl = phase;
    253 	hd->scsi_tmod = 0; /*XXX*/
    254 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
    255 
    256 	/* wait for xfer to start or svc_req interrupt */
    257 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
    258 		if (hd->scsi_ints || --wait < 0)
    259 			return (0);
    260 		DELAY(1);
    261 	}
    262 	return (1);
    263 }
    264 
    265 static int
    266 ixfer_out(hd, len, buf)
    267 	volatile register struct scsidevice *hd;
    268 	int len;
    269 	register u_char *buf;
    270 {
    271 	register int wait = scsi_data_wait;
    272 
    273 	for (; len > 0; --len) {
    274 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
    275 			if (hd->scsi_ints || --wait < 0)
    276 				return (len);
    277 			DELAY(1);
    278 		}
    279 		hd->scsi_dreg = *buf++;
    280 	}
    281 	return (0);
    282 }
    283 
    284 static int
    285 ixfer_in(hd, len, buf)
    286 	volatile register struct scsidevice *hd;
    287 	int len;
    288 	register u_char *buf;
    289 {
    290 	register int wait = scsi_data_wait;
    291 
    292 	for (; len > 0; --len) {
    293 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
    294 			if (hd->scsi_ints || --wait < 0) {
    295 				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
    296 					*buf++ = hd->scsi_dreg;
    297 					--len;
    298 				}
    299 				return (len);
    300 			}
    301 			DELAY(1);
    302 		}
    303 		*buf++ = hd->scsi_dreg;
    304 	}
    305 	return (len);
    306 }
    307 
    308 static int
    309 scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
    310 	struct scsi_softc *hs;
    311 	int target;
    312 	u_char *cbuf;
    313 	int clen;
    314 	u_char *buf;
    315 	int len;
    316 	u_char xferphase;
    317 {
    318 	volatile register struct scsidevice *hd =
    319 				(struct scsidevice *)hs->sc_addr;
    320 	u_char phase, ints;
    321 	register int wait;
    322 
    323 	/* select the SCSI bus (it's an error if bus isn't free) */
    324 	if (issue_select(hd, target, hs->sc_scsi_addr))
    325 		return (-2);
    326 	if (wait_for_select(hd))
    327 		return (-2);
    328 	/*
    329 	 * Wait for a phase change (or error) then let the device
    330 	 * sequence us through the various SCSI phases.
    331 	 */
    332 	hs->sc_stat = -1;
    333 	phase = CMD_PHASE;
    334 	while (1) {
    335 		wait = scsi_cmd_wait;
    336 		switch (phase) {
    337 
    338 		case CMD_PHASE:
    339 			if (ixfer_start(hd, clen, phase, wait))
    340 				if (ixfer_out(hd, clen, cbuf))
    341 					goto abort;
    342 			phase = xferphase;
    343 			break;
    344 
    345 		case DATA_IN_PHASE:
    346 			if (len <= 0)
    347 				goto abort;
    348 			wait = scsi_data_wait;
    349 			if (ixfer_start(hd, len, phase, wait) ||
    350 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
    351 				ixfer_in(hd, len, buf);
    352 			phase = STATUS_PHASE;
    353 			break;
    354 
    355 		case DATA_OUT_PHASE:
    356 			if (len <= 0)
    357 				goto abort;
    358 			wait = scsi_data_wait;
    359 			if (ixfer_start(hd, len, phase, wait))
    360 				if (ixfer_out(hd, len, buf))
    361 					goto abort;
    362 			phase = STATUS_PHASE;
    363 			break;
    364 
    365 		case STATUS_PHASE:
    366 			wait = scsi_data_wait;
    367 			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
    368 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
    369 				ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat);
    370 			phase = MESG_IN_PHASE;
    371 			break;
    372 
    373 		case MESG_IN_PHASE:
    374 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
    375 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
    376 				ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg);
    377 				hd->scsi_scmd = SCMD_RST_ACK;
    378 			}
    379 			phase = BUS_FREE_PHASE;
    380 			break;
    381 
    382 		case BUS_FREE_PHASE:
    383 			goto out;
    384 
    385 		default:
    386 			printf("scsi%d: unexpected scsi phase %d\n",
    387 			       hs - scsi_softc, phase);
    388 			goto abort;
    389 		}
    390 #ifdef SLOWSCSI
    391 		/*
    392 		 * XXX we have weird transient problems with booting from
    393 		 * slow scsi disks on fast machines.  I have never been
    394 		 * able to pin the problem down, but a large delay here
    395 		 * seems to always work.
    396 		 */
    397 		DELAY(1000);
    398 #endif
    399 		/* wait for last command to complete */
    400 		while ((ints = hd->scsi_ints) == 0) {
    401 			if (--wait < 0)
    402 				goto abort;
    403 			DELAY(1);
    404 		}
    405 		hd->scsi_ints = ints;
    406 		if (ints & INTS_SRV_REQ)
    407 			phase = hd->scsi_psns & PHASE;
    408 		else if (ints & INTS_DISCON)
    409 			goto out;
    410 		else if ((ints & INTS_CMD_DONE) == 0)
    411 			goto abort;
    412 	}
    413 abort:
    414 	scsiabort(hs, hd);
    415 out:
    416 	return (hs->sc_stat);
    417 }
    418 
    419 int
    420 scsi_test_unit_rdy(ctlr, slave)
    421 	int ctlr, slave;
    422 {
    423 	register struct scsi_softc *hs = &scsi_softc[ctlr];
    424 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
    425 
    426 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
    427 			 STATUS_PHASE));
    428 }
    429 
    430 int
    431 scsi_request_sense(ctlr, slave, buf, len)
    432 	int ctlr, slave;
    433 	u_char *buf;
    434 	unsigned len;
    435 {
    436 	register struct scsi_softc *hs = &scsi_softc[ctlr];
    437 	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
    438 
    439 	cdb.len = len;
    440 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
    441 			 DATA_IN_PHASE));
    442 }
    443 
    444 int
    445 scsi_read_capacity(ctlr, slave, buf, len)
    446 	int ctlr, slave;
    447 	u_char *buf;
    448 	unsigned len;
    449 {
    450 	register struct scsi_softc *hs = &scsi_softc[ctlr];
    451 	static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
    452 
    453 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
    454 			 DATA_IN_PHASE));
    455 }
    456 
    457 int
    458 scsi_tt_read(ctlr, slave, buf, len, blk, nblk)
    459 	int ctlr, slave;
    460 	u_char *buf;
    461 	u_int len;
    462 	daddr_t blk;
    463 	u_int nblk;
    464 {
    465 	register struct scsi_softc *hs = &scsi_softc[ctlr];
    466 	struct scsi_cdb10 cdb;
    467 
    468 	bzero(&cdb, sizeof(cdb));
    469 	cdb.cmd = CMD_READ_EXT;
    470 	cdb.lbah = blk >> 24;
    471 	cdb.lbahm = blk >> 16;
    472 	cdb.lbalm = blk >> 8;
    473 	cdb.lbal = blk;
    474 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
    475 	cdb.lenl = nblk >> DEV_BSHIFT;
    476 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
    477 			 DATA_IN_PHASE));
    478 }
    479 
    480 int
    481 scsi_tt_write(ctlr, slave, buf, len, blk, nblk)
    482 	int ctlr, slave;
    483 	u_char *buf;
    484 	u_int len;
    485 	daddr_t blk;
    486 	u_int nblk;
    487 {
    488 	register struct scsi_softc *hs = &scsi_softc[ctlr];
    489 	struct scsi_cdb10 cdb;
    490 
    491 	bzero(&cdb, sizeof(cdb));
    492 	cdb.cmd = CMD_WRITE_EXT;
    493 	cdb.lbah = blk >> 24;
    494 	cdb.lbahm = blk >> 16;
    495 	cdb.lbalm = blk >> 8;
    496 	cdb.lbal = blk;
    497 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
    498 	cdb.lenl = nblk >> DEV_BSHIFT;
    499 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
    500 			 DATA_OUT_PHASE));
    501 }
    502