Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / disk / i386 / bs / bshw_pdma.c
1 /* $FreeBSD: src/sys/i386/isa/bs/bshw_pdma.c,v 1.6.6.1 2000/10/21 07:44:26 nyan Exp $ */
2 /*      $NecBSD: bshw_pdma.c,v 1.4 1997/10/31 17:43:39 honda Exp $      */
3 /*      $NetBSD$        */
4 /*
5  * [NetBSD for NEC PC98 series]
6  *  Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
7  *  All rights reserved.
8  * 
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. The name of the author may not be used to endorse or promote products
18  *     derived from this software without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1994, 1995, 1996 Naofumi HONDA.  All rights reserved.
34  */
35
36 #define LC_SMIT_TIMEOUT 2       /* 2 sec: timeout for a fifo status ready */
37
38 static BS_INLINE void bshw_lc_smit_start __P((struct bs_softc *, int, u_int));
39 static int bshw_lc_smit_fstat __P((struct bs_softc *, int, int));
40 static void bshw_lc_smit_stop __P((struct bs_softc *));
41
42 /*********************************************************
43  * SM FIFO (GENERIC)
44  *********************************************************/
45 void
46 bshw_smitabort(bsc)
47         struct bs_softc *bsc;
48 {
49         if (bsc->sc_hw->hw_flags & BSHW_SMFIFO)
50                 bshw_lc_smit_stop(bsc);
51
52         bshw_set_count(bsc, 0);
53         bsc->sc_flags &= ~BSSMITSTART;
54 }
55
56 void
57 bs_smit_xfer_end(ti)
58         struct targ_info *ti;
59 {
60         struct bs_softc *bsc = ti->ti_bsc;
61         struct sc_p *sp = &bsc->sc_p;
62         u_int count;
63         u_char *s;
64
65         bshw_lc_smit_stop(bsc);
66         bsc->sc_flags &= ~BSSMITSTART;
67
68         if (ti->ti_phase == DATAPHASE)
69         {
70                 count = bshw_get_count(bsc);
71                 if (count < (u_int) sp->datalen)
72                 {
73                         sp->data += (sp->datalen - count);
74                         sp->datalen = count;
75                         /* XXX:
76                          * strict double checks!
77                          * target   => wd33c93c transfer counts
78                          * wd33c93c => memory   transfer counts
79                          */
80                         if ((bsc->sc_dmadir & BSHW_READ) &&
81                              count != bsc->sm_tdatalen)
82                         {
83                                 s = "read count miss";
84                                 goto bad;
85                         }
86                         return;
87                 }
88                 else if (count == (u_int) sp->datalen)
89                 {
90                         return;
91                 }
92
93                 s = "strange count";
94         }
95         else
96                 s = "extra smit interrupt";
97
98 bad:
99         bs_printf(ti, "smit_xfer_end", s);
100         ti->ti_error |= BSDMAABNORMAL;
101 }
102
103 /*********************************************************
104  * LOGITEC's SMIT TRANSFER
105  *********************************************************/
106
107 #define BSHW_LC_FSET    0x36
108 #define BSHW_LC_FCTRL   0x44
109 #define FCTRL_EN        0x01
110 #define FCTRL_WRITE     0x02
111
112 #define SF_ABORT        0x08
113 #define SF_RDY          0x10
114
115 #define LC_FSZ          DEV_BSIZE
116 #define LC_SFSZ         0x0c
117 #define LC_REST         (LC_FSZ - LC_SFSZ)
118
119 static void
120 bshw_lc_smit_stop(bsc)
121         struct bs_softc *bsc;
122 {
123
124         write_wd33c93(bsc, BSHW_LC_FCTRL, 0);
125         BUS_IOW(cmd_port, CMDP_DMER);
126 }
127
128 static BS_INLINE void
129 bshw_lc_smit_start(bsc, count, direction)
130         struct bs_softc *bsc;
131         int count;
132         u_int direction;
133 {
134         u_int8_t pval, val = read_wd33c93(bsc, BSHW_LC_FSET);
135
136         bsc->sc_flags |= BSSMITSTART;
137         bshw_set_count(bsc, count);
138
139         pval = FCTRL_EN;
140         if ((direction & BSHW_READ) == 0)
141                 pval |= (val & 0xe0) | FCTRL_WRITE;
142         write_wd33c93(bsc, BSHW_LC_FCTRL, pval);
143         bshw_start_xfer(bsc);
144 }
145
146 static int
147 bshw_lc_smit_fstat(bsc, wc, read)
148         struct bs_softc *bsc;
149         int wc, read;
150 {
151         u_int8_t stat;
152
153 #define ALWAYS_ABORT
154 #ifdef  ALWAYS_ABORT
155         if (read == BSHW_READ)
156         {
157                 while (wc -- > 0)
158                 {
159                         BUS_IO_WEIGHT;
160                         stat = BUS_IOR(cmd_port);
161                         if (stat & SF_RDY)
162                                 return 0;
163                         if (stat & SF_ABORT)
164                                 return EIO;
165                 }
166         }
167         else
168         {
169 #endif  /* ALWAYS_ABORT */
170                 while (wc -- > 0)
171                 {
172                         BUS_IO_WEIGHT;
173                         stat = BUS_IOR(cmd_port);
174                         if (stat & SF_ABORT)
175                                 return EIO;
176                         if (stat & SF_RDY)
177                                 return 0;
178                 }
179 #ifdef  ALWAYS_ABORT
180         }
181 #endif  /* ALWAYS_ABORT */
182
183         bs_poll_timeout(bsc, "bshw_lc_smit");
184         return EIO;
185 }
186
187 void
188 bs_lc_smit_xfer(ti, direction)
189         struct targ_info *ti;
190         u_int direction;
191 {
192         struct bs_softc *bsc = ti->ti_bsc;
193         struct sc_p *sp = &bsc->sc_p;
194         int datalen, count, wc = LC_SMIT_TIMEOUT * 1024 * 1024;
195         u_int8_t *data;
196
197         sp->bufp = NULL;
198         sp->seglen = 0;
199         data = sp->data;
200         datalen = sp->datalen;
201
202         bsc->sc_dmadir = direction;
203         bshw_set_dma_trans(bsc, ti->ti_cfgflags);
204         bshw_lc_smit_start(bsc, sp->datalen, direction);
205
206         if (direction & BSHW_READ)
207         {
208                 do
209                 {
210                         if (bshw_lc_smit_fstat(bsc, wc, BSHW_READ))
211                                 break;
212
213                         count = (datalen > LC_FSZ ? LC_FSZ : datalen);
214 #ifdef  __FreeBSD__
215                         memcopy((u_int8_t *)ti->sm_offset, data, count);
216 #else   /* NetBSD */
217                         bus_space_read_region_4(bsc->sc_memt, bsc->sc_memh,
218                                 ti->sm_offset, (u_int32_t *) data, count >> 2);
219 #endif  /* NetBSD */
220                         data += count;
221                         datalen -= count;
222                 }
223                 while (datalen > 0);
224
225                 bsc->sm_tdatalen = datalen;
226         }
227         else
228         {
229                 do
230                 {
231                         if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
232                                 break;
233
234                         count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
235 #ifdef  __FreeBSD__
236                         memcopy(data, (u_int8_t *)ti->sm_offset, count);
237 #else   /* NetBSD */
238                         bus_space_write_region_4(bsc->sc_memt, bsc->sc_memh,
239                                 ti->sm_offset, (u_int32_t *) data, count >> 2);
240 #endif  /* NetBSD */
241                         data += count;
242                         datalen -= count;
243
244                         if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
245                                 break;
246
247                         count = (datalen > LC_REST ? LC_REST : datalen);
248 #ifdef  __FreeBSD__
249                         memcopy(data, (u_int8_t *)(ti->sm_offset + LC_SFSZ), count);
250 #else   /* NetBSD */
251                         bus_space_write_region_4(bsc->sc_memt, bsc->sc_memh,
252                                                  ti->sm_offset + LC_SFSZ, 
253                                                  (u_int32_t *) data, count >> 2);
254 #endif  /* NetBSD */
255                         data += count;
256                         datalen -= count;
257                 }
258                 while (datalen > 0);
259         }
260 }