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