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