1 /* $NetBSD: scsi.c,v 1.5 2003/11/14 16:52:40 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) 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 static void scsireset(int); 102 static int issue_select(volatile struct scsidevice *, u_char, u_char); 103 static int wait_for_select(volatile struct scsidevice *hd); 104 static int ixfer_start(volatile struct scsidevice *, int, u_char, int); 105 static int ixfer_out(volatile struct scsidevice *, int, u_char *); 106 static int ixfer_in(volatile struct scsidevice *hd, int, u_char *); 107 static int scsiicmd(struct scsi_softc *, int, u_char *, int, u_char *, int, 108 u_char); 109 110 struct scsi_softc scsi_softc[NSCSI]; 111 112 113 int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */ 114 int scsi_data_wait = 50000; /* use the "real" driver init_wait value */ 115 116 void 117 scsiinit() 118 { 119 struct hp_hw *hw; 120 struct scsi_softc *hs; 121 int i; 122 static int waitset = 0; 123 124 i = 0; 125 for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) { 126 if (!HW_ISSCSI(hw)) 127 continue; 128 hs = &scsi_softc[i]; 129 hs->sc_addr = hw->hw_kva; 130 scsireset(i); 131 if (howto & RB_ASKNAME) 132 printf("scsi%d at sc%d\n", i, hw->hw_sc); 133 hw->hw_pa = (caddr_t) i; /* XXX for autoconfig */ 134 hs->sc_alive = 1; 135 i++; 136 } 137 /* 138 * Adjust the wait values 139 */ 140 if (!waitset) { 141 scsi_cmd_wait *= cpuspeed; 142 scsi_data_wait *= cpuspeed; 143 waitset = 1; 144 } 145 } 146 147 int 148 scsialive(unit) 149 int unit; 150 { 151 if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0) 152 return 0; 153 return 1; 154 } 155 156 static void 157 scsireset(unit) 158 int unit; 159 { 160 volatile struct scsidevice *hd; 161 struct scsi_softc *hs; 162 u_int i; 163 164 hs = &scsi_softc[unit]; 165 hd = (void *)hs->sc_addr; 166 hd->scsi_id = 0xFF; 167 DELAY(100); 168 /* 169 * Disable interrupts then reset the FUJI chip. 170 */ 171 hd->scsi_csr = 0; 172 hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 173 hd->scsi_scmd = 0; 174 hd->scsi_tmod = 0; 175 hd->scsi_pctl = 0; 176 hd->scsi_temp = 0; 177 hd->scsi_tch = 0; 178 hd->scsi_tcm = 0; 179 hd->scsi_tcl = 0; 180 hd->scsi_ints = 0; 181 182 /* 183 * Configure the FUJI chip with its SCSI address, all 184 * interrupts enabled & appropriate parity. 185 */ 186 i = (~hd->scsi_hconf) & 0x7; 187 hs->sc_scsi_addr = 1 << i; 188 hd->scsi_bdid = i; 189 if (hd->scsi_hconf & HCONF_PARITY) 190 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 191 SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 192 SCTL_INTR_ENAB | SCTL_PARITY_ENAB; 193 else 194 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 195 SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 196 SCTL_INTR_ENAB; 197 hd->scsi_sctl &=~ SCTL_DISABLE; 198 } 199 200 201 void 202 scsiabort(hs, hd) 203 struct scsi_softc *hs; 204 volatile struct scsidevice *hd; 205 { 206 printf("scsi%d error: scsiabort\n", hs - scsi_softc); 207 208 scsireset(hs - scsi_softc); 209 DELAY(1000000); 210 } 211 212 static int 213 issue_select(hd, target, our_addr) 214 volatile struct scsidevice *hd; 215 u_char target, our_addr; 216 { 217 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) 218 return 1; 219 220 if (hd->scsi_ints & INTS_DISCON) 221 hd->scsi_ints = INTS_DISCON; 222 223 hd->scsi_pctl = 0; 224 hd->scsi_temp = (1 << target) | our_addr; 225 /* select timeout is hardcoded to 2ms */ 226 hd->scsi_tch = 0; 227 hd->scsi_tcm = 32; 228 hd->scsi_tcl = 4; 229 230 hd->scsi_scmd = SCMD_SELECT; 231 return 0; 232 } 233 234 static int 235 wait_for_select(hd) 236 volatile struct scsidevice *hd; 237 { 238 int wait; 239 u_char ints; 240 241 wait = scsi_data_wait; 242 while ((ints = hd->scsi_ints) == 0) { 243 if (--wait < 0) 244 return 1; 245 DELAY(1); 246 } 247 hd->scsi_ints = ints; 248 return !(hd->scsi_ssts & SSTS_INITIATOR); 249 } 250 251 static int 252 ixfer_start(hd, len, phase, wait) 253 volatile struct scsidevice *hd; 254 int len; 255 u_char phase; 256 int wait; 257 { 258 259 hd->scsi_tch = len >> 16; 260 hd->scsi_tcm = len >> 8; 261 hd->scsi_tcl = len; 262 hd->scsi_pctl = phase; 263 hd->scsi_tmod = 0; /*XXX*/ 264 hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 265 266 /* wait for xfer to start or svc_req interrupt */ 267 while ((hd->scsi_ssts & SSTS_BUSY) == 0) { 268 if (hd->scsi_ints || --wait < 0) 269 return 0; 270 DELAY(1); 271 } 272 return 1; 273 } 274 275 static int 276 ixfer_out(hd, len, buf) 277 volatile struct scsidevice *hd; 278 int len; 279 u_char *buf; 280 { 281 int wait = scsi_data_wait; 282 283 for (; len > 0; --len) { 284 while (hd->scsi_ssts & SSTS_DREG_FULL) { 285 if (hd->scsi_ints || --wait < 0) 286 return len; 287 DELAY(1); 288 } 289 hd->scsi_dreg = *buf++; 290 } 291 return 0; 292 } 293 294 static int 295 ixfer_in(hd, len, buf) 296 volatile struct scsidevice *hd; 297 int len; 298 u_char *buf; 299 { 300 int wait = scsi_data_wait; 301 302 for (; len > 0; --len) { 303 while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 304 if (hd->scsi_ints || --wait < 0) { 305 while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { 306 *buf++ = hd->scsi_dreg; 307 --len; 308 } 309 return len; 310 } 311 DELAY(1); 312 } 313 *buf++ = hd->scsi_dreg; 314 } 315 return len; 316 } 317 318 static int 319 scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) 320 struct scsi_softc *hs; 321 int target; 322 u_char *cbuf; 323 int clen; 324 u_char *buf; 325 int len; 326 u_char xferphase; 327 { 328 volatile struct scsidevice *hd = (void *)hs->sc_addr; 329 u_char phase, ints; 330 int wait; 331 332 /* select the SCSI bus (it's an error if bus isn't free) */ 333 if (issue_select(hd, target, hs->sc_scsi_addr)) 334 return -2; 335 if (wait_for_select(hd)) 336 return -2; 337 /* 338 * Wait for a phase change (or error) then let the device 339 * sequence us through the various SCSI phases. 340 */ 341 hs->sc_stat = -1; 342 phase = CMD_PHASE; 343 while (1) { 344 wait = scsi_cmd_wait; 345 switch (phase) { 346 347 case CMD_PHASE: 348 if (ixfer_start(hd, clen, phase, wait)) 349 if (ixfer_out(hd, clen, cbuf)) 350 goto abort; 351 phase = xferphase; 352 break; 353 354 case DATA_IN_PHASE: 355 if (len <= 0) 356 goto abort; 357 wait = scsi_data_wait; 358 if (ixfer_start(hd, len, phase, wait) || 359 !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 360 ixfer_in(hd, len, buf); 361 phase = STATUS_PHASE; 362 break; 363 364 case DATA_OUT_PHASE: 365 if (len <= 0) 366 goto abort; 367 wait = scsi_data_wait; 368 if (ixfer_start(hd, len, phase, wait)) 369 if (ixfer_out(hd, len, buf)) 370 goto abort; 371 phase = STATUS_PHASE; 372 break; 373 374 case STATUS_PHASE: 375 wait = scsi_data_wait; 376 if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || 377 !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 378 ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat); 379 phase = MESG_IN_PHASE; 380 break; 381 382 case MESG_IN_PHASE: 383 if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || 384 !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { 385 ixfer_in(hd, sizeof(hs->sc_msg), 386 (u_char *)&hs->sc_msg); 387 hd->scsi_scmd = SCMD_RST_ACK; 388 } 389 phase = BUS_FREE_PHASE; 390 break; 391 392 case BUS_FREE_PHASE: 393 goto out; 394 395 default: 396 printf("scsi%d: unexpected scsi phase %d\n", 397 hs - scsi_softc, phase); 398 goto abort; 399 } 400 #ifdef SLOWSCSI 401 /* 402 * XXX we have weird transient problems with booting from 403 * slow scsi disks on fast machines. I have never been 404 * able to pin the problem down, but a large delay here 405 * seems to always work. 406 */ 407 DELAY(1000); 408 #endif 409 /* wait for last command to complete */ 410 while ((ints = hd->scsi_ints) == 0) { 411 if (--wait < 0) 412 goto abort; 413 DELAY(1); 414 } 415 hd->scsi_ints = ints; 416 if (ints & INTS_SRV_REQ) 417 phase = hd->scsi_psns & PHASE; 418 else if (ints & INTS_DISCON) 419 goto out; 420 else if ((ints & INTS_CMD_DONE) == 0) 421 goto abort; 422 } 423 abort: 424 scsiabort(hs, hd); 425 out: 426 return hs->sc_stat; 427 } 428 429 int 430 scsi_test_unit_rdy(ctlr, slave) 431 int ctlr, slave; 432 { 433 struct scsi_softc *hs = &scsi_softc[ctlr]; 434 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 435 436 return scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), NULL, 0, 437 STATUS_PHASE); 438 } 439 440 int 441 scsi_request_sense(ctlr, slave, buf, len) 442 int ctlr, slave; 443 u_char *buf; 444 unsigned int len; 445 { 446 struct scsi_softc *hs = &scsi_softc[ctlr]; 447 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 448 449 cdb.len = len; 450 return scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), buf, len, 451 DATA_IN_PHASE); 452 } 453 454 int 455 scsi_read_capacity(ctlr, slave, buf, len) 456 int ctlr, slave; 457 u_char *buf; 458 unsigned int len; 459 { 460 struct scsi_softc *hs = &scsi_softc[ctlr]; 461 static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY }; 462 463 return scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), buf, len, 464 DATA_IN_PHASE); 465 } 466 467 int 468 scsi_tt_read(ctlr, slave, buf, len, blk, nblk) 469 int ctlr, slave; 470 u_char *buf; 471 u_int len; 472 daddr_t blk; 473 u_int nblk; 474 { 475 struct scsi_softc *hs = &scsi_softc[ctlr]; 476 struct scsi_cdb10 cdb; 477 478 memset(&cdb, 0, sizeof(cdb)); 479 cdb.cmd = CMD_READ_EXT; 480 cdb.lbah = blk >> 24; 481 cdb.lbahm = blk >> 16; 482 cdb.lbalm = blk >> 8; 483 cdb.lbal = blk; 484 cdb.lenh = nblk >> (8 + DEV_BSHIFT); 485 cdb.lenl = nblk >> DEV_BSHIFT; 486 return scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), buf, len, 487 DATA_IN_PHASE); 488 } 489 490 int 491 scsi_tt_write(ctlr, slave, buf, len, blk, nblk) 492 int ctlr, slave; 493 u_char *buf; 494 u_int len; 495 daddr_t blk; 496 u_int nblk; 497 { 498 struct scsi_softc *hs = &scsi_softc[ctlr]; 499 struct scsi_cdb10 cdb; 500 501 memset(&cdb, 0, sizeof(cdb)); 502 cdb.cmd = CMD_WRITE_EXT; 503 cdb.lbah = blk >> 24; 504 cdb.lbahm = blk >> 16; 505 cdb.lbalm = blk >> 8; 506 cdb.lbal = blk; 507 cdb.lenh = nblk >> (8 + DEV_BSHIFT); 508 cdb.lenl = nblk >> DEV_BSHIFT; 509 return scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), buf, len, 510 DATA_OUT_PHASE); 511 } 512