vpo.c revision 35210
1/*- 2 * Copyright (c) 1997 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: vpo.c,v 1.4 1997/09/01 00:51:52 bde Exp $ 27 * 28 */ 29 30#ifdef KERNEL 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/malloc.h> 34#include <sys/buf.h> 35 36#include <machine/clock.h> 37 38#endif /* KERNEL */ 39#include <scsi/scsi_disk.h> 40#include <scsi/scsiconf.h> 41 42#ifdef KERNEL 43#include <sys/kernel.h> 44#endif /*KERNEL */ 45 46#include <dev/ppbus/ppbconf.h> 47#include <dev/ppbus/vpo.h> 48 49/* -------------------------------------------------------------------- 50 * HERE ARE THINGS YOU MAY HAVE/WANT TO CHANGE 51 */ 52 53/* 54 * XXX 55 * We may add a timeout queue to avoid active polling on nACK. 56 */ 57#define VP0_SELTMO 5000 /* select timeout */ 58#define VP0_FAST_SPINTMO 500000 /* wait status timeout */ 59#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */ 60 61/* 62 * DO NOT MODIFY ANYTHING UNDER THIS LINE 63 * -------------------------------------------------------------------- 64 */ 65 66static __inline int vpoio_do_scsi(struct vpo_data *, int, int, char *, int, 67 char *, int, int *, int *); 68 69static int32_t vpo_scsi_cmd(struct scsi_xfer *); 70static void vpominphys(struct buf *); 71static u_int32_t vpo_adapter_info(int); 72 73static int vpo_detect(struct vpo_data *vpo); 74 75static int nvpo = 0; 76#define MAXVP0 8 /* XXX not much better! */ 77static struct vpo_data *vpodata[MAXVP0]; 78 79#ifdef KERNEL 80static struct scsi_adapter vpo_switch = 81{ 82 vpo_scsi_cmd, 83 vpominphys, 84 0, 85 0, 86 vpo_adapter_info, 87 "vpo", 88 { 0, 0 } 89}; 90 91/* 92 * The below structure is so we have a default dev struct 93 * for out link struct. 94 */ 95static struct scsi_device vpo_dev = 96{ 97 NULL, /* Use default error handler */ 98 NULL, /* have a queue, served by this */ 99 NULL, /* have no async handler */ 100 NULL, /* Use default 'done' routine */ 101 "vpo", 102 0, 103 { 0, 0 } 104}; 105 106 107/* 108 * Make ourselves visible as a ppbus driver 109 */ 110 111static struct ppb_device *vpoprobe(struct ppb_data *ppb); 112static int vpoattach(struct ppb_device *dev); 113 114static struct ppb_driver vpodriver = { 115 vpoprobe, vpoattach, "vpo" 116}; 117DATA_SET(ppbdriver_set, vpodriver); 118 119 120#endif /* KERNEL */ 121 122static u_int32_t 123vpo_adapter_info(int unit) 124{ 125 126 return 1; 127} 128 129/* 130 * vpoprobe() 131 * 132 * Called by ppb_attachdevs(). 133 */ 134static struct ppb_device * 135vpoprobe(struct ppb_data *ppb) 136{ 137 138 struct vpo_data *vpo; 139 140 if (nvpo >= MAXVP0) { 141 printf("vpo: Too many devices (max %d)\n", MAXVP0); 142 return(NULL); 143 } 144 145 vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data), 146 M_DEVBUF, M_NOWAIT); 147 if (!vpo) { 148 printf("vpo: cannot malloc!\n"); 149 return(NULL); 150 } 151 bzero(vpo, sizeof(struct vpo_data)); 152 153 vpodata[nvpo] = vpo; 154 155 /* vpo dependent initialisation */ 156 vpo->vpo_unit = nvpo; 157 158 /* ppbus dependent initialisation */ 159 vpo->vpo_dev.id_unit = vpo->vpo_unit; 160 vpo->vpo_dev.ppb = ppb; 161 162 /* now, try to initialise the drive */ 163 if (vpo_detect(vpo)) { 164 free(vpo, M_DEVBUF); 165 return (NULL); 166 } 167 168 /* ok, go to next device on next probe */ 169 nvpo ++; 170 171 return (&vpo->vpo_dev); 172} 173 174/* 175 * vpoattach() 176 * 177 * Called by ppb_attachdevs(). 178 */ 179static int 180vpoattach(struct ppb_device *dev) 181{ 182 183 struct scsibus_data *scbus; 184 struct vpo_data *vpo = vpodata[dev->id_unit]; 185 186 vpo->sc_link.adapter_unit = vpo->vpo_unit; 187 vpo->sc_link.adapter_targ = VP0_INITIATOR; 188 vpo->sc_link.adapter = &vpo_switch; 189 vpo->sc_link.device = &vpo_dev; 190 vpo->sc_link.opennings = VP0_OPENNINGS; 191 192 /* 193 * Report ourselves 194 */ 195 printf("vpo%d: <Adaptec aic7110 scsi> on ppbus %d\n", 196 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 197 198 /* 199 * Prepare the scsibus_data area for the upperlevel 200 * scsi code. 201 */ 202 scbus = scsi_alloc_bus(); 203 if(!scbus) 204 return (0); 205 scbus->adapter_link = &vpo->sc_link; 206 207 scsi_attachdevs(scbus); 208 209 return (1); 210} 211 212static void 213vpominphys(struct buf *bp) 214{ 215 216 if (bp->b_bcount > VP0_BUFFER_SIZE) 217 bp->b_bcount = VP0_BUFFER_SIZE; 218 219 return; 220} 221 222#ifdef VP0_WARNING 223static __inline void 224vpo_warning(struct vpo_data *vpo, struct scsi_xfer *xs, int timeout) 225{ 226 227 switch (timeout) { 228 case 0: 229 case VP0_ESELECT_TIMEOUT: 230 /* log(LOG_WARNING, 231 "vpo%d: select timeout\n", vpo->vpo_unit); */ 232 break; 233 case VP0_EDISCONNECT: 234 log(LOG_WARNING, 235 "vpo%d: can't get printer state\n", vpo->vpo_unit); 236 break; 237 case VP0_ECONNECT: 238 log(LOG_WARNING, 239 "vpo%d: can't get disk state\n", vpo->vpo_unit); 240 break; 241 case VP0_ECMD_TIMEOUT: 242 log(LOG_WARNING, 243 "vpo%d: command timeout\n", vpo->vpo_unit); 244 break; 245 case VP0_EPPDATA_TIMEOUT: 246 log(LOG_WARNING, 247 "vpo%d: EPP data timeout\n", vpo->vpo_unit); 248 break; 249 case VP0_ESTATUS_TIMEOUT: 250 log(LOG_WARNING, 251 "vpo%d: status timeout\n", vpo->vpo_unit); 252 break; 253 case VP0_EDATA_OVERFLOW: 254 log(LOG_WARNING, 255 "vpo%d: data overflow\n", vpo->vpo_unit); 256 break; 257 case VP0_EINTR: 258 log(LOG_WARNING, 259 "vpo%d: ppb request interrupted\n", vpo->vpo_unit); 260 break; 261 default: 262 log(LOG_WARNING, 263 "vpo%d: timeout = %d\n", vpo->vpo_unit, timeout); 264 break; 265 } 266} 267#endif /* VP0_WARNING */ 268 269/* 270 * vpointr() 271 */ 272static __inline void 273vpointr(struct vpo_data *vpo, struct scsi_xfer *xs) 274{ 275 276 int errno; /* error in errno.h */ 277 278 if (xs->datalen && !(xs->flags & SCSI_DATA_IN)) 279 bcopy(xs->data, vpo->vpo_buffer, xs->datalen); 280 281 errno = vpoio_do_scsi(vpo, VP0_INITIATOR, 282 xs->sc_link->target, (char *)xs->cmd, xs->cmdlen, 283 vpo->vpo_buffer, xs->datalen, &vpo->vpo_stat, &vpo->vpo_count); 284 285#ifdef VP0_DEBUG 286 printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 287 errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error); 288#endif 289 290 if (errno) { 291#ifdef VP0_WARNING 292 log(LOG_WARNING, "vpo%d: errno = %d\n", vpo->vpo_unit, errno); 293#endif 294 /* connection to ppbus interrupted */ 295 xs->error = XS_DRIVER_STUFFUP; 296 goto error; 297 } 298 299 /* if a timeout occured, no sense */ 300 if (vpo->vpo_error) { 301#ifdef VP0_WARNING 302 vpo_warning(vpo, xs, vpo->vpo_error); 303#endif 304 xs->error = XS_TIMEOUT; 305 goto error; 306 } 307 308#define RESERVED_BITS_MASK 0x3e /* 00111110b */ 309#define NO_SENSE 0x0 310#define CHECK_CONDITION 0x02 311 312 switch (vpo->vpo_stat & RESERVED_BITS_MASK) { 313 case NO_SENSE: 314 break; 315 316 case CHECK_CONDITION: 317 vpo->vpo_sense.cmd.op_code = REQUEST_SENSE; 318 vpo->vpo_sense.cmd.length = sizeof(xs->sense); 319 vpo->vpo_sense.cmd.control = 0; 320 321 errno = vpoio_do_scsi(vpo, VP0_INITIATOR, 322 xs->sc_link->target, (char *)&vpo->vpo_sense.cmd, 323 sizeof(vpo->vpo_sense.cmd), 324 (char *)&xs->sense, sizeof(xs->sense), 325 &vpo->vpo_sense.stat, &vpo->vpo_sense.count); 326 327 if (errno) 328 /* connection to ppbus interrupted */ 329 xs->error = XS_DRIVER_STUFFUP; 330 else 331 xs->error = XS_SENSE; 332 333 goto error; 334 335 default: /* BUSY or RESERVATION_CONFLICT */ 336 xs->error = XS_TIMEOUT; 337 goto error; 338 } 339 340 if (xs->datalen && (xs->flags & SCSI_DATA_IN)) 341 bcopy(vpo->vpo_buffer, xs->data, xs->datalen); 342 343done: 344 xs->resid = 0; 345 xs->error = XS_NOERROR; 346 347error: 348 xs->flags |= ITSDONE; 349 scsi_done(xs); 350 351 return; 352} 353 354static int32_t 355vpo_scsi_cmd(struct scsi_xfer *xs) 356{ 357 358 int s; 359 360 if (xs->sc_link->lun > 0) { 361 xs->error = XS_DRIVER_STUFFUP; 362 return TRY_AGAIN_LATER; 363 } 364 365 if (xs->flags & SCSI_DATA_UIO) { 366 printf("UIO not supported by vpo_driver !\n"); 367 xs->error = XS_DRIVER_STUFFUP; 368 return TRY_AGAIN_LATER; 369 } 370 371#ifdef VP0_DEBUG 372 printf("vpo_scsi_cmd(): xs->flags = 0x%x, "\ 373 "xs->data = 0x%x, xs->datalen = %d\ncommand : %*D\n", 374 xs->flags, xs->data, xs->datalen, 375 xs->cmdlen, xs->cmd, " " ); 376#endif 377 378 if (xs->flags & SCSI_NOMASK) { 379 vpointr(vpodata[xs->sc_link->adapter_unit], xs); 380 return COMPLETE; 381 } 382 383 s = VP0_SPL(); 384 385 vpointr(vpodata[xs->sc_link->adapter_unit], xs); 386 387 splx(s); 388 return SUCCESSFULLY_QUEUED; 389} 390 391#define vpoio_d_pulse(vpo,b) { \ 392 ppb_wdtr(&(vpo)->vpo_dev, b); \ 393 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 394 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \ 395 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \ 396 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \ 397 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 398 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \ 399 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \ 400 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \ 401 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 402 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 403 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 404} 405 406#define vpoio_c_pulse(vpo,b) { \ 407 ppb_wdtr(&(vpo)->vpo_dev, b); \ 408 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 409 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \ 410 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \ 411 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \ 412 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \ 413 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \ 414 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 415 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 416 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \ 417} 418 419static int 420vpoio_disconnect(struct vpo_data *vpo) 421{ 422 423 vpoio_d_pulse(vpo, 0); 424 vpoio_d_pulse(vpo, 0x3c); 425 vpoio_d_pulse(vpo, 0x20); 426 vpoio_d_pulse(vpo, 0xf); 427 428 return (ppb_release_bus(&vpo->vpo_dev)); 429} 430 431/* 432 * how : PPB_WAIT or PPB_DONTWAIT 433 */ 434static int 435vpoio_connect(struct vpo_data *vpo, int how) 436{ 437 int error; 438 439 if ((error = ppb_request_bus(&vpo->vpo_dev, how))) 440 return error; 441 442 vpoio_c_pulse(vpo, 0); 443 vpoio_c_pulse(vpo, 0x3c); 444 vpoio_c_pulse(vpo, 0x20); 445 446 if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) { 447 vpoio_c_pulse(vpo, 0xcf); 448 } else { 449 vpoio_c_pulse(vpo, 0x8f); 450 } 451 452 return (0); 453} 454 455/* 456 * vpoio_in_disk_mode() 457 * 458 * Check if we are in disk mode 459 */ 460static int 461vpoio_in_disk_mode(struct vpo_data *vpo) 462{ 463 464 /* first, set H_AUTO high */ 465 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); 466 467 /* when H_AUTO is set low, H_FLT should be high */ 468 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); 469 if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) == 0) 470 return (0); 471 472 /* when H_AUTO is set high, H_FLT should be low */ 473 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); 474 if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) != 0) 475 return (0); 476 477 return (1); 478} 479 480/* 481 * vpoio_reset() 482 * 483 * SCSI reset signal, the drive must be in disk mode 484 */ 485static void 486vpoio_reset (struct vpo_data *vpo) 487{ 488 489 /* 490 * SCSI reset signal. 491 */ 492 ppb_wdtr(&vpo->vpo_dev, (1 << 7)); 493 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE); 494 DELAY(25); 495 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); 496 497 return; 498} 499 500 501/* 502 * vpo_detect() 503 * 504 * Detect and initialise the VP0 adapter. 505 */ 506static int 507vpo_detect(struct vpo_data *vpo) 508{ 509 510 vpoio_disconnect(vpo); 511 vpoio_connect(vpo, PPB_DONTWAIT); 512 513 if (!vpoio_in_disk_mode(vpo)) { 514 vpoio_disconnect(vpo); 515 return (VP0_EINITFAILED); 516 } 517 518 /* send SCSI reset signal */ 519 vpoio_reset (vpo); 520 521 vpoio_disconnect(vpo); 522 523 if (vpoio_in_disk_mode(vpo)) 524 return (VP0_EINITFAILED); 525 526 return (0); 527} 528 529#define vpo_wctr(dev,byte,delay) { \ 530 int i; int iter = delay / MHZ_16_IO_DURATION; \ 531 for (i = 0; i < iter; i++) { \ 532 ppb_wctr(dev, byte); \ 533 } \ 534} 535 536#define vpoio_spp_outbyte(vpo,byte) { \ 537 ppb_wdtr(&vpo->vpo_dev, byte); \ 538 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \ 539 vpo_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE, \ 540 VP0_SPP_WRITE_PULSE); \ 541} 542 543#define vpoio_nibble_inbyte(vpo,buffer) { \ 544 register char h, l; \ 545 vpo_wctr(&vpo->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE, \ 546 VP0_NIBBLE_READ_PULSE); \ 547 h = ppb_rstr(&vpo->vpo_dev); \ 548 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \ 549 l = ppb_rstr(&vpo->vpo_dev); \ 550 *buffer = ((l >> 4) & 0x0f) + (h & 0xf0); \ 551} 552 553#define vpoio_ps2_inbyte(vpo,buffer) { \ 554 *buffer = ppb_rdtr(&vpo->vpo_dev); \ 555 ppb_wctr(&vpo->vpo_dev, PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE); \ 556 ppb_wctr(&vpo->vpo_dev, PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE); \ 557} 558 559/* 560 * vpoio_outstr() 561 */ 562static int 563vpoio_outstr(struct vpo_data *vpo, char *buffer, int size) 564{ 565 566 register int k; 567 int error = 0; 568 int r, mode, epp; 569 570 mode = ppb_get_mode(&vpo->vpo_dev); 571 switch (mode) { 572 case PPB_NIBBLE: 573 case PPB_PS2: 574 for (k = 0; k < size; k++) { 575 vpoio_spp_outbyte(vpo, *buffer++); 576 } 577 break; 578 579 case PPB_EPP: 580 case PPB_ECP_EPP: 581 epp = ppb_get_epp_protocol(&vpo->vpo_dev); 582 583 ppb_reset_epp_timeout(&vpo->vpo_dev); 584 ppb_wctr(&vpo->vpo_dev, 585 H_AUTO | H_SELIN | H_INIT | H_STROBE); 586 587 if (epp == EPP_1_7) 588 for (k = 0; k < size; k++) { 589 ppb_wepp(&vpo->vpo_dev, *buffer++); 590 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { 591 error = VP0_EPPDATA_TIMEOUT; 592 break; 593 } 594 } 595 else { 596 if (((long) buffer | size) & 0x03) 597 ppb_outsb_epp(&vpo->vpo_dev, 598 buffer, size); 599 else 600 ppb_outsl_epp(&vpo->vpo_dev, 601 buffer, size/4); 602 603 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { 604 error = VP0_EPPDATA_TIMEOUT; 605 break; 606 } 607 } 608 ppb_wctr(&vpo->vpo_dev, 609 H_AUTO | H_nSELIN | H_INIT | H_STROBE); 610 /* ppb_ecp_sync(&vpo->vpo_dev); */ 611 break; 612 613 default: 614 printf("vpoio_outstr(): unknown transfer mode (%d)!\n", 615 mode); 616 return (1); /* XXX */ 617 } 618 619 return (error); 620} 621 622/* 623 * vpoio_instr() 624 */ 625static int 626vpoio_instr(struct vpo_data *vpo, char *buffer, int size) 627{ 628 629 register int k; 630 int error = 0; 631 int r, mode, epp; 632 633 mode = ppb_get_mode(&vpo->vpo_dev); 634 switch (mode) { 635 case PPB_NIBBLE: 636 for (k = 0; k < size; k++) { 637 vpoio_nibble_inbyte(vpo, buffer++); 638 } 639 ppb_wctr(&vpo->vpo_dev, 640 H_AUTO | H_nSELIN | H_INIT | H_STROBE); 641 break; 642 643 case PPB_PS2: 644 ppb_wctr(&vpo->vpo_dev, PCD | 645 H_AUTO | H_SELIN | H_INIT | H_nSTROBE); 646 647 for (k = 0; k < size; k++) { 648 vpoio_ps2_inbyte(vpo, buffer++); 649 } 650 ppb_wctr(&vpo->vpo_dev, 651 H_AUTO | H_nSELIN | H_INIT | H_STROBE); 652 break; 653 654 case PPB_EPP: 655 case PPB_ECP_EPP: 656 epp = ppb_get_epp_protocol(&vpo->vpo_dev); 657 658 ppb_reset_epp_timeout(&vpo->vpo_dev); 659 ppb_wctr(&vpo->vpo_dev, PCD | 660 H_AUTO | H_SELIN | H_INIT | H_STROBE); 661 662 if (epp == EPP_1_7) 663 for (k = 0; k < size; k++) { 664 *buffer++ = ppb_repp(&vpo->vpo_dev); 665 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { 666 error = VP0_EPPDATA_TIMEOUT; 667 break; 668 } 669 } 670 else { 671 if (((long) buffer | size) & 0x03) 672 ppb_insb_epp(&vpo->vpo_dev, 673 buffer, size); 674 else 675 ppb_insl_epp(&vpo->vpo_dev, 676 buffer, size/4); 677 678 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) { 679 error = VP0_EPPDATA_TIMEOUT; 680 break; 681 } 682 } 683 ppb_wctr(&vpo->vpo_dev, PCD | 684 H_AUTO | H_nSELIN | H_INIT | H_STROBE); 685 /* ppb_ecp_sync(&vpo->vpo_dev); */ 686 break; 687 688 default: 689 printf("vpoio_instr(): unknown transfer mode (%d)!\n", 690 mode); 691 return (1); /* XXX */ 692 } 693 694 return (error); 695} 696 697static __inline char 698vpoio_select(struct vpo_data *vpo, int initiator, int target) 699{ 700 701 register int k; 702 703 ppb_wdtr(&vpo->vpo_dev, (1 << target)); 704 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); 705 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); 706 ppb_wdtr(&vpo->vpo_dev, (1 << initiator)); 707 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE); 708 709 k = 0; 710 while (!(ppb_rstr(&vpo->vpo_dev) & 0x40) && (k++ < VP0_SELTMO)) 711 barrier(); 712 713 if (k >= VP0_SELTMO) 714 return (VP0_ESELECT_TIMEOUT); 715 716 return (0); 717} 718 719/* 720 * vpoio_wait() 721 * 722 * H_SELIN must be low. 723 */ 724static __inline char 725vpoio_wait(struct vpo_data *vpo, int tmo) 726{ 727 728 register int k; 729 register char r; 730 731#if 0 /* broken */ 732 if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR)) 733 return (0); 734 735 return (ppb_rstr(&vpo->vpo_dev) & 0xf0); 736#endif 737 738 k = 0; 739 while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo)) 740 barrier(); 741 742 /* 743 * Return some status information. 744 * Semantics : 0xc0 = ZIP wants more data 745 * 0xd0 = ZIP wants to send more data 746 * 0xe0 = ZIP wants command 747 * 0xf0 = end of transfer, ZIP is sending status 748 */ 749 if (k < tmo) 750 return (r & 0xf0); 751 752 return (0); /* command timed out */ 753} 754 755static __inline int 756vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command, 757 int clen, char *buffer, int blen, int *result, int *count) 758{ 759 760 register char r; 761 char l, h = 0; 762 int rw, len, error = 0; 763 register int k; 764 765 /* 766 * enter disk state, allocate the ppbus 767 * 768 * XXX 769 * Should we allow this call to be interruptible? 770 * The only way to report the interruption is to return 771 * EIO do upper SCSI code :^( 772 */ 773 if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR))) 774 return (error); 775 776 if (!vpoio_in_disk_mode(vpo)) { 777 vpo->vpo_error = VP0_ECONNECT; goto error; 778 } 779 780 if ((vpo->vpo_error = vpoio_select(vpo,host,target))) 781 goto error; 782 783 /* 784 * Send the command ... 785 * 786 * set H_SELIN low for vpoio_wait(). 787 */ 788 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); 789 790#ifdef VP0_DEBUG 791 printf("vpo%d: drive selected, now sending the command...\n", 792 vpo->vpo_unit); 793#endif 794 795 for (k = 0; k < clen; k++) { 796 if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) { 797 vpo->vpo_error = VP0_ECMD_TIMEOUT; 798 goto error; 799 } 800 if (vpoio_outstr(vpo, &command[k], 1)) { 801 vpo->vpo_error = VP0_EPPDATA_TIMEOUT; 802 goto error; 803 } 804 } 805 806#ifdef VP0_DEBUG 807 printf("vpo%d: command sent, now completing the request...\n", 808 vpo->vpo_unit); 809#endif 810 811 /* 812 * Completion ... 813 */ 814 rw = ((command[0] == READ_COMMAND) || (command[0] == READ_BIG) || 815 (command[0] == WRITE_COMMAND) || (command[0] == WRITE_BIG)); 816 817 *count = 0; 818 for (;;) { 819 820 if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) { 821 vpo->vpo_error = VP0_ESTATUS_TIMEOUT; goto error; 822 } 823 824 /* stop when the ZIP wants to send status */ 825 if (r == (char)0xf0) 826 break; 827 828 if (*count >= blen) { 829 vpo->vpo_error = VP0_EDATA_OVERFLOW; 830 goto error; 831 } 832 len = (rw && ((blen - *count) >= VP0_SECTOR_SIZE)) ? 833 VP0_SECTOR_SIZE : 1; 834 835 /* ZIP wants to send data? */ 836 if (r == (char)0xc0) 837 error = vpoio_outstr(vpo, &buffer[*count], len); 838 else 839 error = vpoio_instr(vpo, &buffer[*count], len); 840 841 if (error) { 842 vpo->vpo_error = error; 843 goto error; 844 } 845 846 *count += len; 847 } 848 849 if (vpoio_instr(vpo, &l, 1)) { 850 vpo->vpo_error = VP0_EOTHER; goto error; 851 } 852 853 /* check if the ZIP wants to send more status */ 854 if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0) 855 if (vpoio_instr(vpo, &h, 1)) { 856 vpo->vpo_error = VP0_EOTHER+2; goto error; 857 } 858 859 *result = ((int) h << 8) | ((int) l & 0xff); 860 861error: 862 /* return to printer state, release the ppbus */ 863 vpoio_disconnect(vpo); 864 return (0); 865} 866