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