/[gxemul]/upstream/0.4.4/src/devices/dev_wdsc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.4/src/devices/dev_wdsc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (show annotations)
Mon Oct 8 16:21:26 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 10033 byte(s)
0.4.4
1 /*
2 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_wdsc.c,v 1.34 2007/01/28 14:15:30 debug Exp $
29 *
30 * WDSC SCSI (WD33C93) controller.
31 * (For SGI-IP22. See sys/arch/sgimips/hpc/sbic* in NetBSD for details.)
32 *
33 * TODO: This device doesn't do much yet.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "cpu.h"
41 #include "devices.h"
42 #include "diskimage.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46
47 #include "wdsc_sbicreg.h"
48
49
50 struct wdsc_data {
51 int irq_nr;
52 int controller_nr;
53
54 int register_select;
55 unsigned char reg[DEV_WDSC_NREGS];
56
57 int irq_pending;
58
59 int buf_allocatedlen;
60 int buf_curptr;
61 unsigned char *buf;
62
63 int current_phase;
64
65 struct scsi_transfer *xfer;
66 };
67
68
69 DEVICE_TICK(wdsc)
70 {
71 /* struct wdsc_data *d = extra; */
72
73 fatal("TODO: legacy interrupt rewrite!\n");
74 abort();
75
76 // if (d->irq_pending)
77 // cpu_interrupt(cpu, d->irq_nr);
78 // else
79 // cpu_interrupt_ack(cpu, d->irq_nr);
80 }
81
82
83 /*
84 * dev_wdsc_regwrite():
85 *
86 * Handle writes to WDSC registers.
87 */
88 static void dev_wdsc_regwrite(struct cpu *cpu, struct wdsc_data *d, int idata)
89 {
90 d->reg[d->register_select] = idata & 0xff;
91
92 debug("[ wdsc: write to register %i", d->register_select);
93
94 switch (d->register_select) {
95
96 case SBIC_myid:
97 debug(" (myid): 0x%02x => ", (int)idata);
98 if (idata & SBIC_ID_FS_16_20)
99 debug("16-20MHz, ");
100 if (idata & SBIC_ID_FS_12_15)
101 debug("12-15MHz, ");
102 if (idata & SBIC_ID_RAF)
103 debug("RAF(?), ");
104 if (idata & SBIC_ID_EHP)
105 debug("Parity, ");
106 if (idata & SBIC_ID_EAF)
107 debug("EnableAdvancedFeatures, ");
108 debug("ID=%i", idata & SBIC_ID_MASK);
109 break;
110
111 case SBIC_control:
112 debug(" (control): 0x%02x =>", (int)idata);
113 if (idata & SBIC_CTL_DMA)
114 debug(" SingleByteDMA");
115 if (idata & SBIC_CTL_DBA_DMA)
116 debug(" DirectBufferAccess");
117 if (idata & SBIC_CTL_BURST_DMA)
118 debug(" BurstDMA");
119 if (idata & SBIC_CTL_HHP)
120 debug(" HaltOnParity");
121 if (idata & SBIC_CTL_EDI)
122 debug(" EndDisconIntr");
123 if (idata & SBIC_CTL_IDI)
124 debug(" IntermediateDisconIntr");
125 if (idata & SBIC_CTL_HA)
126 debug(" HaltOnATN");
127 if (idata & SBIC_CTL_HSP)
128 debug(" HaltOnParityError");
129
130 if (idata == SBIC_CTL_NO_DMA)
131 debug(" PIO");
132
133 /* TODO: When/how are interrupts acknowledged? */
134 if (idata & SBIC_CTL_EDI)
135 d->irq_pending = 0;
136
137 break;
138
139 case SBIC_count_hi:
140 debug(" (count_hi): 0x%02x", (int)idata);
141 break;
142
143 case SBIC_count_med:
144 debug(" (count_med): 0x%02x", (int)idata);
145 break;
146
147 case SBIC_count_lo:
148 debug(" (count_lo): 0x%02x", (int)idata);
149 break;
150
151 case SBIC_selid:
152 debug(" (selid): 0x%02x => ", (int)idata);
153
154 if (idata & SBIC_SID_SCC)
155 debug("SelectCommandChaining, ");
156 if (idata & SBIC_SID_FROM_SCSI)
157 debug("FromSCSI, ");
158 else
159 debug("ToSCSI, ");
160
161 debug("id %i", idata & SBIC_SID_IDMASK);
162 break;
163
164 case SBIC_rselid:
165 debug(" (rselid): 0x%02x => ", (int)idata);
166
167 if (idata & SBIC_RID_ER)
168 debug("EnableReselection, ");
169 if (idata & SBIC_RID_ES)
170 debug("EnableSelection, ");
171 if (idata & SBIC_RID_DSP)
172 debug("DisableSelectParity, ");
173 if (idata & SBIC_RID_SIV)
174 debug("SourceIDValid, ");
175
176 debug("id %i", idata & SBIC_RID_MASK);
177 break;
178
179 case SBIC_cmd:
180 debug(" (cmd): 0x%02x => ", (int)idata);
181
182 /* SBT = Single Byte Transfer */
183 if (idata & SBIC_CMD_SBT)
184 debug("SBT, ");
185
186 /* Handle commands: */
187 switch (idata & SBIC_CMD_MASK) {
188 case SBIC_CMD_RESET:
189 debug("RESET");
190 d->irq_pending = 1;
191 d->reg[SBIC_csr] = SBIC_CSR_RESET;
192 break;
193 case SBIC_CMD_ABORT:
194 debug("ABORT");
195 break;
196 case SBIC_CMD_SEL_ATN:
197 debug("SEL_ATN");
198 d->irq_pending = 1;
199 d->reg[SBIC_csr] = SBIC_CSR_SEL_TIMEO;
200 if (d->controller_nr == 0 && diskimage_exist(
201 cpu->machine, d->reg[SBIC_selid] &
202 SBIC_SID_IDMASK, DISKIMAGE_SCSI)) {
203 if (d->xfer != NULL)
204 scsi_transfer_free(d->xfer);
205 d->xfer = scsi_transfer_alloc();
206
207 /* According to NetBSD, we can go either to
208 SBIC_CSR_MIS_2 | CMD_PHASE, or
209 SBIC_CSR_MIS_2 | MESG_OUT_PHASE. */
210
211 d->reg[SBIC_csr] = SBIC_CSR_MIS_2 | CMD_PHASE;
212
213 d->current_phase = CMD_PHASE;
214 }
215 break;
216 case SBIC_CMD_XFER_INFO:
217 debug("XFER_INFO");
218
219 if (d->buf != NULL)
220 free(d->buf);
221
222 d->buf_allocatedlen = (d->reg[SBIC_count_hi] << 16)
223 + (d->reg[SBIC_count_med] << 8) +
224 d->reg[SBIC_count_lo];
225
226 d->buf = malloc(d->buf_allocatedlen);
227 if (d->buf == NULL) {
228 fprintf(stderr, "out of memory in wdsc\n");
229 exit(1);
230 }
231
232 d->buf_curptr = 0;
233 d->irq_pending = 0;
234 break;
235 default:
236 debug("unimplemented command");
237 }
238 break;
239
240 case SBIC_data:
241 debug(" (data): 0x%02x", (int)idata);
242
243 switch (d->reg[SBIC_cmd] & ~SBIC_CMD_SBT) {
244 case SBIC_CMD_XFER_INFO:
245 if (d->buf == NULL || d->buf_curptr >=
246 d->buf_allocatedlen) {
247 fprintf(stderr, "fatal error in wdsc\n");
248 exit(1);
249 }
250
251 d->buf[d->buf_curptr++] = idata;
252
253 if (d->buf_curptr >= d->buf_allocatedlen) {
254 int res;
255
256 /*
257 * Transfer buf to/from the SCSI unit:
258 */
259
260 switch (d->current_phase) {
261 case CMD_PHASE:
262 scsi_transfer_allocbuf(
263 &d->xfer->cmd_len, &d->xfer->cmd,
264 d->buf_allocatedlen, 1);
265 memcpy(d->xfer->cmd, d->buf,
266 d->buf_allocatedlen);
267 break;
268 default:
269 fatal("wdsc: unimplemented phase %i!\n",
270 d->current_phase);
271 }
272
273 res = diskimage_scsicommand(cpu,
274 d->reg[SBIC_selid] & SBIC_SID_IDMASK,
275 DISKIMAGE_SCSI, d->xfer);
276 debug("{ res = %i }", res);
277
278 d->irq_pending = 1;
279
280 if (res == 2)
281 d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
282 DATA_OUT_PHASE;
283 else
284 d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
285 DATA_IN_PHASE;
286
287 /* status phase? msg in and msg out? */
288 }
289 break;
290 default:
291 fatal("[ wdsc: don't know how to handle data for "
292 "cmd = 0x%02x ]\n", d->reg[SBIC_cmd]);
293 }
294
295 break;
296
297 default:
298 debug(" (TODO): 0x%02x", (int)idata);
299 }
300
301 debug(" ]\n");
302
303 /* After writing to a register, advance to the next: */
304 d->register_select ++;
305 }
306
307
308 /*
309 * dev_wdsc_access():
310 */
311 DEVICE_ACCESS(wdsc)
312 {
313 size_t i;
314 struct wdsc_data *d = extra;
315 uint64_t idata = 0, odata = 0;
316
317 if (writeflag == MEM_WRITE)
318 idata = memory_readmax64(cpu, data, len);
319
320 /*
321 * All registers on the WDSC seem to be accessed by writing the
322 * register number to one address (SBIC_ADDR), and then reading/
323 * writing another address (SBIC_VAL).
324 *
325 * On SGI-IP22, these are at offset 3 and 7, respectively.
326 *
327 * TODO: If this device is to be used by other machine types, then
328 * this needs to be conditionalized.
329 */
330 relative_addr = (relative_addr - 3) / 4;
331
332 switch (relative_addr) {
333
334 case SBIC_ADDR:
335 /*
336 * Reading the combined ADDR/ASR returns the Status
337 * Register, writing selects which register to access
338 * via SBIC_VAL.
339 */
340 if (writeflag == MEM_READ) {
341 odata = SBIC_ASR_DBR;
342 if (d->irq_pending)
343 odata |= SBIC_ASR_INT;
344
345 debug("[ wdsc: read from Status Register: %02x ]\n",
346 (int)odata);
347 } else {
348 d->register_select = idata & (DEV_WDSC_NREGS - 1);
349 }
350 break;
351
352 case SBIC_VAL:
353 if (writeflag == MEM_READ) {
354 odata = d->reg[d->register_select];
355
356 if (d->register_select == SBIC_csr) {
357 /* TODO: when should interrupts actually be
358 ack:ed? */
359 d->irq_pending = 0;
360 }
361
362 debug("[ wdsc: read from register %i: 0x%02x ]\n",
363 d->register_select, (int)odata);
364 } else {
365 dev_wdsc_regwrite(cpu, d, idata & 0xff);
366 }
367 break;
368
369 default:
370 /* These should never occur: */
371 if (writeflag==MEM_READ) {
372 fatal("[ wdsc: read from 0x%x:", (int)relative_addr);
373 for (i=0; i<len; i++)
374 fatal(" %02x", data[i]);
375 fatal(" (len=%i) ]\n", len);
376 } else {
377 fatal("[ wdsc: write to 0x%x:", (int)relative_addr);
378 for (i=0; i<len; i++)
379 fatal(" %02x", data[i]);
380 fatal(" (len=%i) ]\n", len);
381 }
382 }
383
384 if (writeflag == MEM_READ)
385 memory_writemax64(cpu, data, len, odata);
386
387 dev_wdsc_tick(cpu, extra);
388
389 return 1;
390 }
391
392
393 /*
394 * dev_wdsc_init():
395 */
396 void dev_wdsc_init(struct machine *machine, struct memory *mem,
397 uint64_t baseaddr, int controller_nr, int irq_nr)
398 {
399 struct wdsc_data *d;
400
401 d = malloc(sizeof(struct wdsc_data));
402 if (d == NULL) {
403 fprintf(stderr, "out of memory\n");
404 exit(1);
405 }
406 memset(d, 0, sizeof(struct wdsc_data));
407 d->irq_nr = irq_nr;
408 d->controller_nr = controller_nr;
409
410 memory_device_register(mem, "wdsc", baseaddr, DEV_WDSC_LENGTH,
411 dev_wdsc_access, d, DM_DEFAULT, NULL);
412
413 machine_add_tickfunction(machine, dev_wdsc_tick, d, 14, 0.0);
414 }
415

  ViewVC Help
Powered by ViewVC 1.1.26