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