1/* $NetBSD: scsi.c,v 1.9 2007/03/04 05:59:50 christos 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 63static void scsireset(int); 64static int issue_select(volatile struct scsidevice *, uint8_t, uint8_t); 65static int wait_for_select(volatile struct scsidevice *hd); 66static int ixfer_start(volatile struct scsidevice *, int, uint8_t, int); 67static int ixfer_out(volatile struct scsidevice *, int, uint8_t *); 68static int ixfer_in(volatile struct scsidevice *hd, int, uint8_t *); 69static int scsiicmd(struct scsi_softc *, int, uint8_t *, int, uint8_t *, int, 70 uint8_t); 71 72struct scsi_softc scsi_softc[NSCSI]; 73 74 75int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */ 76int scsi_data_wait = 50000; /* use the "real" driver init_wait value */ 77 78void 79scsiinit(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 109int 110scsialive(int unit) 111{ 112 113 if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0) 114 return 0; 115 return 1; 116} 117 118static void 119scsireset(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 162void 163scsiabort(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 172static int 173issue_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 2ms */ 185 hd->scsi_tch = 0; 186 hd->scsi_tcm = 32; 187 hd->scsi_tcl = 4; 188 189 hd->scsi_scmd = SCMD_SELECT; 190 return 0; 191} 192 193static int 194wait_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 209static int 210ixfer_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 229static int 230ixfer_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 245static int 246ixfer_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 266static int 267scsiicmd(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 } 366abort: 367 scsiabort(hs, hd); 368out: 369 return hs->sc_stat; 370} 371 372int 373scsi_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 382int 383scsi_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 393int 394scsi_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 403int 404scsi_tt_read(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk, 405 u_int nblk) 406{ 407 struct scsi_softc *hs = &scsi_softc[ctlr]; 408 struct scsi_cdb10 cdb; 409 410 memset(&cdb, 0, sizeof(cdb)); 411 cdb.cmd = CMD_READ_EXT; 412 cdb.lbah = blk >> 24; 413 cdb.lbahm = blk >> 16; 414 cdb.lbalm = blk >> 8; 415 cdb.lbal = blk; 416 cdb.lenh = nblk >> (8 + DEV_BSHIFT); 417 cdb.lenl = nblk >> DEV_BSHIFT; 418 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len, 419 DATA_IN_PHASE); 420} 421 422int 423scsi_tt_write(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk, 424 u_int nblk) 425{ 426 struct scsi_softc *hs = &scsi_softc[ctlr]; 427 struct scsi_cdb10 cdb; 428 429 memset(&cdb, 0, sizeof(cdb)); 430 cdb.cmd = CMD_WRITE_EXT; 431 cdb.lbah = blk >> 24; 432 cdb.lbahm = blk >> 16; 433 cdb.lbalm = blk >> 8; 434 cdb.lbal = blk; 435 cdb.lenh = nblk >> (8 + DEV_BSHIFT); 436 cdb.lenl = nblk >> DEV_BSHIFT; 437 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len, 438 DATA_OUT_PHASE); 439} 440