Deleted Added
sdiff udiff text old ( 55205 ) new ( 55939 )
full compact
1/*-
2 * Copyright (c) 1998, 1999 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

--- 7 unchanged lines hidden (view full) ---

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 * $FreeBSD: head/sys/dev/ppbus/vpoio.c 55939 2000-01-14 00:18:06Z nsouch $
27 *
28 */
29
30#ifdef _KERNEL
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/module.h>
34#include <sys/bus.h>
35#include <sys/malloc.h>
36#include <sys/buf.h>
37
38#include <machine/clock.h>
39
40#endif
41
42#ifdef _KERNEL
43#include <sys/kernel.h>
44#endif
45
46#include "opt_vpo.h"
47
48#include <dev/ppbus/ppbio.h>
49#include <dev/ppbus/ppbconf.h>
50#include <dev/ppbus/ppb_msq.h>
51#include <dev/ppbus/vpoio.h>
52
53#include "ppbus_if.h"
54
55/*
56 * The driver pools the drive. We may add a timeout queue to avoid
57 * active polling on nACK. I've tried this but it leads to unreliable
58 * transfers
59 */
60#define VP0_SELTMO 5000 /* select timeout */
61#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
62#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */

--- 208 unchanged lines hidden (view full) ---

271 MS_RET(1),
272/* error: */
273 MS_RET(0)
274};
275
276static int
277vpoio_disconnect(struct vpoio_data *vpo)
278{
279 device_t ppbus = device_get_parent(vpo->vpo_dev);
280 int ret;
281
282 ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
283 return (ppb_release_bus(ppbus, vpo->vpo_dev));
284}
285
286/*
287 * how : PPB_WAIT or PPB_DONTWAIT
288 */
289static int
290vpoio_connect(struct vpoio_data *vpo, int how)
291{
292 device_t ppbus = device_get_parent(vpo->vpo_dev);
293 int error;
294 int ret;
295
296 if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, how))) {
297
298#ifdef VP0_DEBUG
299 printf("%s: can't request bus!\n", __FUNCTION__);
300#endif
301 return error;
302 }
303
304 if (PPB_IN_EPP_MODE(ppbus))
305 ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret);
306 else
307 ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
308
309 return (0);
310}
311
312/*
313 * vpoio_reset()
314 *
315 * SCSI reset signal, the drive must be in disk mode
316 */
317static void
318vpoio_reset (struct vpoio_data *vpo)
319{
320 device_t ppbus = device_get_parent(vpo->vpo_dev);
321 int ret;
322
323 struct ppb_microseq reset_microseq[] = {
324
325 #define INITIATOR MS_PARAM(0, 1, MS_TYP_INT)
326
327 MS_DASS(MS_UNKNOWN),
328 MS_CASS(H_AUTO | H_nSELIN | H_nINIT | H_STROBE),
329 MS_DELAY(25),
330 MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
331 MS_RET(0)
332 };
333
334 ppb_MS_init_msq(reset_microseq, 1, INITIATOR, 1 << VP0_INITIATOR);
335 ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, &ret);
336
337 return;
338}
339
340/*
341 * vpoio_in_disk_mode()
342 */
343static int
344vpoio_in_disk_mode(struct vpoio_data *vpo)
345{
346 device_t ppbus = device_get_parent(vpo->vpo_dev);
347 int ret;
348
349 ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
350
351 return (ret);
352}
353
354/*
355 * vpoio_detect()
356 *
357 * Detect and initialise the VP0 adapter.
358 */
359static int
360vpoio_detect(struct vpoio_data *vpo)
361{
362 device_t ppbus = device_get_parent(vpo->vpo_dev);
363 int error, ret;
364
365 /* allocate the bus, then apply microsequences */
366 if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT)))
367 return (error);
368
369 ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
370
371 if (PPB_IN_EPP_MODE(ppbus))
372 ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret);
373 else
374 ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
375
376 ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
377 if (!ret) {
378
379 /* try spp mode (maybe twice or because previous mode was PS2)
380 * NIBBLE mode will be restored on next transfers if detection
381 * succeed
382 */
383 ppb_set_mode(ppbus, PPB_NIBBLE);
384 ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
385
386 ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
387 if (!ret) {
388 if (bootverbose)
389 printf("vpo%d: can't connect to the drive\n",
390 vpo->vpo_unit);
391
392 /* disconnect and release the bus */
393 ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq,
394 &ret);
395 goto error;
396 }
397 }
398
399 /* send SCSI reset signal */
400 vpoio_reset(vpo);
401
402 ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
403
404 /* ensure we are disconnected or daisy chained peripheral
405 * may cause serious problem to the disk */
406
407 ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
408 if (ret) {
409 if (bootverbose)
410 printf("vpo%d: can't disconnect from the drive\n",
411 vpo->vpo_unit);
412 goto error;
413 }
414
415 ppb_release_bus(ppbus, vpo->vpo_dev);
416 return (0);
417
418error:
419 ppb_release_bus(ppbus, vpo->vpo_dev);
420 return (VP0_EINITFAILED);
421}
422
423/*
424 * vpoio_outstr()
425 */
426static int
427vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size)
428{
429 device_t ppbus = device_get_parent(vpo->vpo_dev);
430 int error = 0;
431
432 ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer,
433 (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
434
435#if 0
436 /* XXX EPP 1.9 not implemented with microsequences */
437 else {
438
439 ppb_reset_epp_timeout(ppbus);
440 ppb_wctr(ppbus, H_AUTO | H_SELIN | H_INIT | H_STROBE);
441
442 if (((long) buffer | size) & 0x03)
443 ppb_outsb_epp(ppbus,
444 buffer, size);
445 else
446 ppb_outsl_epp(ppbus,
447 buffer, size/4);
448
449 if ((ppb_rstr(ppbus) & TIMEOUT)) {
450 error = VP0_EPPDATA_TIMEOUT;
451 goto error;
452 }
453
454 ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
455 }
456#endif
457 ppb_ecp_sync(ppbus);
458
459 return (error);
460}
461
462/*
463 * vpoio_instr()
464 */
465static int
466vpoio_instr(struct vpoio_data *vpo, char *buffer, int size)
467{
468 device_t ppbus = device_get_parent(vpo->vpo_dev);
469 int error = 0;
470
471 ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer,
472 (union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
473
474#if 0
475 /* XXX EPP 1.9 not implemented with microsequences */
476 else {
477
478 ppb_reset_epp_timeout(ppbus);
479 ppb_wctr(ppbus, PCD |
480 H_AUTO | H_SELIN | H_INIT | H_STROBE);
481
482 if (((long) buffer | size) & 0x03)
483 ppb_insb_epp(ppbus,
484 buffer, size);
485 else
486 ppb_insl_epp(ppbus,
487 buffer, size/4);
488
489 if ((ppb_rstr(ppbus) & TIMEOUT)) {
490 error = VP0_EPPDATA_TIMEOUT;
491 goto error;
492 }
493
494 ppb_wctr(ppbus, PCD |
495 H_AUTO | H_nSELIN | H_INIT | H_STROBE);
496 }
497#endif
498 ppb_ecp_sync(ppbus);
499
500 return (error);
501}
502
503static char
504vpoio_select(struct vpoio_data *vpo, int initiator, int target)
505{
506 device_t ppbus = device_get_parent(vpo->vpo_dev);
507 int ret;
508
509 struct ppb_microseq select_microseq[] = {
510
511 /* parameter list
512 */
513 #define SELECT_TARGET MS_PARAM(0, 1, MS_TYP_INT)
514 #define SELECT_INITIATOR MS_PARAM(3, 1, MS_TYP_INT)

--- 13 unchanged lines hidden (view full) ---

528/* ready: */ MS_RET(0)
529 };
530
531 /* initialize the select microsequence */
532 ppb_MS_init_msq(select_microseq, 2,
533 SELECT_TARGET, 1 << target,
534 SELECT_INITIATOR, 1 << initiator);
535
536 ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret);
537
538 if (ret)
539 return (VP0_ESELECT_TIMEOUT);
540
541 return (0);
542}
543
544/*
545 * vpoio_wait()
546 *
547 * H_SELIN must be low.
548 *
549 * XXX should be ported to microseq
550 */
551static char
552vpoio_wait(struct vpoio_data *vpo, int tmo)
553{
554 device_t ppbus = device_get_parent(vpo->vpo_dev);
555 register int k;
556 register char r;
557
558#if 0 /* broken */
559 if (ppb_poll_device(ppbus, 150, nBUSY, nBUSY, PPB_INTR))
560 return (0);
561
562 return (ppb_rstr(ppbus) & 0xf0);
563#endif
564
565 /* XXX should be ported to microseq */
566 k = 0;
567 while (!((r = ppb_rstr(ppbus)) & nBUSY) && (k++ < tmo))
568 ;
569
570 /*
571 * Return some status information.
572 * Semantics : 0xc0 = ZIP wants more data
573 * 0xd0 = ZIP wants to send more data
574 * 0xe0 = ZIP wants command
575 * 0xf0 = end of transfer, ZIP is sending status

--- 5 unchanged lines hidden (view full) ---

581}
582
583/*
584 * vpoio_probe()
585 *
586 * Low level probe of vpo device
587 *
588 */
589int
590vpoio_probe(device_t dev, struct vpoio_data *vpo)
591{
592 int error;
593
594 /* ppbus dependent initialisation */
595 vpo->vpo_dev = dev;
596
597 /*
598 * Initialize microsequence code
599 */
600 INIT_TRIG_MICROSEQ;
601
602 /* now, try to initialise the drive */
603 if ((error = vpoio_detect(vpo))) {
604 return (error);
605 }
606
607 return (0);
608}
609
610/*
611 * vpoio_attach()
612 *
613 * Low level attachment of vpo device
614 *
615 */
616int
617vpoio_attach(struct vpoio_data *vpo)
618{
619 device_t ppbus = device_get_parent(vpo->vpo_dev);
620 int epp;
621
622 vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
623 sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
624
625 if (!vpo->vpo_nibble_inbyte_msq)
626 return (ENXIO);
627
628 bcopy((void *)nibble_inbyte_submicroseq,
629 (void *)vpo->vpo_nibble_inbyte_msq,
630 sizeof(nibble_inbyte_submicroseq));
631
632 INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo);
633
634 /*
635 * Initialize mode dependent in/out microsequences
636 */
637 ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT);
638
639 /* enter NIBBLE mode to configure submsq */
640 if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) {
641
642 ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
643
644 ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
645 }
646
647 /* enter PS2 mode to configure submsq */
648 if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
649
650 ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq);
651
652 ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
653 }
654
655 epp = ppb_get_epp_protocol(ppbus);
656
657 /* enter EPP mode to configure submsq */
658 if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
659
660 switch (epp) {
661 case EPP_1_9:
662 /* XXX EPP 1.9 support should be improved */
663 case EPP_1_7:
664 ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr_body);
665
666 ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr_body);
667 break;
668 default:
669 panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
670 epp);
671 }
672 }
673
674 /* try to enter EPP or PS/2 mode, NIBBLE otherwise */
675 if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
676 switch (epp) {
677 case EPP_1_9:
678 printf("vpo%d: EPP 1.9 mode\n", vpo->vpo_unit);
679 break;
680 case EPP_1_7:
681 printf("vpo%d: EPP 1.7 mode\n", vpo->vpo_unit);
682 break;
683 default:
684 panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
685 epp);
686 }
687 } else if (ppb_set_mode(ppbus, PPB_PS2) != -1)
688 printf("vpo%d: PS2 mode\n", vpo->vpo_unit);
689
690 else if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1)
691 printf("vpo%d: NIBBLE mode\n", vpo->vpo_unit);
692
693 else {
694 printf("vpo%d: can't enter NIBBLE, PS2 or EPP mode\n",
695 vpo->vpo_unit);
696
697 ppb_release_bus(ppbus, vpo->vpo_dev);
698
699 free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);
700 return (ENXIO);
701 }
702
703 ppb_release_bus(ppbus, vpo->vpo_dev);
704
705 return (0);
706}
707
708/*
709 * vpoio_reset_bus()
710 *
711 */
712int
713vpoio_reset_bus(struct vpoio_data *vpo)

