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