Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / disk / i386 / bs / bshw.c
1 /*      $NecBSD: bshw.c,v 1.1 1997/07/18 09:19:03 kmatsuda Exp $        */
2 /*      $NetBSD$        */
3 /*
4  * [NetBSD for NEC PC98 series]
5  *  Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
6  *  All rights reserved.
7  * 
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *  1. Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *  2. Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *  3. The name of the author may not be used to endorse or promote products
17  *     derived from this software without specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * Copyright (c) 1994, 1995, 1996 Naofumi HONDA.  All rights reserved.
33  *
34  * $FreeBSD: src/sys/i386/isa/bs/bshw.c,v 1.7.2.1 2001/07/26 02:32:18 nyan Exp $
35  */
36
37 #ifdef  __NetBSD__
38 #include <dev/isa/isadmareg.h>
39 #include <i386/Cbus/dev/bs/bsif.h>
40 #include <i386/Cbus/dev/bs/bshw.lst>
41 #endif
42 #ifdef  __FreeBSD__
43 #include "opt_pc98.h"
44 #include <i386/isa/ic/i8237.h>
45 #include <i386/isa/bs/bsif.h>
46 #include <i386/isa/bs/bshw.lst>
47 #include <machine/clock.h>
48 #include <sys/cons.h>
49 #endif
50
51 static struct bs_softc *gbsc;
52
53 /**************************************************
54  * DECLARATION
55  **************************************************/
56 static void bshw_force_bsmode __P((struct bs_softc *));
57
58 /**************************************************
59  * STATIC VAL
60  **************************************************/
61 static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };
62
63 /**************************************************
64  * SCSI CMD BRANCH
65  **************************************************/
66 #define RS      (BSSAT | BSSMIT | BSLINK | BSREAD)
67 #define WS      (BSSAT | BSSMIT | BSLINK)
68 #define EOK     (BSERROROK)
69
70 u_int8_t bshw_cmd[256] = {
71 /*   0  1   2   3   4   5   6   7   8   9   A   B   C   E   D   F */
72 /*0*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,RS ,0  ,WS ,0  ,0  ,0  ,0  ,0  ,
73 /*1*/0  ,0  ,EOK,0  ,0  ,0  ,0  ,0  ,0  ,0  ,EOK,0  ,0  ,0  ,0  ,0  ,
74 /*2*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,RS ,0  ,WS ,0  ,0  ,0  ,0  ,0  ,
75 /*3*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
76 /*4*/0  ,0  ,EOK,EOK,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
77 /*5*/0  ,0  ,0  ,0  ,EOK,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
78 /*6*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
79 /*7*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
80 /*8*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
81 /*9*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
82 /*A*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
83 /*B*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
84 /*C*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
85 /*D*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
86 /*E*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
87 /*F*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
88 };
89
90 #undef  RS
91 #undef  WS
92 #undef  EOK
93
94 /**********************************************
95  * init
96  **********************************************/
97 static void
98 bshw_force_bsmode(bsc)
99         struct bs_softc *bsc;
100 {
101
102         if (bsc->sc_flags & BSBSMODE)
103                 return;
104         bsc->sc_flags |= BSBSMODE;
105
106         /*
107          * If you have memory over 16M, some stupid boards always force to
108          * use the io polling mode. Check such a case and change mode into
109          * bus master DMA. However this depends heavily on the board's
110          * specifications!
111          */
112
113         if (bsc->sc_hw->dma_init && ((*bsc->sc_hw->dma_init)(bsc)))
114                 printf("%s change mode using external DMA (%x)\n",
115                     bsc->sc_dvname, (u_int)read_wd33c93(bsc, 0x37));
116 }
117
118 #define RESET_DEFAULT   2000
119
120 int
121 bshw_chip_reset(bsc)
122         struct bs_softc *bsc;
123 {
124         int ct;
125         u_int8_t aux;
126
127         bshw_lock(bsc);
128
129         bshw_abort_cmd(bsc);
130         delay(10000);
131
132         bshw_get_auxstat(bsc);
133         bshw_get_busstat(bsc);
134
135         write_wd33c93(bsc, wd3s_oid, IDR_EHP | bsc->sc_cspeed | bsc->sc_hostid);
136         write_wd33c93(bsc, wd3s_cmd, WD3S_RESET);
137
138         for (ct = RESET_DEFAULT; ct > 0; ct--)
139         {
140                 aux = bshw_get_auxstat(bsc);
141                 if (aux != 0xff && (aux & STR_INT))
142                 {
143                         if (bshw_get_busstat(bsc) == 0)
144                                 break;
145
146                         write_wd33c93(bsc, wd3s_cmd, WD3S_RESET);
147                 }
148                 delay(1);
149         }
150
151         if (ct == 0)
152         {
153                 bshw_unlock(bsc);
154                 return ENXIO;
155         }
156
157         bshw_force_bsmode(bsc);
158
159         write_wd33c93(bsc, wd3s_tout, BSHW_SEL_TIMEOUT);
160         write_wd33c93(bsc, wd3s_sid, SIDR_RESEL);
161         bsc->sc_flags |= BSDMATRANSFER;
162         write_wd33c93(bsc, wd3s_ctrl, CR_DEFAULT);
163         write_wd33c93(bsc, wd3s_synch, 0);
164
165         bshw_get_auxstat(bsc);
166         bsc->sc_busstat = bshw_get_busstat(bsc);
167         bshw_unlock(bsc);
168
169         return 0;
170 }
171
172 /* scsi bus hard reset */
173 #define TWIDDLEWAIT     10000
174 static int tw_pos;
175 static char tw_chars[] = "|/-\\";
176
177 /* this is some jokes */
178 static void
179 twiddle_wait(void)
180 {
181
182         cnputc('\b');
183         cnputc(tw_chars[tw_pos++]);
184         tw_pos %= (sizeof(tw_chars) - 1);
185         delay(TWIDDLEWAIT);
186 }
187
188 static void bshw_set_vsp __P((struct bs_softc *, u_int, u_int8_t));
189
190 static void
191 bshw_set_vsp(bsc, chan, spva)
192         struct bs_softc *bsc;
193         u_int chan;
194         u_int8_t spva;
195 {
196         struct bshw *hw = bsc->sc_hw;
197
198         if (hw->sregaddr == 0)
199                 return;
200
201         write_wd33c93(bsc, hw->sregaddr + chan, spva);
202         if (hw->hw_flags & BSHW_DOUBLE_DMACHAN)
203                 write_wd33c93(bsc, hw->sregaddr + chan + 8, spva);
204 }
205
206 void
207 bshw_bus_reset(bsc)
208         struct bs_softc *bsc;
209 {
210         struct targ_info *ti;
211         int i, lpc;
212
213         if (bsc->sc_RSTdelay == 0)
214                 bsc->sc_RSTdelay = 6 * 1000 * 1000;
215         else
216         {
217                 /* XXX:
218                  * second time reset will be requested by hardware failuer.
219                  */
220                 bsc->sc_RSTdelay = 12 * 1000 * 1000;
221         }
222
223         bshw_lock(bsc);
224         write_wd33c93(bsc, wd3s_mbank, (bsc->sc_membank | MBR_RST) & ~MBR_IEN);
225         delay(500000);
226         write_wd33c93(bsc, wd3s_mbank, (bsc->sc_membank) & ~MBR_IEN);
227         bshw_unlock(bsc);
228
229         for (lpc = 0; lpc < 2; lpc ++)
230         {
231                 cnputc(' ');
232                 for (i = 0; i <= bsc->sc_RSTdelay / TWIDDLEWAIT; i++)
233                         twiddle_wait();
234                 cnputc('\b');
235
236                 (void) read_wd33c93(bsc, wd3s_auxc);
237
238                 delay(10000);
239
240                 if ((read_wd33c93(bsc, wd3s_auxc) & AUXCR_RRST) == 0)
241                         break;
242
243                 printf("\nreset state still continue, wait ...");
244         }
245
246         for (i = 0; i < NTARGETS; i++)
247         {
248                 if ((ti = bsc->sc_ti[i]) != NULL)
249                 {
250                         ti->ti_sync = 0;
251                         bshw_set_vsp(bsc, i, 0);
252                 }
253         }
254 }
255
256 /* probe */
257 int
258 bshw_board_probe(bsc, drq, irq)
259         struct bs_softc *bsc;
260         u_int *drq;
261         u_int *irq;
262 {
263
264         gbsc = bsc;
265 #ifdef  SHOW_PORT
266         bshw_print_port(bsc);
267 #endif  /* SHOW_PORT */
268
269         bsc->sc_hostid = (read_wd33c93(bsc, wd3s_auxc) & AUXCR_HIDM);
270
271         if ((*irq) == IRQUNK)
272                 *irq = irq_tbl[(read_wd33c93(bsc, wd3s_auxc) >> 3) & 7];
273
274         if ((*drq) == DRQUNK)
275                 *drq = BUS_IOR(cmd_port) & 3;
276
277         bsc->sc_dmachan = *drq;
278         bsc->sc_irq = (*irq);
279
280         bsc->sc_membank = read_wd33c93(bsc, wd3s_mbank);
281         bsc->sc_membank &= ~MBR_RST;
282         bsc->sc_membank |= MBR_IEN;
283
284         bsc->sc_cspeed = (read_wd33c93(bsc, wd3s_oid) & (~IDR_IDM));
285         switch (BSC_CHIP_CLOCK(bsc->sc_cfgflags))
286         {
287         case 0:
288                 break;
289
290         case 1:
291                 bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_16_20);
292                 break;
293
294         case 2:
295                 bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_16_20);
296                 bsc->sc_cspeed |= IDR_FS_12_15;
297                 break;
298
299         case 3:
300                 bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_16_20);
301                 bsc->sc_cspeed |= IDR_FS_16_20;
302                 break;
303         }
304
305         /* XXX: host id fixed(7) */
306         bsc->sc_hostid = 7;
307
308         if (bshw_chip_reset(bsc))
309                 return ENXIO;
310
311         return 0;
312 }
313
314 /*
315  * XXX:
316  * Assume the board clock rate must be 20Mhz (always satisfied, maybe)!
317  * Only 10M/s 6.6M/s 5.0M/s 3.3M/s for synchronus transfer speed set.
318  */
319 #define ILLEGAL_SYNCH
320 #ifdef  ILLEGAL_SYNCH
321 /*  A  10    6.6   5.0   4.0   3.3   2.8   2.5   2.0  M/s */
322 /*  X  100   150   200   250   300   350   400   500  ns  */
323 static u_int bshw_scsi_period[] =
324    {0, 25,   37,   50,   62,   75,   87,   100,  125};
325 static u_int8_t bshw_chip_pval[] =
326    {0, 0xa0, 0xb0, 0x20, 0xd0, 0x30, 0xf0, 0x40, 0x50};
327 #else   /* !ILLEGAL_SYNCH */
328 /*  A  10    6.6   5.0   3.3   2.5 M/s */
329 /*  X  100   150   200   300   400 ns  */
330 static u_int bshw_scsi_period[] =
331    {0, 25,   37,   50,   75,   100};
332 static u_int8_t bshw_chip_pval[] =
333    {0, 0xa0, 0xb0, 0x20, 0x30, 0x40};
334 #endif  /* !ILLEGAL_SYNCH */
335
336 void
337 bshw_adj_syncdata(sdp)
338         struct syncdata *sdp;
339 {
340         int i;
341
342         if (sdp->offset == 0 || sdp->period < 25 || sdp->period > 100)
343                 sdp->offset = sdp->period = 0;
344         else
345         {
346                 for (i = 0; sdp->period > bshw_scsi_period[i] + 2; i ++)
347                         ;
348                 sdp->period = bshw_scsi_period[i];
349         }
350 }
351
352 void
353 bshw_set_synchronous(bsc, ti)
354         struct bs_softc *bsc;
355         struct targ_info *ti;
356 {
357         struct syncdata sd;
358         int i;
359
360         sd = ti->ti_syncnow;
361         bshw_adj_syncdata(&sd);
362         for (i = 0; sd.period != bshw_scsi_period[i]; i++)
363                 ;
364
365         ti->ti_sync = ((sd.offset & 0x0f) | bshw_chip_pval[i]);
366         bshw_set_vsp(bsc, ti->ti_id, ti->ti_sync);
367
368         if (bsc->sc_nexus == ti)
369                 bshw_set_sync_reg(bsc, ti->ti_sync);
370 }
371
372 /* ctrl reg */
373 void
374 bshw_setup_ctrl_reg(bsc, flags)
375         struct bs_softc *bsc;
376         u_int flags;
377 {
378         u_int8_t regval;
379
380         regval = (flags & BS_SCSI_NOPARITY) ? CR_DEFAULT : CR_DEFAULT_HP;
381         if (bsc->sc_flags & BSDMATRANSFER)
382                 regval |= CR_DMA;
383         write_wd33c93(bsc, wd3s_ctrl, regval);
384 }
385
386 /* sat command */
387 void
388 bshw_issue_satcmd(bsc, cb, link)
389         struct bs_softc *bsc;
390         struct bsccb *cb;
391         int link;
392 {
393         int i;
394
395         BUS_IOW(addr_port, wd3s_cdb);
396         for (i = 0; i < cb->cmdlen - 1; i++)
397                 BUS_IOW(ctrl_port, cb->cmd[i]);
398         BUS_IOW(ctrl_port, cb->cmd[i] | (link ? 1 : 0));
399 }
400
401 /* lock */
402 void
403 bshw_lock(bsc)
404         struct bs_softc *bsc;
405 {
406
407         bsc->sc_hwlock++;
408         write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank & (~MBR_IEN));
409 }
410
411 void
412 bshw_unlock(bsc)
413         struct bs_softc *bsc;
414 {
415
416         if ((--bsc->sc_hwlock) <= 0)
417                 write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank);
418 }
419
420 /**********************************************
421  * DMA OPERATIONS
422  **********************************************/
423 #ifdef  __NetBSD__
424 #include <i386/Cbus/dev/bs/bshw_dma.c>
425 #include <i386/Cbus/dev/bs/bshw_pdma.c>
426 #endif
427 #ifdef  __FreeBSD__
428 #include <i386/isa/bs/bshw_dma.c>
429 #include <i386/isa/bs/bshw_pdma.c>
430 #endif
431
432 /**********************************************
433  * DEBUG
434  **********************************************/
435 /* misc */
436 void
437 bshw_print_port(bsc)
438         struct bs_softc * bsc;
439 {
440         int i, j;
441         int port = 0x0;
442
443         if (bsc == NULL)
444                 bsc = gbsc;
445
446         printf("\n");
447         for (j = 0; j <= 0x70; j += 0x10)
448         {
449                 printf("port %x: ", port);
450                 for (i = 0; i < 0x10; i++)
451                         printf("%x ", (u_int) read_wd33c93(bsc, port++));
452                 printf("\n");
453         }
454 }