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