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