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