remove __P() from this directory
[dragonfly.git] / sys / dev / disk / i386 / bs / bshw.c
CommitLineData
984263bc
MD
1/* $NecBSD: bshw.c,v 1.1 1997/07/18 09:19:03 kmatsuda Exp $ */
2/* $NetBSD$ */
38e94a25 3/* $DragonFly: src/sys/dev/disk/i386/bs/Attic/bshw.c,v 1.4 2003/08/27 10:35:16 rob Exp $ */
984263bc
MD
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 $
38e94a25 36 * $DragonFly: src/sys/dev/disk/i386/bs/Attic/bshw.c,v 1.4 2003/08/27 10:35:16 rob Exp $
984263bc
MD
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#ifdef __FreeBSD__
45#include "opt_pc98.h"
46#include <i386/isa/ic/i8237.h>
1f2de5d4
MD
47#include "bsif.h"
48#include "bshw.lst"
984263bc
MD
49#include <machine/clock.h>
50#include <sys/cons.h>
51#endif
52
53static struct bs_softc *gbsc;
54
55/**************************************************
56 * DECLARATION
57 **************************************************/
38e94a25 58static void bshw_force_bsmode (struct bs_softc *);
984263bc
MD
59
60/**************************************************
61 * STATIC VAL
62 **************************************************/
63static 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
72u_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 **********************************************/
99static void
100bshw_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
122int
123bshw_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
176static int tw_pos;
177static char tw_chars[] = "|/-\\";
178
179/* this is some jokes */
180static void
181twiddle_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
38e94a25 190static void bshw_set_vsp (struct bs_softc *, u_int, u_int8_t);
984263bc
MD
191
192static void
193bshw_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
208void
209bshw_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 */
259int
260bshw_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 */
325static u_int bshw_scsi_period[] =
326 {0, 25, 37, 50, 62, 75, 87, 100, 125};
327static 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 */
332static u_int bshw_scsi_period[] =
333 {0, 25, 37, 50, 75, 100};
334static u_int8_t bshw_chip_pval[] =
335 {0, 0xa0, 0xb0, 0x20, 0x30, 0x40};
336#endif /* !ILLEGAL_SYNCH */
337
338void
339bshw_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
354void
355bshw_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 */
375void
376bshw_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 */
389void
390bshw_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 */
404void
405bshw_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
413void
414bshw_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#ifdef __FreeBSD__
1f2de5d4
MD
430#include "bshw_dma.c"
431#include "bshw_pdma.c"
984263bc
MD
432#endif
433
434/**********************************************
435 * DEBUG
436 **********************************************/
437/* misc */
438void
439bshw_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}