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