Remove vpo.4
The Parallel Port SCSI adapter was interesting for 100MB ZIP drives, but is no longer used or maintained. Remove it from the tree. The Parallel Port microsequencer (microseq.9) is now mostly unused in the tree, but remains. PPI still refrences it, but doesn't use its full functionality. Relnotes: Yes Reviewed by: rgrimes@, Ihor Antonov Discussed on: arch@ Differential Revision: https://reviews.freebsd.org/D23389
This commit is contained in:
parent
5a622926ea
commit
51691e26d0
@ -36,6 +36,10 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20200127: vpo removed
|
||||
OLD_FILES+=usr/share/man/man4/imm.4.gz
|
||||
OLD_FILES+=usr/share/man/man4/vpo.4.gz
|
||||
|
||||
# 20200104: gcc libssp removed
|
||||
OLD_FILES+=usr/include/ssp/ssp.h
|
||||
OLD_FILES+=usr/include/ssp/stdio.h
|
||||
|
@ -553,7 +553,6 @@ MAN= aac.4 \
|
||||
${_vmd.4} \
|
||||
${_vmm.4} \
|
||||
${_vmx.4} \
|
||||
vpo.4 \
|
||||
vr.4 \
|
||||
vt.4 \
|
||||
vte.4 \
|
||||
@ -740,7 +739,6 @@ MLINKS+=vge.4 if_vge.4
|
||||
MLINKS+=vlan.4 if_vlan.4
|
||||
MLINKS+=vxlan.4 if_vxlan.4
|
||||
MLINKS+=${_vmx.4} ${_if_vmx.4}
|
||||
MLINKS+=vpo.4 imm.4
|
||||
MLINKS+=vr.4 if_vr.4
|
||||
MLINKS+=vte.4 if_vte.4
|
||||
MLINKS+=${_vtnet.4} ${_if_vtnet.4}
|
||||
|
@ -33,8 +33,6 @@
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device ppbus"
|
||||
.Pp
|
||||
.Cd "device vpo"
|
||||
.Pp
|
||||
.Cd "device lpt"
|
||||
.Cd "device plip"
|
||||
.Cd "device ppi"
|
||||
@ -66,8 +64,6 @@ and non-standard software:
|
||||
.Pp
|
||||
.Bl -column "Driver" -compact
|
||||
.It Em Driver Ta Em Description
|
||||
.It Sy vpo Ta "VPI0 parallel to Adaptec AIC-7110 SCSI controller driver" .
|
||||
It uses standard and non-standard parallel port accesses.
|
||||
.It Sy ppi Ta "Parallel port interface for general I/O"
|
||||
.It Sy pps Ta "Pulse per second Timing Interface"
|
||||
.It Sy lpbb Ta "Philips official parallel port I2C bit-banging interface"
|
||||
@ -336,22 +332,11 @@ operation (opcodes are described in
|
||||
.Xr microseq 9 ) .
|
||||
Standard I/O operations are implemented at ppbus level whereas basic I/O
|
||||
operations and microseq language are coded at adapter level for efficiency.
|
||||
.Pp
|
||||
As an example, the
|
||||
.Xr vpo 4
|
||||
driver uses microsequences to implement:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
a modified version of the NIBBLE transfer mode
|
||||
.It
|
||||
various I/O sequences to initialize, select and allocate the peripheral
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr lpt 4 ,
|
||||
.Xr plip 4 ,
|
||||
.Xr ppc 4 ,
|
||||
.Xr ppi 4 ,
|
||||
.Xr vpo 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
@ -1,111 +0,0 @@
|
||||
.\" Copyright (c) 1998, 1999, Nicolas Souchu
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 21, 2019
|
||||
.Dt VPO 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm vpo
|
||||
.Nd parallel to SCSI interface driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device vpo"
|
||||
.Pp
|
||||
For one or more SCSI busses:
|
||||
.Cd "device scbus"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provide access to parallel port Iomega Zip and Jaz drives.
|
||||
.Sh DEPRECATED
|
||||
The
|
||||
.Nm
|
||||
driver is now deprecated.
|
||||
It will be removed in
|
||||
.Fx 13.0 .
|
||||
.Sh HARDWARE
|
||||
The
|
||||
.Nm
|
||||
driver supports the following parallel to SCSI interfaces:
|
||||
.Pp
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
Adaptec AIC-7110 Parallel to SCSI interface (built-in to Iomega ZIP
|
||||
drives)
|
||||
.It
|
||||
Iomega Jaz Traveller interface
|
||||
.It
|
||||
Iomega MatchMaker SCSI interface (built-in to Iomega ZIP+ drives)
|
||||
.El
|
||||
.Sh USAGE
|
||||
The driver should let you use a printer connected to the drive while
|
||||
transferring data.
|
||||
.Pp
|
||||
DOS and
|
||||
.Fx
|
||||
file systems are supported.
|
||||
When mounting a DOS file system or
|
||||
formatting a
|
||||
.Fx
|
||||
file system, check the slice of the disk with the
|
||||
.Xr gpart 8
|
||||
utility.
|
||||
.Pp
|
||||
In order to unixify a ZIP disk, put the following in /etc/disktab:
|
||||
.Bd -literal
|
||||
zip|zip 100:\\
|
||||
:ty=removable:se#512:nc#96:nt#64:ns#32:\\
|
||||
:pa#196608:oa#0:ba#4096:fa#512:\\
|
||||
:pb#196608:ob#0:bb#4096:fb#512:\\
|
||||
:pc#196608:oc#0:bc#4096:fc#512:
|
||||
.Ed
|
||||
.Pp
|
||||
and use
|
||||
.Xr bsdlabel 8 .
|
||||
.Pp
|
||||
If you have trouble with your driver, your parallel chipset may not run
|
||||
properly at the detected mode (NIBBLE, PS2 or EPP).
|
||||
Tune the
|
||||
.Xr ppc 4
|
||||
bootflags to force other modes.
|
||||
.Sh SEE ALSO
|
||||
.Xr da 4 ,
|
||||
.Xr lpt 4 ,
|
||||
.Xr ppbus 4 ,
|
||||
.Xr ppc 4 ,
|
||||
.Xr scsi 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
manual page first appeared in
|
||||
.Fx 3.0 .
|
||||
.Sh AUTHORS
|
||||
This
|
||||
manual page was written by
|
||||
.An Nicolas Souchu .
|
||||
.Sh BUGS
|
||||
During boot, the driver first tries to detect a classic ZIP, then a ZIP+.
|
||||
The ZIP+ detection is intrusive and may send erroneous characters to your
|
||||
printer if the drive is not connected to your parallel port.
|
@ -51,7 +51,7 @@ efficient code
|
||||
Before using microsequences, you are encouraged to look at
|
||||
.Xr ppc 4
|
||||
microsequencer implementation and an example of how using it in
|
||||
.Xr vpo 4 .
|
||||
.Xr ppi 4 .
|
||||
.Sh PPBUS register model
|
||||
.Ss Background
|
||||
The parallel port model chosen for ppbus is the PC parallel port model.
|
||||
@ -477,7 +477,7 @@ executed at ppbus layer.
|
||||
.Sh SEE ALSO
|
||||
.Xr ppbus 4 ,
|
||||
.Xr ppc 4 ,
|
||||
.Xr vpo 4
|
||||
.Xr ppi 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
@ -2358,9 +2358,6 @@ device syr827 # Silergy Corp. DC/DC regulator
|
||||
# are automatically probed and attached when found.
|
||||
#
|
||||
# Supported devices:
|
||||
# vpo Iomega Zip Drive
|
||||
# Requires SCSI disk support ('scbus' and 'da'), best
|
||||
# performance is achieved with ports in EPP 1.9 mode.
|
||||
# lpt Parallel Printer
|
||||
# plip Parallel network interface
|
||||
# ppi General-purpose I/O ("Geek Port") + IEEE1284 I/O
|
||||
@ -2378,7 +2375,6 @@ options DEBUG_1284 # IEEE1284 signaling protocol debug
|
||||
options PERIPH_1284 # Makes your computer act as an IEEE1284
|
||||
# compliant peripheral
|
||||
options DONTPROBE_1284 # Avoid boot detection of PnP parallel devices
|
||||
options VP0_DEBUG # ZIP/ZIP+ debug
|
||||
options LPT_DEBUG # Printer driver debug
|
||||
options PPC_DEBUG # Parallel chipset level debug
|
||||
options PLIP_DEBUG # Parallel network IP interface debug
|
||||
@ -2389,7 +2385,6 @@ device ppc
|
||||
hint.ppc.0.at="isa"
|
||||
hint.ppc.0.irq="7"
|
||||
device ppbus
|
||||
device vpo
|
||||
device lpt
|
||||
device plip
|
||||
device ppi
|
||||
|
@ -2672,7 +2672,6 @@ dev/pms/RefTisa/tisa/sassata/sata/host/ossasat.c optional pmspcv \
|
||||
dev/pms/RefTisa/tisa/sassata/sata/host/sathw.c optional pmspcv \
|
||||
compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w"
|
||||
dev/ppbus/if_plip.c optional plip
|
||||
dev/ppbus/immio.c optional vpo
|
||||
dev/ppbus/lpbb.c optional lpbb
|
||||
dev/ppbus/lpt.c optional lpt
|
||||
dev/ppbus/pcfclock.c optional pcfclock
|
||||
@ -2683,8 +2682,6 @@ dev/ppbus/ppbconf.c optional ppbus
|
||||
dev/ppbus/ppbus_if.m optional ppbus
|
||||
dev/ppbus/ppi.c optional ppi
|
||||
dev/ppbus/pps.c optional pps
|
||||
dev/ppbus/vpo.c optional vpo
|
||||
dev/ppbus/vpoio.c optional vpo
|
||||
dev/ppc/ppc.c optional ppc
|
||||
dev/ppc/ppc_acpi.c optional ppc acpi
|
||||
dev/ppc/ppc_isa.c optional ppc isa
|
||||
|
@ -569,7 +569,6 @@ TI_JUMBO_HDRSPLIT opt_ti.h
|
||||
# with 'make CC="cc -DDEBUG"'.
|
||||
CLUSTERDEBUG opt_debug_cluster.h
|
||||
DEBUG_1284 opt_ppb_1284.h
|
||||
VP0_DEBUG opt_vpo.h
|
||||
LPT_DEBUG opt_lpt.h
|
||||
PLIP_DEBUG opt_plip.h
|
||||
LOCKF_DEBUG opt_debug_lockf.h
|
||||
|
@ -1,818 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 1998, 1999 Nicolas Souchu
|
||||
* Copyright (c) 2001 Alcove - Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Iomega ZIP+ Matchmaker Parallel Port Interface driver
|
||||
*
|
||||
* Thanks to David Campbell work on the Linux driver and the Iomega specs
|
||||
* Thanks to Thiebault Moeglin for the drive
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbio.h>
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
#include <dev/ppbus/ppb_1284.h>
|
||||
|
||||
#include "ppbus_if.h"
|
||||
|
||||
#define VP0_SELTMO 5000 /* select timeout */
|
||||
#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
|
||||
#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
|
||||
|
||||
#define VP0_SECTOR_SIZE 512
|
||||
|
||||
/*
|
||||
* Microcode to execute very fast I/O sequences at the lowest bus level.
|
||||
*/
|
||||
|
||||
#define WAIT_RET MS_PARAM(7, 2, MS_TYP_PTR)
|
||||
#define WAIT_TMO MS_PARAM(1, 0, MS_TYP_INT)
|
||||
|
||||
#define DECLARE_WAIT_MICROSEQUENCE \
|
||||
struct ppb_microseq wait_microseq[] = { \
|
||||
MS_CASS(0x0c), \
|
||||
MS_SET(MS_UNKNOWN), \
|
||||
/* loop */ \
|
||||
MS_BRSET(nBUSY, 4 /* ready */), \
|
||||
MS_DBRA(-2 /* loop */), \
|
||||
MS_CASS(0x04), \
|
||||
MS_RET(1), /* timed out */ \
|
||||
/* ready */ \
|
||||
MS_CASS(0x04), \
|
||||
MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN ), \
|
||||
MS_RET(0) /* no error */ \
|
||||
}
|
||||
|
||||
#define SELECT_TARGET MS_PARAM(6, 1, MS_TYP_CHA)
|
||||
|
||||
#define DECLARE_SELECT_MICROSEQUENCE \
|
||||
struct ppb_microseq select_microseq[] = { \
|
||||
MS_CASS(0xc), \
|
||||
/* first, check there is nothing holding onto the bus */ \
|
||||
MS_SET(VP0_SELTMO), \
|
||||
/* _loop: */ \
|
||||
MS_BRCLEAR(0x8, 2 /* _ready */), \
|
||||
MS_DBRA(-2 /* _loop */), \
|
||||
MS_RET(2), /* bus busy */ \
|
||||
/* _ready: */ \
|
||||
MS_CASS(0x4), \
|
||||
MS_DASS(MS_UNKNOWN /* 0x80 | 1 << target */), \
|
||||
MS_DELAY(1), \
|
||||
MS_CASS(0xc), \
|
||||
MS_CASS(0xd), \
|
||||
/* now, wait until the drive is ready */ \
|
||||
MS_SET(VP0_SELTMO), \
|
||||
/* loop: */ \
|
||||
MS_BRSET(0x8, 3 /* ready */), \
|
||||
MS_DBRA(-2 /* loop */), \
|
||||
/* error: */ \
|
||||
MS_CASS(0xc), \
|
||||
MS_RET(VP0_ESELECT_TIMEOUT), \
|
||||
/* ready: */ \
|
||||
MS_CASS(0xc), \
|
||||
MS_RET(0) \
|
||||
}
|
||||
|
||||
static struct ppb_microseq transfer_epilog[] = {
|
||||
MS_CASS(0x4),
|
||||
MS_CASS(0xc),
|
||||
MS_CASS(0xe),
|
||||
MS_CASS(0x4),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
#define CPP_S1 MS_PARAM(10, 2, MS_TYP_PTR)
|
||||
#define CPP_S2 MS_PARAM(13, 2, MS_TYP_PTR)
|
||||
#define CPP_S3 MS_PARAM(16, 2, MS_TYP_PTR)
|
||||
#define CPP_PARAM MS_PARAM(17, 1, MS_TYP_CHA)
|
||||
|
||||
#define DECLARE_CPP_MICROSEQ \
|
||||
struct ppb_microseq cpp_microseq[] = { \
|
||||
MS_CASS(0x0c), MS_DELAY(2), \
|
||||
MS_DASS(0xaa), MS_DELAY(10), \
|
||||
MS_DASS(0x55), MS_DELAY(10), \
|
||||
MS_DASS(0x00), MS_DELAY(10), \
|
||||
MS_DASS(0xff), MS_DELAY(10), \
|
||||
MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s1 */), \
|
||||
MS_DASS(0x87), MS_DELAY(10), \
|
||||
MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s2 */), \
|
||||
MS_DASS(0x78), MS_DELAY(10), \
|
||||
MS_RFETCH(MS_REG_STR, 0x38, MS_UNKNOWN /* &s3 */), \
|
||||
MS_DASS(MS_UNKNOWN /* param */), \
|
||||
MS_DELAY(2), \
|
||||
MS_CASS(0x0c), MS_DELAY(10), \
|
||||
MS_CASS(0x0d), MS_DELAY(2), \
|
||||
MS_CASS(0x0c), MS_DELAY(10), \
|
||||
MS_DASS(0xff), MS_DELAY(10), \
|
||||
MS_RET(0) \
|
||||
}
|
||||
|
||||
#define NEGOCIATED_MODE MS_PARAM(2, 1, MS_TYP_CHA)
|
||||
|
||||
#define DECLARE_NEGOCIATE_MICROSEQ \
|
||||
struct ppb_microseq negociate_microseq[] = { \
|
||||
MS_CASS(0x4), \
|
||||
MS_DELAY(5), \
|
||||
MS_DASS(MS_UNKNOWN /* mode */), \
|
||||
MS_DELAY(100), \
|
||||
MS_CASS(0x6), \
|
||||
MS_DELAY(5), \
|
||||
MS_BRSET(0x20, 5 /* continue */), \
|
||||
MS_DELAY(5), \
|
||||
MS_CASS(0x7), \
|
||||
MS_DELAY(5), \
|
||||
MS_CASS(0x6), \
|
||||
MS_RET(VP0_ENEGOCIATE), \
|
||||
/* continue: */ \
|
||||
MS_DELAY(5), \
|
||||
MS_CASS(0x7), \
|
||||
MS_DELAY(5), \
|
||||
MS_CASS(0x6), \
|
||||
MS_RET(0) \
|
||||
}
|
||||
|
||||
#define INB_NIBBLE_L MS_PARAM(3, 2, MS_TYP_PTR)
|
||||
#define INB_NIBBLE_H MS_PARAM(6, 2, MS_TYP_PTR)
|
||||
#define INB_NIBBLE_F MS_PARAM(9, 0, MS_TYP_FUN)
|
||||
#define INB_NIBBLE_P MS_PARAM(9, 1, MS_TYP_PTR)
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in NIBBLE mode
|
||||
* Retrieve the two nibbles and call the C function to generate the character
|
||||
* and store it in the buffer (see nibble_inbyte_hook())
|
||||
*/
|
||||
|
||||
#define DECLARE_NIBBLE_INBYTE_SUBMICROSEQ \
|
||||
struct ppb_microseq nibble_inbyte_submicroseq[] = { \
|
||||
MS_CASS(0x4), \
|
||||
/* loop: */ \
|
||||
MS_CASS(0x6), \
|
||||
MS_DELAY(1), \
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */),\
|
||||
MS_CASS(0x5), \
|
||||
MS_DELAY(1), \
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */),\
|
||||
MS_CASS(0x4), \
|
||||
MS_DELAY(1), \
|
||||
/* do a C call to format the received nibbles */ \
|
||||
MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */), \
|
||||
MS_DBRA(-7 /* loop */), \
|
||||
MS_RET(0) \
|
||||
}
|
||||
|
||||
static struct ppb_microseq reset_microseq[] = {
|
||||
MS_CASS(0x04),
|
||||
MS_DASS(0x40),
|
||||
MS_DELAY(1),
|
||||
MS_CASS(0x0c),
|
||||
MS_CASS(0x0d),
|
||||
MS_DELAY(50),
|
||||
MS_CASS(0x0c),
|
||||
MS_CASS(0x04),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* nibble_inbyte_hook()
|
||||
*
|
||||
* Formats high and low nibble into a character
|
||||
*/
|
||||
static int
|
||||
nibble_inbyte_hook (void *p, char *ptr)
|
||||
{
|
||||
struct vpo_nibble *s = (struct vpo_nibble *)p;
|
||||
|
||||
/* increment the buffer pointer */
|
||||
*ptr = ((s->l >> 4) & 0x0f) + (s->h & 0xf0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in PS2 mode
|
||||
*/
|
||||
static struct ppb_microseq ps2_inbyte_submicroseq[] = {
|
||||
MS_CASS(0x4),
|
||||
|
||||
/* loop: */
|
||||
MS_CASS(PCD | 0x6),
|
||||
MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL),
|
||||
MS_CASS(PCD | 0x5),
|
||||
MS_DBRA(-4 /* loop */),
|
||||
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes
|
||||
*/
|
||||
static struct ppb_microseq spp_outbyte_submicroseq[] = {
|
||||
MS_CASS(0x4),
|
||||
|
||||
/* loop: */
|
||||
MS_RASSERT_P(1, MS_REG_DTR),
|
||||
MS_CASS(0x5),
|
||||
MS_DBRA(0), /* decrement counter */
|
||||
MS_RASSERT_P(1, MS_REG_DTR),
|
||||
MS_CASS(0x0),
|
||||
MS_DBRA(-6 /* loop */),
|
||||
|
||||
/* return from the put call */
|
||||
MS_CASS(0x4),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* EPP 1.7 microsequences, ptr and len set at runtime */
|
||||
static struct ppb_microseq epp17_outstr[] = {
|
||||
MS_CASS(0x4),
|
||||
MS_RASSERT_P(MS_ACCUM, MS_REG_EPP_D),
|
||||
MS_CASS(0xc),
|
||||
MS_RET(0),
|
||||
};
|
||||
|
||||
static struct ppb_microseq epp17_instr[] = {
|
||||
MS_CASS(PCD | 0x4),
|
||||
MS_RFETCH_P(MS_ACCUM, MS_REG_EPP_D, MS_FETCH_ALL),
|
||||
MS_CASS(PCD | 0xc),
|
||||
MS_RET(0),
|
||||
};
|
||||
|
||||
static int
|
||||
imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus)
|
||||
{
|
||||
DECLARE_CPP_MICROSEQ;
|
||||
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
char s1, s2, s3;
|
||||
int ret;
|
||||
|
||||
/* all should be ok */
|
||||
if (connected)
|
||||
*connected = 0;
|
||||
|
||||
ppb_MS_init_msq(cpp_microseq, 4, CPP_S1, (void *)&s1,
|
||||
CPP_S2, (void *)&s2, CPP_S3, (void *)&s3,
|
||||
CPP_PARAM, 0x30);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret);
|
||||
|
||||
if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38)) {
|
||||
if (bootverbose)
|
||||
device_printf(vpo->vpo_dev,
|
||||
"(disconnect) s1=0x%x s2=0x%x, s3=0x%x\n",
|
||||
s1 & 0xff, s2 & 0xff, s3 & 0xff);
|
||||
if (connected)
|
||||
*connected = VP0_ECONNECT;
|
||||
}
|
||||
|
||||
if (release_bus)
|
||||
return (ppb_release_bus(ppbus, vpo->vpo_dev));
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* how : PPB_WAIT or PPB_DONTWAIT
|
||||
*/
|
||||
static int
|
||||
imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus)
|
||||
{
|
||||
DECLARE_CPP_MICROSEQ;
|
||||
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
char s1, s2, s3;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
/* all should be ok */
|
||||
if (disconnected)
|
||||
*disconnected = 0;
|
||||
|
||||
if (request_bus)
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, how)))
|
||||
return (error);
|
||||
|
||||
ppb_MS_init_msq(cpp_microseq, 3, CPP_S1, (void *)&s1,
|
||||
CPP_S2, (void *)&s2, CPP_S3, (void *)&s3);
|
||||
|
||||
/* select device 0 in compatible mode */
|
||||
ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0);
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret);
|
||||
|
||||
/* disconnect all devices */
|
||||
ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x30);
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret);
|
||||
|
||||
if (PPB_IN_EPP_MODE(ppbus))
|
||||
ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x28);
|
||||
else
|
||||
ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, cpp_microseq, &ret);
|
||||
|
||||
if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30)) {
|
||||
if (bootverbose)
|
||||
device_printf(vpo->vpo_dev,
|
||||
"(connect) s1=0x%x s2=0x%x, s3=0x%x\n",
|
||||
s1 & 0xff, s2 & 0xff, s3 & 0xff);
|
||||
if (disconnected)
|
||||
*disconnected = VP0_ECONNECT;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_detect()
|
||||
*
|
||||
* Detect and initialise the VP0 adapter.
|
||||
*/
|
||||
static int
|
||||
imm_detect(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error;
|
||||
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT)))
|
||||
return (error);
|
||||
|
||||
/* disconnect the drive, keep the bus */
|
||||
imm_disconnect(vpo, NULL, 0);
|
||||
|
||||
vpo->vpo_mode_found = VP0_MODE_UNDEFINED;
|
||||
error = 1;
|
||||
|
||||
/* try to enter EPP mode since vpoio failure put the bus in NIBBLE */
|
||||
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
|
||||
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
|
||||
}
|
||||
|
||||
/* if connection failed try PS/2 then NIBBLE modes */
|
||||
if (error) {
|
||||
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
|
||||
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
|
||||
}
|
||||
if (error) {
|
||||
if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) {
|
||||
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
|
||||
if (error)
|
||||
goto error;
|
||||
vpo->vpo_mode_found = VP0_MODE_NIBBLE;
|
||||
} else {
|
||||
device_printf(vpo->vpo_dev,
|
||||
"NIBBLE mode unavailable!\n");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
vpo->vpo_mode_found = VP0_MODE_PS2;
|
||||
}
|
||||
} else {
|
||||
vpo->vpo_mode_found = VP0_MODE_EPP;
|
||||
}
|
||||
|
||||
/* send SCSI reset signal */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, NULL);
|
||||
|
||||
/* release the bus now */
|
||||
imm_disconnect(vpo, &error, 1);
|
||||
|
||||
/* ensure we are disconnected or daisy chained peripheral
|
||||
* may cause serious problem to the disk */
|
||||
|
||||
if (error) {
|
||||
if (bootverbose)
|
||||
device_printf(vpo->vpo_dev,
|
||||
"can't disconnect from the drive\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
ppb_release_bus(ppbus, vpo->vpo_dev);
|
||||
return (VP0_EINITFAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_outstr()
|
||||
*/
|
||||
static int
|
||||
imm_outstr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
if (PPB_IN_EPP_MODE(ppbus))
|
||||
ppb_reset_epp_timeout(ppbus);
|
||||
|
||||
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer,
|
||||
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_instr()
|
||||
*/
|
||||
static int
|
||||
imm_instr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
if (PPB_IN_EPP_MODE(ppbus))
|
||||
ppb_reset_epp_timeout(ppbus);
|
||||
|
||||
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer,
|
||||
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static char
|
||||
imm_select(struct vpoio_data *vpo, int initiator, int target)
|
||||
{
|
||||
DECLARE_SELECT_MICROSEQUENCE;
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret;
|
||||
|
||||
/* initialize the select microsequence */
|
||||
ppb_MS_init_msq(select_microseq, 1,
|
||||
SELECT_TARGET, 1 << initiator | 1 << target);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_wait()
|
||||
*
|
||||
* H_SELIN must be low.
|
||||
*
|
||||
*/
|
||||
static char
|
||||
imm_wait(struct vpoio_data *vpo, int tmo)
|
||||
{
|
||||
DECLARE_WAIT_MICROSEQUENCE;
|
||||
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret, err;
|
||||
|
||||
/*
|
||||
* Return some status information.
|
||||
* Semantics : 0x88 = ZIP+ wants more data
|
||||
* 0x98 = ZIP+ wants to send more data
|
||||
* 0xa8 = ZIP+ wants command
|
||||
* 0xb8 = end of transfer, ZIP+ is sending status
|
||||
*/
|
||||
|
||||
ppb_MS_init_msq(wait_microseq, 2,
|
||||
WAIT_RET, (void *)&ret,
|
||||
WAIT_TMO, tmo);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, wait_microseq, &err);
|
||||
|
||||
if (err)
|
||||
return (0); /* command timed out */
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
imm_negociate(struct vpoio_data *vpo)
|
||||
{
|
||||
DECLARE_NEGOCIATE_MICROSEQ;
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int negociate_mode;
|
||||
int ret;
|
||||
|
||||
if (PPB_IN_NIBBLE_MODE(ppbus))
|
||||
negociate_mode = 0;
|
||||
else if (PPB_IN_PS2_MODE(ppbus))
|
||||
negociate_mode = 1;
|
||||
else
|
||||
return (0);
|
||||
|
||||
#if 0 /* XXX use standalone code not to depend on ppb_1284 code yet */
|
||||
ret = ppb_1284_negociate(ppbus, negociate_mode);
|
||||
|
||||
if (ret)
|
||||
return (VP0_ENEGOCIATE);
|
||||
#endif
|
||||
|
||||
ppb_MS_init_msq(negociate_microseq, 1,
|
||||
NEGOCIATED_MODE, negociate_mode);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, negociate_microseq, &ret);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_probe()
|
||||
*
|
||||
* Low level probe of vpo device
|
||||
*
|
||||
*/
|
||||
int
|
||||
imm_probe(device_t dev, struct vpoio_data *vpo)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* ppbus dependent initialisation */
|
||||
vpo->vpo_dev = dev;
|
||||
|
||||
/* now, try to initialise the drive */
|
||||
if ((error = imm_detect(vpo))) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_attach()
|
||||
*
|
||||
* Low level attachment of vpo device
|
||||
*
|
||||
*/
|
||||
int
|
||||
imm_attach(struct vpoio_data *vpo)
|
||||
{
|
||||
DECLARE_NIBBLE_INBYTE_SUBMICROSEQ;
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Initialize microsequence code
|
||||
*/
|
||||
vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
|
||||
sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!vpo->vpo_nibble_inbyte_msq)
|
||||
return (ENXIO);
|
||||
|
||||
bcopy((void *)nibble_inbyte_submicroseq,
|
||||
(void *)vpo->vpo_nibble_inbyte_msq,
|
||||
sizeof(nibble_inbyte_submicroseq));
|
||||
|
||||
ppb_MS_init_msq(vpo->vpo_nibble_inbyte_msq, 4,
|
||||
INB_NIBBLE_H, (void *)&(vpo)->vpo_nibble.h,
|
||||
INB_NIBBLE_L, (void *)&(vpo)->vpo_nibble.l,
|
||||
INB_NIBBLE_F, nibble_inbyte_hook,
|
||||
INB_NIBBLE_P, (void *)&(vpo)->vpo_nibble);
|
||||
|
||||
/*
|
||||
* Initialize mode dependent in/out microsequences
|
||||
*/
|
||||
ppb_lock(ppbus);
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT)))
|
||||
goto error;
|
||||
|
||||
/* ppbus automatically restore the last mode entered during detection */
|
||||
switch (vpo->vpo_mode_found) {
|
||||
case VP0_MODE_EPP:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr);
|
||||
device_printf(vpo->vpo_dev, "EPP mode\n");
|
||||
break;
|
||||
case VP0_MODE_PS2:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
device_printf(vpo->vpo_dev, "PS2 mode\n");
|
||||
break;
|
||||
case VP0_MODE_NIBBLE:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
device_printf(vpo->vpo_dev, "NIBBLE mode\n");
|
||||
break;
|
||||
default:
|
||||
panic("imm: unknown mode %d", vpo->vpo_mode_found);
|
||||
}
|
||||
|
||||
ppb_release_bus(ppbus, vpo->vpo_dev);
|
||||
error:
|
||||
ppb_unlock(ppbus);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_reset_bus()
|
||||
*
|
||||
*/
|
||||
int
|
||||
imm_reset_bus(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int disconnected;
|
||||
|
||||
/* first, connect to the drive and request the bus */
|
||||
imm_connect(vpo, PPB_WAIT|PPB_INTR, &disconnected, 1);
|
||||
|
||||
if (!disconnected) {
|
||||
|
||||
/* reset the SCSI bus */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, NULL);
|
||||
|
||||
/* then disconnect */
|
||||
imm_disconnect(vpo, NULL, 1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* imm_do_scsi()
|
||||
*
|
||||
* Send an SCSI command
|
||||
*
|
||||
*/
|
||||
int
|
||||
imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
char r;
|
||||
char l, h = 0;
|
||||
int len, error = 0, not_connected = 0;
|
||||
int k;
|
||||
int negociated = 0;
|
||||
|
||||
/*
|
||||
* enter disk state, allocate the ppbus
|
||||
*
|
||||
* XXX
|
||||
* Should we allow this call to be interruptible?
|
||||
* The only way to report the interruption is to return
|
||||
* EIO to upper SCSI code :^(
|
||||
*/
|
||||
if ((error = imm_connect(vpo, PPB_WAIT|PPB_INTR, ¬_connected, 1)))
|
||||
return (error);
|
||||
|
||||
if (not_connected) {
|
||||
*ret = VP0_ECONNECT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the drive ...
|
||||
*/
|
||||
if ((*ret = imm_select(vpo,host,target)))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Send the command ...
|
||||
*/
|
||||
for (k = 0; k < clen; k+=2) {
|
||||
if (imm_wait(vpo, VP0_FAST_SPINTMO) != (char)0xa8) {
|
||||
*ret = VP0_ECMD_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
if (imm_outstr(vpo, &command[k], 2)) {
|
||||
*ret = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(r = imm_wait(vpo, VP0_LOW_SPINTMO))) {
|
||||
*ret = VP0_ESTATUS_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((r & 0x30) == 0x10) {
|
||||
if (imm_negociate(vpo)) {
|
||||
*ret = VP0_ENEGOCIATE;
|
||||
goto error;
|
||||
} else
|
||||
negociated = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Complete transfer ...
|
||||
*/
|
||||
*count = 0;
|
||||
for (;;) {
|
||||
|
||||
if (!(r = imm_wait(vpo, VP0_LOW_SPINTMO))) {
|
||||
*ret = VP0_ESTATUS_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* stop when the ZIP+ wants to send status */
|
||||
if (r == (char)0xb8)
|
||||
break;
|
||||
|
||||
if (*count >= blen) {
|
||||
*ret = VP0_EDATA_OVERFLOW;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* ZIP+ wants to send data? */
|
||||
if (r == (char)0x88) {
|
||||
len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
|
||||
VP0_SECTOR_SIZE : 2;
|
||||
|
||||
error = imm_outstr(vpo, &buffer[*count], len);
|
||||
} else {
|
||||
if (!PPB_IN_EPP_MODE(ppbus))
|
||||
len = 1;
|
||||
else
|
||||
len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
|
||||
VP0_SECTOR_SIZE : 1;
|
||||
|
||||
error = imm_instr(vpo, &buffer[*count], len);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
*ret = error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*count += len;
|
||||
}
|
||||
|
||||
if ((PPB_IN_NIBBLE_MODE(ppbus) ||
|
||||
PPB_IN_PS2_MODE(ppbus)) && negociated)
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, transfer_epilog, NULL);
|
||||
|
||||
/*
|
||||
* Retrieve status ...
|
||||
*/
|
||||
if (imm_negociate(vpo)) {
|
||||
*ret = VP0_ENEGOCIATE;
|
||||
goto error;
|
||||
} else
|
||||
negociated = 1;
|
||||
|
||||
if (imm_instr(vpo, &l, 1)) {
|
||||
*ret = VP0_EOTHER;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check if the ZIP+ wants to send more status */
|
||||
if (imm_wait(vpo, VP0_FAST_SPINTMO) == (char)0xb8)
|
||||
if (imm_instr(vpo, &h, 1)) {
|
||||
*ret = VP0_EOTHER + 2;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Experience showed that we should discard this */
|
||||
if (h == (char) -1)
|
||||
h = 0;
|
||||
|
||||
*result = ((int) h << 8) | ((int) l & 0xff);
|
||||
|
||||
error:
|
||||
if ((PPB_IN_NIBBLE_MODE(ppbus) ||
|
||||
PPB_IN_PS2_MODE(ppbus)) && negociated)
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, transfer_epilog, NULL);
|
||||
|
||||
/* return to printer state, release the ppbus */
|
||||
imm_disconnect(vpo, NULL, 1);
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,441 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 1999 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_sim.h>
|
||||
#include <cam/cam_xpt_sim.h>
|
||||
#include <cam/cam_debug.h>
|
||||
#include <cam/cam_periph.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <cam/scsi/scsi_da.h>
|
||||
|
||||
#include <sys/kernel.h>
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
||||
#include "ppbus_if.h"
|
||||
|
||||
struct vpo_sense {
|
||||
struct scsi_sense cmd;
|
||||
unsigned int stat;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
struct vpo_data {
|
||||
device_t vpo_dev;
|
||||
int vpo_stat;
|
||||
int vpo_count;
|
||||
int vpo_error;
|
||||
|
||||
int vpo_isplus;
|
||||
|
||||
struct cam_sim *sim;
|
||||
|
||||
struct vpo_sense vpo_sense;
|
||||
|
||||
struct vpoio_data vpo_io; /* interface to low level functions */
|
||||
};
|
||||
|
||||
#define DEVTOSOFTC(dev) \
|
||||
((struct vpo_data *)device_get_softc(dev))
|
||||
|
||||
/* cam related functions */
|
||||
static void vpo_action(struct cam_sim *sim, union ccb *ccb);
|
||||
static void vpo_poll(struct cam_sim *sim);
|
||||
|
||||
static void
|
||||
vpo_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
|
||||
device_t dev;
|
||||
|
||||
dev = device_find_child(parent, "vpo", -1);
|
||||
if (!dev)
|
||||
BUS_ADD_CHILD(parent, 0, "vpo", -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpo_probe()
|
||||
*/
|
||||
static int
|
||||
vpo_probe(device_t dev)
|
||||
{
|
||||
device_t ppbus = device_get_parent(dev);
|
||||
struct vpo_data *vpo;
|
||||
int error;
|
||||
|
||||
vpo = DEVTOSOFTC(dev);
|
||||
vpo->vpo_dev = dev;
|
||||
|
||||
/* check ZIP before ZIP+ or imm_probe() will send controls to
|
||||
* the printer or whatelse connected to the port */
|
||||
ppb_lock(ppbus);
|
||||
if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) {
|
||||
vpo->vpo_isplus = 0;
|
||||
device_set_desc(dev,
|
||||
"Iomega VPI0 Parallel to SCSI interface");
|
||||
} else if ((error = imm_probe(dev, &vpo->vpo_io)) == 0) {
|
||||
vpo->vpo_isplus = 1;
|
||||
device_set_desc(dev,
|
||||
"Iomega Matchmaker Parallel to SCSI interface");
|
||||
} else {
|
||||
ppb_unlock(ppbus);
|
||||
return (error);
|
||||
}
|
||||
ppb_unlock(ppbus);
|
||||
gone_in_dev(dev, 13, "Hardware no longer relevant");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpo_attach()
|
||||
*/
|
||||
static int
|
||||
vpo_attach(device_t dev)
|
||||
{
|
||||
struct vpo_data *vpo = DEVTOSOFTC(dev);
|
||||
device_t ppbus = device_get_parent(dev);
|
||||
struct ppb_data *ppb = device_get_softc(ppbus); /* XXX: layering */
|
||||
struct cam_devq *devq;
|
||||
int error;
|
||||
|
||||
/* low level attachment */
|
||||
if (vpo->vpo_isplus) {
|
||||
if ((error = imm_attach(&vpo->vpo_io)))
|
||||
return (error);
|
||||
} else {
|
||||
if ((error = vpoio_attach(&vpo->vpo_io)))
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
** Now tell the generic SCSI layer
|
||||
** about our bus.
|
||||
*/
|
||||
devq = cam_simq_alloc(/*maxopenings*/1);
|
||||
/* XXX What about low-level detach on error? */
|
||||
if (devq == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo,
|
||||
device_get_unit(dev), ppb->ppc_lock,
|
||||
/*untagged*/1, /*tagged*/0, devq);
|
||||
if (vpo->sim == NULL) {
|
||||
cam_simq_free(devq);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
ppb_lock(ppbus);
|
||||
if (xpt_bus_register(vpo->sim, dev, /*bus*/0) != CAM_SUCCESS) {
|
||||
cam_sim_free(vpo->sim, /*free_devq*/TRUE);
|
||||
ppb_unlock(ppbus);
|
||||
return (ENXIO);
|
||||
}
|
||||
ppb_unlock(ppbus);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpo_intr()
|
||||
*/
|
||||
static void
|
||||
vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
|
||||
{
|
||||
int errno; /* error in errno.h */
|
||||
#ifdef VP0_DEBUG
|
||||
int i;
|
||||
#endif
|
||||
uint8_t *ptr;
|
||||
|
||||
ptr = scsiio_cdb_ptr(csio);
|
||||
if (vpo->vpo_isplus) {
|
||||
errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
csio->ccb_h.target_id,
|
||||
ptr, csio->cdb_len,
|
||||
(char *)csio->data_ptr, csio->dxfer_len,
|
||||
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
|
||||
} else {
|
||||
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
csio->ccb_h.target_id,
|
||||
ptr, csio->cdb_len,
|
||||
(char *)csio->data_ptr, csio->dxfer_len,
|
||||
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
|
||||
}
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
|
||||
errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
|
||||
|
||||
/* dump of command */
|
||||
for (i=0; i<csio->cdb_len; i++)
|
||||
printf("%x ", ((char *)ptr)[i]);
|
||||
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (errno) {
|
||||
/* connection to ppbus interrupted */
|
||||
csio->ccb_h.status = CAM_CMD_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if a timeout occurred, no sense */
|
||||
if (vpo->vpo_error) {
|
||||
if (vpo->vpo_error != VP0_ESELECT_TIMEOUT)
|
||||
device_printf(vpo->vpo_dev, "VP0 error/timeout (%d)\n",
|
||||
vpo->vpo_error);
|
||||
|
||||
csio->ccb_h.status = CAM_CMD_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check scsi status */
|
||||
if (vpo->vpo_stat != SCSI_STATUS_OK) {
|
||||
csio->scsi_status = vpo->vpo_stat;
|
||||
|
||||
/* check if we have to sense the drive */
|
||||
if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) {
|
||||
|
||||
vpo->vpo_sense.cmd.opcode = REQUEST_SENSE;
|
||||
vpo->vpo_sense.cmd.length = csio->sense_len;
|
||||
vpo->vpo_sense.cmd.control = 0;
|
||||
|
||||
if (vpo->vpo_isplus) {
|
||||
errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
csio->ccb_h.target_id,
|
||||
(char *)&vpo->vpo_sense.cmd,
|
||||
sizeof(vpo->vpo_sense.cmd),
|
||||
(char *)&csio->sense_data, csio->sense_len,
|
||||
&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
|
||||
&vpo->vpo_error);
|
||||
} else {
|
||||
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
csio->ccb_h.target_id,
|
||||
(char *)&vpo->vpo_sense.cmd,
|
||||
sizeof(vpo->vpo_sense.cmd),
|
||||
(char *)&csio->sense_data, csio->sense_len,
|
||||
&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
|
||||
&vpo->vpo_error);
|
||||
}
|
||||
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
|
||||
errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error);
|
||||
#endif
|
||||
|
||||
/* check sense return status */
|
||||
if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) {
|
||||
/* sense ok */
|
||||
csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
|
||||
csio->sense_resid = csio->sense_len - vpo->vpo_sense.count;
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
/* dump of sense info */
|
||||
printf("(sense) ");
|
||||
for (i=0; i<vpo->vpo_sense.count; i++)
|
||||
printf("%x ", ((char *)&csio->sense_data)[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
} else {
|
||||
/* sense failed */
|
||||
csio->ccb_h.status = CAM_AUTOSENSE_FAIL;
|
||||
}
|
||||
} else {
|
||||
/* no sense */
|
||||
csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
csio->resid = csio->dxfer_len - vpo->vpo_count;
|
||||
csio->ccb_h.status = CAM_REQ_CMP;
|
||||
}
|
||||
|
||||
static void
|
||||
vpo_action(struct cam_sim *sim, union ccb *ccb)
|
||||
{
|
||||
struct vpo_data *vpo = (struct vpo_data *)sim->softc;
|
||||
|
||||
ppb_assert_locked(device_get_parent(vpo->vpo_dev));
|
||||
switch (ccb->ccb_h.func_code) {
|
||||
case XPT_SCSI_IO:
|
||||
{
|
||||
struct ccb_scsiio *csio;
|
||||
|
||||
csio = &ccb->csio;
|
||||
|
||||
if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
|
||||
ccb->ccb_h.status = CAM_REQ_INVALID;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
#ifdef VP0_DEBUG
|
||||
device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n",
|
||||
*scsiio_cdb_ptr(csio));
|
||||
#endif
|
||||
vpo_intr(vpo, csio);
|
||||
|
||||
xpt_done(ccb);
|
||||
|
||||
break;
|
||||
}
|
||||
case XPT_CALC_GEOMETRY:
|
||||
{
|
||||
struct ccb_calc_geometry *ccg;
|
||||
|
||||
ccg = &ccb->ccg;
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
device_printf(vpo->vpo_dev, "XPT_CALC_GEOMETRY (bs=%d,vs=%jd,c=%d,h=%d,spt=%d) request\n",
|
||||
ccg->block_size,
|
||||
(intmax_t)ccg->volume_size,
|
||||
ccg->cylinders,
|
||||
ccg->heads,
|
||||
ccg->secs_per_track);
|
||||
#endif
|
||||
|
||||
ccg->heads = 64;
|
||||
ccg->secs_per_track = 32;
|
||||
ccg->cylinders = ccg->volume_size /
|
||||
(ccg->heads * ccg->secs_per_track);
|
||||
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
|
||||
{
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
device_printf(vpo->vpo_dev, "XPT_RESET_BUS request\n");
|
||||
#endif
|
||||
|
||||
if (vpo->vpo_isplus) {
|
||||
if (imm_reset_bus(&vpo->vpo_io)) {
|
||||
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
xpt_done(ccb);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (vpoio_reset_bus(&vpo->vpo_io)) {
|
||||
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
xpt_done(ccb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
case XPT_PATH_INQ: /* Path routing inquiry */
|
||||
{
|
||||
struct ccb_pathinq *cpi = &ccb->cpi;
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
device_printf(vpo->vpo_dev, "XPT_PATH_INQ request\n");
|
||||
#endif
|
||||
cpi->version_num = 1; /* XXX??? */
|
||||
cpi->hba_inquiry = 0;
|
||||
cpi->target_sprt = 0;
|
||||
cpi->hba_misc = 0;
|
||||
cpi->hba_eng_cnt = 0;
|
||||
cpi->max_target = 7;
|
||||
cpi->max_lun = 0;
|
||||
cpi->initiator_id = VP0_INITIATOR;
|
||||
cpi->bus_id = sim->bus_id;
|
||||
cpi->base_transfer_speed = 93;
|
||||
strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
|
||||
strlcpy(cpi->hba_vid, "Iomega", HBA_IDLEN);
|
||||
strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
|
||||
cpi->unit_number = sim->unit_number;
|
||||
cpi->transport = XPORT_PPB;
|
||||
cpi->transport_version = 0;
|
||||
|
||||
cpi->ccb_h.status = CAM_REQ_CMP;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ccb->ccb_h.status = CAM_REQ_INVALID;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
vpo_poll(struct cam_sim *sim)
|
||||
{
|
||||
|
||||
/* The ZIP is actually always polled throw vpo_action(). */
|
||||
}
|
||||
|
||||
static devclass_t vpo_devclass;
|
||||
|
||||
static device_method_t vpo_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_identify, vpo_identify),
|
||||
DEVMETHOD(device_probe, vpo_probe),
|
||||
DEVMETHOD(device_attach, vpo_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t vpo_driver = {
|
||||
"vpo",
|
||||
vpo_methods,
|
||||
sizeof(struct vpo_data),
|
||||
};
|
||||
DRIVER_MODULE(vpo, ppbus, vpo_driver, vpo_devclass, 0, 0);
|
||||
MODULE_DEPEND(vpo, ppbus, 1, 1, 1);
|
||||
MODULE_DEPEND(vpo, cam, 1, 1, 1);
|
@ -1,789 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 1998, 1999 Nicolas Souchu
|
||||
* Copyright (c) 2000 Alcove - Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbio.h>
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
||||
#include "ppbus_if.h"
|
||||
|
||||
/*
|
||||
* The driver pools the drive. We may add a timeout queue to avoid
|
||||
* active polling on nACK. I've tried this but it leads to unreliable
|
||||
* transfers
|
||||
*/
|
||||
#define VP0_SELTMO 5000 /* select timeout */
|
||||
#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
|
||||
#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
|
||||
|
||||
/*
|
||||
* Actually, VP0 timings are more accurate (about few 16MHZ cycles),
|
||||
* but succeeding in respecting such timings leads to architecture
|
||||
* dependent considerations.
|
||||
*/
|
||||
#define VP0_PULSE 1
|
||||
|
||||
#define VP0_SECTOR_SIZE 512
|
||||
#define VP0_BUFFER_SIZE 0x12000
|
||||
|
||||
#define n(flags) (~(flags) & (flags))
|
||||
|
||||
/*
|
||||
* VP0 connections.
|
||||
*/
|
||||
#define H_AUTO n(AUTOFEED)
|
||||
#define H_nAUTO AUTOFEED
|
||||
#define H_STROBE n(STROBE)
|
||||
#define H_nSTROBE STROBE
|
||||
#define H_BSY n(nBUSY)
|
||||
#define H_nBSY nBUSY
|
||||
#define H_SEL SELECT
|
||||
#define H_nSEL n(SELECT)
|
||||
#define H_ERR PERROR
|
||||
#define H_nERR n(PERROR)
|
||||
#define H_ACK nACK
|
||||
#define H_nACK n(nACK)
|
||||
#define H_FLT nFAULT
|
||||
#define H_nFLT n(nFAULT)
|
||||
#define H_SELIN n(SELECTIN)
|
||||
#define H_nSELIN SELECTIN
|
||||
#define H_INIT nINIT
|
||||
#define H_nINIT n(nINIT)
|
||||
|
||||
/*
|
||||
* Microcode to execute very fast I/O sequences at the lowest bus level.
|
||||
*/
|
||||
|
||||
#define WAIT_RET MS_PARAM(4, 2, MS_TYP_PTR)
|
||||
#define WAIT_TMO MS_PARAM(0, 0, MS_TYP_INT)
|
||||
|
||||
#define DECLARE_WAIT_MICROSEQUENCE \
|
||||
struct ppb_microseq wait_microseq[] = { \
|
||||
MS_SET(MS_UNKNOWN), \
|
||||
/* loop */ \
|
||||
MS_BRSET(nBUSY, 2 /* ready */), \
|
||||
MS_DBRA(-2 /* loop */), \
|
||||
MS_RET(1), /* timed out */ \
|
||||
/* ready */ \
|
||||
MS_RFETCH(MS_REG_STR, 0xf0, MS_UNKNOWN), \
|
||||
MS_RET(0) /* no error */ \
|
||||
}
|
||||
|
||||
/* call this macro to initialize connect/disconnect microsequences */
|
||||
#define INIT_TRIG_MICROSEQ { \
|
||||
int i; \
|
||||
for (i=1; i <= 7; i+=2) { \
|
||||
disconnect_microseq[i].arg[2] = (union ppb_insarg)d_pulse; \
|
||||
connect_epp_microseq[i].arg[2] = \
|
||||
connect_spp_microseq[i].arg[2] = (union ppb_insarg)c_pulse; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define trig_d_pulse MS_TRIG(MS_REG_CTR,5,MS_UNKNOWN /* d_pulse */)
|
||||
static char d_pulse[] = {
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_nAUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE
|
||||
};
|
||||
|
||||
#define trig_c_pulse MS_TRIG(MS_REG_CTR,5,MS_UNKNOWN /* c_pulse */)
|
||||
static char c_pulse[] = {
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, 0,
|
||||
H_nAUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE
|
||||
};
|
||||
|
||||
static struct ppb_microseq disconnect_microseq[] = {
|
||||
MS_DASS(0x0), trig_d_pulse, MS_DASS(0x3c), trig_d_pulse,
|
||||
MS_DASS(0x20), trig_d_pulse, MS_DASS(0xf), trig_d_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
static struct ppb_microseq connect_epp_microseq[] = {
|
||||
MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,
|
||||
MS_DASS(0x20), trig_c_pulse, MS_DASS(0xcf), trig_c_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
static struct ppb_microseq connect_spp_microseq[] = {
|
||||
MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,
|
||||
MS_DASS(0x20), trig_c_pulse, MS_DASS(0x8f), trig_c_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* nibble_inbyte_hook()
|
||||
*
|
||||
* Formats high and low nibble into a character
|
||||
*/
|
||||
static int
|
||||
nibble_inbyte_hook (void *p, char *ptr)
|
||||
{
|
||||
struct vpo_nibble *s = (struct vpo_nibble *)p;
|
||||
|
||||
/* increment the buffer pointer */
|
||||
*ptr++ = ((s->l >> 4) & 0x0f) + (s->h & 0xf0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define INB_NIBBLE_H MS_PARAM(2, 2, MS_TYP_PTR)
|
||||
#define INB_NIBBLE_L MS_PARAM(4, 2, MS_TYP_PTR)
|
||||
#define INB_NIBBLE_F MS_PARAM(5, 0, MS_TYP_FUN)
|
||||
#define INB_NIBBLE_P MS_PARAM(5, 1, MS_TYP_PTR)
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in NIBBLE mode
|
||||
* Retrieve the two nibbles and call the C function to generate the character
|
||||
* and store it in the buffer (see nibble_inbyte_hook())
|
||||
*/
|
||||
|
||||
#define DECLARE_NIBBLE_INBYTE_SUBMICROSEQ \
|
||||
struct ppb_microseq nibble_inbyte_submicroseq[] = { \
|
||||
/* loop: */ \
|
||||
MS_CASS( H_AUTO | H_SELIN | H_INIT | H_STROBE), \
|
||||
MS_DELAY(VP0_PULSE), \
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */),\
|
||||
MS_CASS(H_nAUTO | H_SELIN | H_INIT | H_STROBE), \
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */),\
|
||||
/* do a C call to format the received nibbles */ \
|
||||
MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */),\
|
||||
MS_DBRA(-7 /* loop */), \
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE), \
|
||||
MS_RET(0) \
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in PS2 mode
|
||||
*/
|
||||
static struct ppb_microseq ps2_inbyte_submicroseq[] = {
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL),
|
||||
MS_CASS(PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
MS_DBRA(-4 /* loop */),
|
||||
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes
|
||||
*/
|
||||
static struct ppb_microseq spp_outbyte_submicroseq[] = {
|
||||
|
||||
/* loop: */
|
||||
MS_RASSERT_P(1, MS_REG_DTR),
|
||||
MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_DELAY(VP0_PULSE),
|
||||
MS_DBRA(-5 /* loop */),
|
||||
|
||||
/* return from the put call */
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* EPP 1.7 microsequences, ptr and len set at runtime */
|
||||
static struct ppb_microseq epp17_outstr_body[] = {
|
||||
MS_CASS(H_AUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RASSERT_P(1, MS_REG_EPP_D),
|
||||
MS_BRSET(TIMEOUT, 3 /* error */), /* EPP timeout? */
|
||||
MS_DBRA(-3 /* loop */),
|
||||
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0),
|
||||
/* error: */
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(1)
|
||||
};
|
||||
|
||||
static struct ppb_microseq epp17_instr_body[] = {
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RFETCH_P(1, MS_REG_EPP_D, MS_FETCH_ALL),
|
||||
MS_BRSET(TIMEOUT, 3 /* error */), /* EPP timeout? */
|
||||
MS_DBRA(-3 /* loop */),
|
||||
|
||||
MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0),
|
||||
/* error: */
|
||||
MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(1)
|
||||
};
|
||||
|
||||
static struct ppb_microseq in_disk_mode[] = {
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
|
||||
MS_BRCLEAR(H_FLT, 3 /* error */),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_BRSET(H_FLT, 1 /* error */),
|
||||
|
||||
MS_RET(1),
|
||||
/* error: */
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
static int
|
||||
vpoio_disconnect(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret;
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
|
||||
return (ppb_release_bus(ppbus, vpo->vpo_dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* how : PPB_WAIT or PPB_DONTWAIT
|
||||
*/
|
||||
static int
|
||||
vpoio_connect(struct vpoio_data *vpo, int how)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, how))) {
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("%s: can't request bus!\n", __func__);
|
||||
#endif
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (PPB_IN_EPP_MODE(ppbus))
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret);
|
||||
else
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_reset()
|
||||
*
|
||||
* SCSI reset signal, the drive must be in disk mode
|
||||
*/
|
||||
static void
|
||||
vpoio_reset(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret;
|
||||
|
||||
struct ppb_microseq reset_microseq[] = {
|
||||
|
||||
#define INITIATOR MS_PARAM(0, 1, MS_TYP_INT)
|
||||
|
||||
MS_DASS(MS_UNKNOWN),
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_nINIT | H_STROBE),
|
||||
MS_DELAY(25),
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
ppb_MS_init_msq(reset_microseq, 1, INITIATOR, 1 << VP0_INITIATOR);
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, &ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_in_disk_mode()
|
||||
*/
|
||||
static int
|
||||
vpoio_in_disk_mode(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret;
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_detect()
|
||||
*
|
||||
* Detect and initialise the VP0 adapter.
|
||||
*/
|
||||
static int
|
||||
vpoio_detect(struct vpoio_data *vpo)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error, ret;
|
||||
|
||||
/* allocate the bus, then apply microsequences */
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT)))
|
||||
return (error);
|
||||
|
||||
/* Force disconnection */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
|
||||
|
||||
/* Try to enter EPP mode, then connect to the drive in EPP mode */
|
||||
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
|
||||
/* call manually the microseq instead of using the appropriate function
|
||||
* since we already requested the ppbus */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret);
|
||||
}
|
||||
|
||||
/* If EPP mode switch failed or ZIP connection in EPP mode failed,
|
||||
* try to connect in NIBBLE mode */
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
|
||||
/* The interface must be at least PS/2 or NIBBLE capable.
|
||||
* There is no way to know if the ZIP will work with
|
||||
* PS/2 mode since PS/2 and SPP both use the same connect
|
||||
* sequence. One must suppress PS/2 with boot flags if
|
||||
* PS/2 mode fails (see ppc(4)).
|
||||
*/
|
||||
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
|
||||
vpo->vpo_mode_found = VP0_MODE_PS2;
|
||||
} else {
|
||||
if (ppb_set_mode(ppbus, PPB_NIBBLE) == -1)
|
||||
goto error;
|
||||
|
||||
vpo->vpo_mode_found = VP0_MODE_NIBBLE;
|
||||
}
|
||||
|
||||
/* Can't know if the interface is capable of PS/2 yet */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
vpo->vpo_mode_found = VP0_MODE_UNDEFINED;
|
||||
if (bootverbose)
|
||||
device_printf(vpo->vpo_dev,
|
||||
"can't connect to the drive\n");
|
||||
|
||||
/* disconnect and release the bus */
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq,
|
||||
&ret);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
vpo->vpo_mode_found = VP0_MODE_EPP;
|
||||
}
|
||||
|
||||
/* send SCSI reset signal */
|
||||
vpoio_reset(vpo);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
|
||||
|
||||
/* ensure we are disconnected or daisy chained peripheral
|
||||
* may cause serious problem to the disk */
|
||||
if (vpoio_in_disk_mode(vpo)) {
|
||||
if (bootverbose)
|
||||
device_printf(vpo->vpo_dev,
|
||||
"can't disconnect from the drive\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ppb_release_bus(ppbus, vpo->vpo_dev);
|
||||
return (0);
|
||||
|
||||
error:
|
||||
ppb_release_bus(ppbus, vpo->vpo_dev);
|
||||
return (VP0_EINITFAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_outstr()
|
||||
*/
|
||||
static int
|
||||
vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer,
|
||||
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
|
||||
|
||||
ppb_ecp_sync(ppbus);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_instr()
|
||||
*/
|
||||
static int
|
||||
vpoio_instr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer,
|
||||
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
|
||||
|
||||
ppb_ecp_sync(ppbus);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static char
|
||||
vpoio_select(struct vpoio_data *vpo, int initiator, int target)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret;
|
||||
|
||||
struct ppb_microseq select_microseq[] = {
|
||||
|
||||
/* parameter list
|
||||
*/
|
||||
#define SELECT_TARGET MS_PARAM(0, 1, MS_TYP_INT)
|
||||
#define SELECT_INITIATOR MS_PARAM(3, 1, MS_TYP_INT)
|
||||
|
||||
/* send the select command to the drive */
|
||||
MS_DASS(MS_UNKNOWN),
|
||||
MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_DASS(MS_UNKNOWN),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_nINIT | H_STROBE),
|
||||
|
||||
/* now, wait until the drive is ready */
|
||||
MS_SET(VP0_SELTMO),
|
||||
/* loop: */ MS_BRSET(H_ACK, 2 /* ready */),
|
||||
MS_DBRA(-2 /* loop */),
|
||||
/* error: */ MS_RET(1),
|
||||
/* ready: */ MS_RET(0)
|
||||
};
|
||||
|
||||
/* initialize the select microsequence */
|
||||
ppb_MS_init_msq(select_microseq, 2,
|
||||
SELECT_TARGET, 1 << target,
|
||||
SELECT_INITIATOR, 1 << initiator);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret);
|
||||
|
||||
if (ret)
|
||||
return (VP0_ESELECT_TIMEOUT);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_wait()
|
||||
*
|
||||
* H_SELIN must be low.
|
||||
*
|
||||
* XXX should be ported to microseq
|
||||
*/
|
||||
static char
|
||||
vpoio_wait(struct vpoio_data *vpo, int tmo)
|
||||
{
|
||||
DECLARE_WAIT_MICROSEQUENCE;
|
||||
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int ret, err;
|
||||
|
||||
#if 0 /* broken */
|
||||
if (ppb_poll_device(ppbus, 150, nBUSY, nBUSY, PPB_INTR))
|
||||
return (0);
|
||||
|
||||
return (ppb_rstr(ppbus) & 0xf0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return some status information.
|
||||
* Semantics : 0xc0 = ZIP wants more data
|
||||
* 0xd0 = ZIP wants to send more data
|
||||
* 0xe0 = ZIP wants command
|
||||
* 0xf0 = end of transfer, ZIP is sending status
|
||||
*/
|
||||
|
||||
ppb_MS_init_msq(wait_microseq, 2,
|
||||
WAIT_RET, (void *)&ret,
|
||||
WAIT_TMO, tmo);
|
||||
|
||||
ppb_MS_microseq(ppbus, vpo->vpo_dev, wait_microseq, &err);
|
||||
|
||||
if (err)
|
||||
return (0); /* command timed out */
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_probe()
|
||||
*
|
||||
* Low level probe of vpo device
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_probe(device_t dev, struct vpoio_data *vpo)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* ppbus dependent initialisation */
|
||||
vpo->vpo_dev = dev;
|
||||
|
||||
/*
|
||||
* Initialize microsequence code
|
||||
*/
|
||||
INIT_TRIG_MICROSEQ;
|
||||
|
||||
/* now, try to initialise the drive */
|
||||
if ((error = vpoio_detect(vpo))) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_attach()
|
||||
*
|
||||
* Low level attachment of vpo device
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_attach(struct vpoio_data *vpo)
|
||||
{
|
||||
DECLARE_NIBBLE_INBYTE_SUBMICROSEQ;
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
int error = 0;
|
||||
|
||||
vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
|
||||
sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!vpo->vpo_nibble_inbyte_msq)
|
||||
return (ENXIO);
|
||||
|
||||
bcopy((void *)nibble_inbyte_submicroseq,
|
||||
(void *)vpo->vpo_nibble_inbyte_msq,
|
||||
sizeof(nibble_inbyte_submicroseq));
|
||||
|
||||
ppb_MS_init_msq(vpo->vpo_nibble_inbyte_msq, 4,
|
||||
INB_NIBBLE_H, (void *)&(vpo)->vpo_nibble.h,
|
||||
INB_NIBBLE_L, (void *)&(vpo)->vpo_nibble.l,
|
||||
INB_NIBBLE_F, nibble_inbyte_hook,
|
||||
INB_NIBBLE_P, (void *)&(vpo)->vpo_nibble);
|
||||
|
||||
/*
|
||||
* Initialize mode dependent in/out microsequences
|
||||
*/
|
||||
ppb_lock(ppbus);
|
||||
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT)))
|
||||
goto error;
|
||||
|
||||
/* ppbus sets automatically the last mode entered during detection */
|
||||
switch (vpo->vpo_mode_found) {
|
||||
case VP0_MODE_EPP:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr_body);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr_body);
|
||||
device_printf(vpo->vpo_dev, "EPP mode\n");
|
||||
break;
|
||||
case VP0_MODE_PS2:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
device_printf(vpo->vpo_dev, "PS2 mode\n");
|
||||
break;
|
||||
case VP0_MODE_NIBBLE:
|
||||
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
|
||||
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
device_printf(vpo->vpo_dev, "NIBBLE mode\n");
|
||||
break;
|
||||
default:
|
||||
panic("vpo: unknown mode %d", vpo->vpo_mode_found);
|
||||
}
|
||||
|
||||
ppb_release_bus(ppbus, vpo->vpo_dev);
|
||||
|
||||
error:
|
||||
ppb_unlock(ppbus);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_reset_bus()
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_reset_bus(struct vpoio_data *vpo)
|
||||
{
|
||||
/* first, connect to the drive */
|
||||
if (vpoio_connect(vpo, PPB_WAIT|PPB_INTR) || !vpoio_in_disk_mode(vpo)) {
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("%s: not in disk mode!\n", __func__);
|
||||
#endif
|
||||
/* release ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* reset the SCSI bus */
|
||||
vpoio_reset(vpo);
|
||||
|
||||
/* then disconnect */
|
||||
vpoio_disconnect(vpo);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_do_scsi()
|
||||
*
|
||||
* Send an SCSI command
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret)
|
||||
{
|
||||
device_t ppbus = device_get_parent(vpo->vpo_dev);
|
||||
char r;
|
||||
char l, h = 0;
|
||||
int len, error = 0;
|
||||
int k;
|
||||
|
||||
/*
|
||||
* enter disk state, allocate the ppbus
|
||||
*
|
||||
* XXX
|
||||
* Should we allow this call to be interruptible?
|
||||
* The only way to report the interruption is to return
|
||||
* EIO do upper SCSI code :^(
|
||||
*/
|
||||
if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))
|
||||
return (error);
|
||||
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
*ret = VP0_ECONNECT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((*ret = vpoio_select(vpo,host,target)))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Send the command ...
|
||||
*
|
||||
* set H_SELIN low for vpoio_wait().
|
||||
*/
|
||||
ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
for (k = 0; k < clen; k++) {
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
|
||||
*ret = VP0_ECMD_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
if (vpoio_outstr(vpo, &command[k], 1)) {
|
||||
*ret = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Completion ...
|
||||
*/
|
||||
|
||||
*count = 0;
|
||||
for (;;) {
|
||||
|
||||
if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
|
||||
*ret = VP0_ESTATUS_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* stop when the ZIP wants to send status */
|
||||
if (r == (char)0xf0)
|
||||
break;
|
||||
|
||||
if (*count >= blen) {
|
||||
*ret = VP0_EDATA_OVERFLOW;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* if in EPP mode or writing bytes, try to transfer a sector
|
||||
* otherwise, just send one byte
|
||||
*/
|
||||
if (PPB_IN_EPP_MODE(ppbus) || r == (char)0xc0)
|
||||
len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
|
||||
VP0_SECTOR_SIZE : 1;
|
||||
else
|
||||
len = 1;
|
||||
|
||||
/* ZIP wants to send data? */
|
||||
if (r == (char)0xc0)
|
||||
error = vpoio_outstr(vpo, &buffer[*count], len);
|
||||
else
|
||||
error = vpoio_instr(vpo, &buffer[*count], len);
|
||||
|
||||
if (error) {
|
||||
*ret = error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*count += len;
|
||||
}
|
||||
|
||||
if (vpoio_instr(vpo, &l, 1)) {
|
||||
*ret = VP0_EOTHER;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check if the ZIP wants to send more status */
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)
|
||||
if (vpoio_instr(vpo, &h, 1)) {
|
||||
*ret = VP0_EOTHER + 2;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*result = ((int) h << 8) | ((int) l & 0xff);
|
||||
|
||||
error:
|
||||
/* return to printer state, release the ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (0);
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
#ifndef __VP0IO_H
|
||||
#define __VP0IO_H
|
||||
|
||||
/*
|
||||
* The ZIP drive cannot act as an initiator.
|
||||
*/
|
||||
#define VP0_INITIATOR 0x7
|
||||
|
||||
#define VP0_ESELECT_TIMEOUT 1
|
||||
#define VP0_ECMD_TIMEOUT 2
|
||||
#define VP0_ECONNECT 3
|
||||
#define VP0_ESTATUS_TIMEOUT 4
|
||||
#define VP0_EDATA_OVERFLOW 5
|
||||
#define VP0_EDISCONNECT 6
|
||||
#define VP0_EPPDATA_TIMEOUT 7
|
||||
#define VP0_ENEGOCIATE 8
|
||||
#define VP0_ENOPORT 9
|
||||
#define VP0_EINITFAILED 10
|
||||
#define VP0_EINTR 12
|
||||
|
||||
#define VP0_EOTHER 13
|
||||
|
||||
#define VP0_OPENNINGS 1
|
||||
|
||||
/*
|
||||
* Data structure used during microsequence execution
|
||||
* when characters are received in nibble mode
|
||||
*/
|
||||
struct vpo_nibble {
|
||||
char h; /* most significant nibble */
|
||||
char l; /* less significant nibble */
|
||||
};
|
||||
|
||||
/* Mode found during initialisation */
|
||||
#define VP0_MODE_UNDEFINED 0x0
|
||||
#define VP0_MODE_NIBBLE 0x1
|
||||
#define VP0_MODE_PS2 0x2
|
||||
#define VP0_MODE_EPP 0x3
|
||||
|
||||
struct vpoio_data {
|
||||
int vpo_mode_found; /* Mode found during init */
|
||||
|
||||
struct vpo_nibble vpo_nibble;
|
||||
|
||||
/* each device must have its own nibble inbyte microsequence */
|
||||
struct ppb_microseq *vpo_nibble_inbyte_msq;
|
||||
|
||||
device_t vpo_dev;
|
||||
};
|
||||
|
||||
int vpoio_probe(device_t dev, struct vpoio_data *vpo);
|
||||
|
||||
int vpoio_attach(struct vpoio_data *vpo);
|
||||
int vpoio_reset_bus(struct vpoio_data *vpo);
|
||||
|
||||
int vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret);
|
||||
|
||||
int imm_probe(device_t dev, struct vpoio_data *vpo);
|
||||
|
||||
int imm_attach(struct vpoio_data *vpo);
|
||||
int imm_reset_bus(struct vpoio_data *vpo);
|
||||
|
||||
int imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret);
|
||||
|
||||
#endif
|
@ -372,7 +372,6 @@ SUBDIR= \
|
||||
${_vmd} \
|
||||
${_vmm} \
|
||||
${_vmware} \
|
||||
${_vpo} \
|
||||
vr \
|
||||
vte \
|
||||
${_wbwd} \
|
||||
@ -558,7 +557,6 @@ _hwpmc_mips74k= hwpmc_mips74k
|
||||
${MACHINE_CPUARCH} != "mips" && ${MACHINE_CPUARCH} != "powerpc" && \
|
||||
${MACHINE_CPUARCH} != "riscv"
|
||||
_syscons= syscons
|
||||
_vpo= vpo
|
||||
.endif
|
||||
|
||||
.if ${MACHINE_CPUARCH} != "mips"
|
||||
|
@ -1,10 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/ppbus
|
||||
|
||||
KMOD= vpo
|
||||
SRCS= bus_if.h device_if.h ppbus_if.h \
|
||||
opt_cam.h opt_scsi.h opt_vpo.h \
|
||||
immio.c vpo.c vpoio.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user