--- 24 unchanged lines hidden (view full) ---

738 * Send an SCSI command
739 *
740 */
741int
742vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
743 int clen, char *buffer, int blen, int *result, int *count,
744 int *ret)
745{
746 device_t ppbus = device_get_parent(vpo->vpo_dev);
747 register char r;
748 char l, h = 0;
749 int len, error = 0;
750 register int k;
751
752 /*
753 * enter disk state, allocate the ppbus
754 *

--- 12 unchanged lines hidden (view full) ---

767 if ((*ret = vpoio_select(vpo,host,target)))
768 goto error;
769
770 /*
771 * Send the command ...
772 *
773 * set H_SELIN low for vpoio_wait().
774 */
775 ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
776
777 for (k = 0; k < clen; k++) {
778 if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
779 *ret = VP0_ECMD_TIMEOUT;
780 goto error;
781 }
782 if (vpoio_outstr(vpo, &command[k], 1)) {
783 *ret = VP0_EPPDATA_TIMEOUT;

--- 19 unchanged lines hidden (view full) ---

803 if (*count >= blen) {
804 *ret = VP0_EDATA_OVERFLOW;
805 goto error;
806 }
807
808 /* if in EPP mode or writing bytes, try to transfer a sector
809 * otherwise, just send one byte
810 */
811 if (PPB_IN_EPP_MODE(ppbus) || r == (char)0xc0)
812 len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
813 VP0_SECTOR_SIZE : 1;
814 else
815 len = 1;
816
817 /* ZIP wants to send data? */
818 if (r == (char)0xc0)
819 error = vpoio_outstr(vpo, &buffer[*count], len);

--- 28 unchanged lines hidden ---