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