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