1 /* 2 * Copyright (c) 1991 University of Utah. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: ac.c 1.5 92/01/21$ 13 * 14 * @(#)ac.c 7.3 (Berkeley) 11/06/92 15 */ 16 17 /* 18 * SCSI driver for MO autochanger. 19 * 20 * Very crude. Because of the lack of connect/disconnect support in the 21 * scsi driver, this driver can tie up the SCSI bus for a long time. It 22 * also grabs a DMA channel and holds it for the duration even though it 23 * never uses it. 24 */ 25 26 #include "ac.h" 27 #if NAC > 0 28 29 #include <sys/param.h> 30 #include <sys/buf.h> 31 #include <sys/errno.h> 32 #include <sys/user.h> 33 #include <sys/ioctl.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/time.h> 37 #include <sys/ucred.h> 38 #include <sys/proc.h> 39 40 #include <vm/vm.h> 41 42 #include <hp/dev/device.h> 43 44 #include <hp300/dev/scsireg.h> 45 #include <hp300/dev/acioctl.h> 46 #include <hp300/dev/acvar.h> 47 48 extern int scsi_test_unit_rdy(); 49 extern int scsi_request_sense(); 50 extern int scsiustart(); 51 extern int scsigo(); 52 extern void scsifree(); 53 extern void scsireset(); 54 extern void scsi_delay(); 55 56 extern int scsi_immed_command(); 57 58 int acinit(), acstart(), acgo(), acintr(); 59 60 struct driver acdriver = { 61 acinit, "ac", acstart, acgo, acintr, 62 }; 63 64 struct ac_softc ac_softc[NAC]; 65 static struct buf acbuf[NAC]; 66 static struct scsi_fmt_cdb accmd[NAC]; 67 68 #ifdef DEBUG 69 int ac_debug = 0x0000; 70 #define ACD_FOLLOW 0x0001 71 #define ACD_OPEN 0x0002 72 #endif 73 74 acinit(hd) 75 register struct hp_device *hd; 76 { 77 int unit = hd->hp_unit; 78 register struct ac_softc *sc = &ac_softc[unit]; 79 80 sc->sc_hd = hd; 81 sc->sc_punit = hd->hp_flags & 7; 82 if (acident(sc, hd) < 0) 83 return(0); 84 sc->sc_dq.dq_unit = unit; 85 sc->sc_dq.dq_ctlr = hd->hp_ctlr; 86 sc->sc_dq.dq_slave = hd->hp_slave; 87 sc->sc_dq.dq_driver = &acdriver; 88 sc->sc_bp = &acbuf[unit]; 89 sc->sc_cmd = &accmd[unit]; 90 sc->sc_flags = ACF_ALIVE; 91 return(1); 92 } 93 94 acident(sc, hd) 95 register struct ac_softc *sc; 96 register struct hp_device *hd; 97 { 98 int unit; 99 register int ctlr, slave; 100 int i, stat; 101 int tries = 5; 102 char idstr[32]; 103 struct scsi_inquiry inqbuf; 104 static struct scsi_fmt_cdb inq = { 105 6, 106 CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 107 }; 108 109 ctlr = hd->hp_ctlr; 110 slave = hd->hp_slave; 111 unit = sc->sc_punit; 112 scsi_delay(-1); 113 114 /* 115 * See if device is ready 116 */ 117 while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 118 if (i == -1 || --tries < 0) 119 /* doesn't exist or not a CCS device */ 120 goto failed; 121 if (i == STS_CHECKCOND) { 122 u_char sensebuf[128]; 123 struct scsi_xsense *sp; 124 125 scsi_request_sense(ctlr, slave, unit, 126 sensebuf, sizeof(sensebuf)); 127 sp = (struct scsi_xsense *) sensebuf; 128 if (sp->class == 7 && sp->key == 6) 129 /* drive doing an RTZ -- give it a while */ 130 DELAY(1000000); 131 } 132 DELAY(1000); 133 } 134 /* 135 * Find out if it is an autochanger 136 */ 137 if (scsi_immed_command(ctlr, slave, unit, &inq, 138 (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 139 goto failed; 140 141 if (inqbuf.type != 8 || inqbuf.qual != 0x80 || inqbuf.version != 2) 142 goto failed; 143 144 bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 145 for (i = 27; i > 23; --i) 146 if (idstr[i] != ' ') 147 break; 148 idstr[i+1] = 0; 149 for (i = 23; i > 7; --i) 150 if (idstr[i] != ' ') 151 break; 152 idstr[i+1] = 0; 153 for (i = 7; i >= 0; --i) 154 if (idstr[i] != ' ') 155 break; 156 idstr[i+1] = 0; 157 printf("ac%d: %s %s rev %s\n", hd->hp_unit, 158 &idstr[0], &idstr[8], &idstr[24]); 159 160 scsi_delay(0); 161 return(inqbuf.type); 162 failed: 163 scsi_delay(0); 164 return(-1); 165 } 166 167 /*ARGSUSED*/ 168 acopen(dev, flag, mode, p) 169 dev_t dev; 170 int flag, mode; 171 struct proc *p; 172 { 173 register int unit = minor(dev); 174 register struct ac_softc *sc = &ac_softc[unit]; 175 int error = 0; 176 177 if (unit >= NAC || (sc->sc_flags & ACF_ALIVE) == 0) 178 error = ENXIO; 179 else if (sc->sc_flags & ACF_OPEN) 180 error = EBUSY; 181 else if (acgeteinfo(dev)) 182 error = EIO; 183 else 184 sc->sc_flags |= ACF_OPEN; 185 return(error); 186 } 187 188 /*ARGSUSED*/ 189 acclose(dev, flag, mode, p) 190 dev_t dev; 191 int flag, mode; 192 struct proc *p; 193 { 194 struct ac_softc *sc = &ac_softc[minor(dev)]; 195 196 sc->sc_flags &= ~ACF_OPEN; 197 } 198 199 #define ACRESLEN(ep) \ 200 (8 + (ep)->nmte*12 + (ep)->nse*12 + (ep)->niee*12 + (ep)->ndte*20) 201 202 /*ARGSUSED*/ 203 acioctl(dev, cmd, data, flag, p) 204 dev_t dev; 205 int cmd; 206 caddr_t data; 207 int flag; 208 struct proc *p; 209 { 210 register struct ac_softc *sc = &ac_softc[minor(dev)]; 211 char *dp; 212 int dlen, error = 0; 213 214 switch (cmd) { 215 216 default: 217 return (EINVAL); 218 219 /* perform an init element status and mode sense to reset state */ 220 case ACIOCINIT: 221 error = accommand(dev, ACCMD_INITES, (caddr_t)0, 0); 222 if (!error) 223 error = acgeteinfo(dev); 224 break; 225 226 /* copy internal element information */ 227 case ACIOCGINFO: 228 *(struct acinfo *)data = sc->sc_einfo; 229 break; 230 231 case ACIOCRAWES: 232 { 233 struct acbuffer *acbp = (struct acbuffer *)data; 234 235 dlen = ACRESLEN(&sc->sc_einfo); 236 dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 237 error = accommand(dev, ACCMD_READES, dp, dlen); 238 if (!error) { 239 dlen = *(int *)&dp[4] + 8; 240 if (dlen > acbp->buflen) 241 dlen = acbp->buflen; 242 error = copyout(dp, acbp->bufptr, dlen); 243 } 244 break; 245 } 246 247 case ACIOCGSTAT: 248 { 249 struct acbuffer *acbp = (struct acbuffer *)data; 250 251 dlen = ACRESLEN(&sc->sc_einfo); 252 dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 253 error = accommand(dev, ACCMD_READES, dp, dlen); 254 if (!error) { 255 int ne; 256 char *tbuf; 257 258 ne = sc->sc_einfo.nmte + sc->sc_einfo.nse + 259 sc->sc_einfo.niee + sc->sc_einfo.ndte; 260 dlen = ne * sizeof(struct aceltstat); 261 tbuf = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 262 acconvert(dp, tbuf, ne); 263 if (dlen > acbp->buflen) 264 dlen = acbp->buflen; 265 error = copyout(tbuf, acbp->bufptr, dlen); 266 free(tbuf, M_DEVBUF); 267 } 268 free(dp, M_DEVBUF); 269 break; 270 } 271 272 case ACIOCMOVE: 273 error = accommand(dev, ACCMD_MOVEM, data, 274 sizeof(struct acmove)); 275 break; 276 } 277 return(error); 278 } 279 280 accommand(dev, command, bufp, buflen) 281 dev_t dev; 282 int command; 283 char *bufp; 284 int buflen; 285 { 286 int unit = minor(dev); 287 register struct ac_softc *sc = &ac_softc[unit]; 288 register struct buf *bp = sc->sc_bp; 289 register struct scsi_fmt_cdb *cmd = sc->sc_cmd; 290 int error; 291 292 #ifdef DEBUG 293 if (ac_debug & ACD_FOLLOW) 294 printf("accommand(dev=%x, cmd=%x, buf=%x, buflen=%x)\n", 295 dev, command, bufp, buflen); 296 #endif 297 if (sc->sc_flags & ACF_ACTIVE) 298 panic("accommand: active!"); 299 300 sc->sc_flags |= ACF_ACTIVE; 301 bzero((caddr_t)cmd->cdb, sizeof(cmd->cdb)); 302 cmd->cdb[0] = command; 303 304 switch (command) { 305 case ACCMD_INITES: 306 cmd->len = 6; 307 break; 308 case ACCMD_READES: 309 cmd->len = 12; 310 *(short *)&cmd->cdb[2] = 0; 311 *(short *)&cmd->cdb[4] = 312 sc->sc_einfo.nmte + sc->sc_einfo.nse + 313 sc->sc_einfo.niee + sc->sc_einfo.ndte; 314 cmd->cdb[7] = buflen >> 16; 315 cmd->cdb[8] = buflen >> 8; 316 cmd->cdb[9] = buflen; 317 break; 318 case ACCMD_MODESENSE: 319 cmd->len = 6; 320 cmd->cdb[2] = 0x3F; /* all pages */ 321 cmd->cdb[4] = buflen; 322 break; 323 case ACCMD_MOVEM: 324 cmd->len = 12; 325 *(short *)&cmd->cdb[2] = sc->sc_picker; 326 *(short *)&cmd->cdb[4] = *(short *)&bufp[0]; 327 *(short *)&cmd->cdb[6] = *(short *)&bufp[2]; 328 if (*(short *)&bufp[4] & AC_INVERT) 329 cmd->cdb[10] = 1; 330 bufp = 0; 331 buflen = 0; 332 break; 333 default: 334 panic("accommand: bad command"); 335 } 336 bp->b_flags = B_BUSY|B_READ; 337 bp->b_dev = dev; 338 bp->b_un.b_addr = bufp; 339 bp->b_bcount = buflen; 340 bp->b_resid = 0; 341 bp->b_blkno = 0; 342 bp->b_error = 0; 343 if (scsireq(&sc->sc_dq)) 344 acstart(unit); 345 error = biowait(bp); 346 sc->sc_flags &= ~ACF_ACTIVE; 347 return (error); 348 } 349 350 acstart(unit) 351 int unit; 352 { 353 #ifdef DEBUG 354 if (ac_debug & ACD_FOLLOW) 355 printf("acstart(unit=%x)\n", unit); 356 #endif 357 if (scsiustart(ac_softc[unit].sc_hd->hp_ctlr)) 358 acgo(unit); 359 } 360 361 acgo(unit) 362 int unit; 363 { 364 register struct ac_softc *sc = &ac_softc[unit]; 365 register struct buf *bp = sc->sc_bp; 366 struct hp_device *hp = sc->sc_hd; 367 int stat; 368 369 #ifdef DEBUG 370 if (ac_debug & ACD_FOLLOW) 371 printf("acgo(unit=%x): ", unit); 372 #endif 373 stat = scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 374 bp, sc->sc_cmd, 0); 375 #ifdef DEBUG 376 if (ac_debug & ACD_FOLLOW) 377 printf("scsigo returns %x\n", stat); 378 #endif 379 if (stat) { 380 bp->b_error = EIO; 381 bp->b_flags |= B_ERROR; 382 (void) biodone(bp); 383 scsifree(&sc->sc_dq); 384 } 385 } 386 387 acintr(unit, stat) 388 int unit, stat; 389 { 390 register struct ac_softc *sc = &ac_softc[unit]; 391 register struct buf *bp = sc->sc_bp; 392 u_char sensebuf[78]; 393 struct scsi_xsense *sp; 394 395 #ifdef DEBUG 396 if (ac_debug & ACD_FOLLOW) 397 printf("acintr(unit=%x, stat=%x)\n", unit, stat); 398 #endif 399 switch (stat) { 400 case 0: 401 bp->b_resid = 0; 402 break; 403 case STS_CHECKCOND: 404 scsi_request_sense(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 405 sc->sc_punit, sensebuf, sizeof sensebuf); 406 sp = (struct scsi_xsense *)sensebuf; 407 printf("ac%d: acintr sense key=%x, ac=%x, acq=%x\n", 408 unit, sp->key, sp->info4, sp->len); 409 bp->b_flags |= B_ERROR; 410 bp->b_error = EIO; 411 break; 412 default: 413 printf("ac%d: acintr unknown status 0x%x\n", unit, stat); 414 break; 415 } 416 (void) biodone(sc->sc_bp); 417 scsifree(&sc->sc_dq); 418 } 419 420 acgeteinfo(dev) 421 dev_t dev; 422 { 423 register struct ac_softc *sc = &ac_softc[minor(dev)]; 424 register char *bp; 425 char msbuf[48]; 426 int error; 427 428 bzero(msbuf, sizeof msbuf); 429 error = accommand(dev, ACCMD_MODESENSE, msbuf, sizeof msbuf); 430 if (error) 431 return(error); 432 bp = &msbuf[4]; 433 while (bp < &msbuf[48]) { 434 switch (bp[0] & 0x3F) { 435 case 0x1D: 436 sc->sc_einfo = *(struct acinfo *)&bp[2]; 437 sc->sc_picker = sc->sc_einfo.fmte; /* XXX */ 438 return(0); 439 case 0x1E: 440 bp += 4; 441 break; 442 case 0x1F: 443 bp += 20; 444 break; 445 default: 446 printf("acgeteinfo: bad page type %x\n", bp[0]); 447 return(EIO); 448 } 449 } 450 return(EIO); 451 } 452 453 acconvert(sbuf, dbuf, ne) 454 char *sbuf, *dbuf; 455 int ne; 456 { 457 register struct aceltstat *ep = (struct aceltstat *)dbuf; 458 register struct ac_restatphdr *phdr; 459 register struct ac_restatdb *dbp; 460 struct ac_restathdr *hdr; 461 #ifdef DEBUG 462 register int bcount; 463 #endif 464 465 hdr = (struct ac_restathdr *)&sbuf[0]; 466 sbuf += sizeof *hdr; 467 #ifdef DEBUG 468 if (ac_debug & ACD_FOLLOW) 469 printf("element status: first=%d, num=%d, len=%d\n", 470 hdr->ac_felt, hdr->ac_nelt, hdr->ac_bcount); 471 if (hdr->ac_nelt != ne) { 472 printf("acconvert: # of elements, %d != %d\n", 473 hdr->ac_nelt, ne); 474 if (hdr->ac_nelt < ne) 475 ne = hdr->ac_nelt; 476 } 477 bcount = hdr->ac_bcount; 478 #endif 479 while (ne) { 480 phdr = (struct ac_restatphdr *)sbuf; 481 sbuf += sizeof *phdr; 482 #ifdef DEBUG 483 bcount -= sizeof *phdr; 484 #endif 485 dbp = (struct ac_restatdb *)sbuf; 486 sbuf += phdr->ac_bcount; 487 #ifdef DEBUG 488 bcount -= phdr->ac_bcount; 489 #endif 490 while (dbp < (struct ac_restatdb *)sbuf) { 491 ep->type = phdr->ac_type; 492 ep->eaddr = dbp->ac_eaddr; 493 ep->flags = 0; 494 if (dbp->ac_full) 495 ep->flags |= AC_FULL; 496 if (dbp->ac_exc) 497 ep->flags |= AC_ERROR; 498 if (dbp->ac_acc) 499 ep->flags |= AC_ACCESS; 500 dbp = (struct ac_restatdb *) 501 ((char *)dbp + phdr->ac_dlen); 502 ep++; 503 ne--; 504 } 505 #ifdef DEBUG 506 if (ne < 0 || bcount < 0) 507 panic("acconvert: inconsistant"); 508 #endif 509 } 510 } 511 #endif 512