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