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