/[gxemul]/upstream/0.3.1/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.3.1/devices/dev_wdsc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 10100 byte(s)
0.3.1
1 /*
2 * Copyright (C) 2004-2005 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.24 2005/02/21 07:18:09 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 "console.h"
41 #include "cpu.h"
42 #include "devices.h"
43 #include "diskimage.h"
44 #include "machine.h"
45 #include "memory.h"
46 #include "misc.h"
47
48 #include "wdsc_sbicreg.h"
49
50
51 struct wdsc_data {
52 int irq_nr;
53 int controller_nr;
54
55 int register_select;
56 unsigned char reg[DEV_WDSC_NREGS];
57
58 int irq_pending;
59
60 int buf_allocatedlen;
61 int buf_curptr;
62 unsigned char *buf;
63
64 int current_phase;
65
66 struct scsi_transfer *xfer;
67 };
68
69
70 /*
71 * dev_wdsc_tick():
72 */
73 void dev_wdsc_tick(struct cpu *cpu, void *extra)
74 {
75 struct wdsc_data *d = extra;
76
77 if (d->irq_pending)
78 cpu_interrupt(cpu, d->irq_nr);
79 else
80 cpu_interrupt_ack(cpu, d->irq_nr);
81 }
82
83
84 /*
85 * dev_wdsc_regwrite():
86 *
87 * Handle writes to WDSC registers.
88 */
89 static void dev_wdsc_regwrite(struct cpu *cpu, struct wdsc_data *d, int idata)
90 {
91 d->reg[d->register_select] = idata & 0xff;
92
93 debug("[ wdsc: write to register %i", d->register_select);
94
95 switch (d->register_select) {
96
97 case SBIC_myid:
98 debug(" (myid): 0x%02x => ", (int)idata);
99 if (idata & SBIC_ID_FS_16_20)
100 debug("16-20MHz, ");
101 if (idata & SBIC_ID_FS_12_15)
102 debug("12-15MHz, ");
103 if (idata & SBIC_ID_RAF)
104 debug("RAF(?), ");
105 if (idata & SBIC_ID_EHP)
106 debug("Parity, ");
107 if (idata & SBIC_ID_EAF)
108 debug("EnableAdvancedFeatures, ");
109 debug("ID=%i", idata & SBIC_ID_MASK);
110 break;
111
112 case SBIC_control:
113 debug(" (control): 0x%02x =>", (int)idata);
114 if (idata & SBIC_CTL_DMA)
115 debug(" SingleByteDMA");
116 if (idata & SBIC_CTL_DBA_DMA)
117 debug(" DirectBufferAccess");
118 if (idata & SBIC_CTL_BURST_DMA)
119 debug(" BurstDMA");
120 if (idata & SBIC_CTL_HHP)
121 debug(" HaltOnParity");
122 if (idata & SBIC_CTL_EDI)
123 debug(" EndDisconIntr");
124 if (idata & SBIC_CTL_IDI)
125 debug(" IntermediateDisconIntr");
126 if (idata & SBIC_CTL_HA)
127 debug(" HaltOnATN");
128 if (idata & SBIC_CTL_HSP)
129 debug(" HaltOnParityError");
130
131 if (idata == SBIC_CTL_NO_DMA)
132 debug(" PIO");
133
134 /* TODO: When/how are interrupts acknowledged? */
135 if (idata & SBIC_CTL_EDI)
136 d->irq_pending = 0;
137
138 break;
139
140 case SBIC_count_hi:
141 debug(" (count_hi): 0x%02x", (int)idata);
142 break;
143
144 case SBIC_count_med:
145 debug(" (count_med): 0x%02x", (int)idata);
146 break;
147
148 case SBIC_count_lo:
149 debug(" (count_lo): 0x%02x", (int)idata);
150 break;
151
152 case SBIC_selid:
153 debug(" (selid): 0x%02x => ", (int)idata);
154
155 if (idata & SBIC_SID_SCC)
156 debug("SelectCommandChaining, ");
157 if (idata & SBIC_SID_FROM_SCSI)
158 debug("FromSCSI, ");
159 else
160 debug("ToSCSI, ");
161
162 debug("id %i", idata & SBIC_SID_IDMASK);
163 break;
164
165 case SBIC_rselid:
166 debug(" (rselid): 0x%02x => ", (int)idata);
167
168 if (idata & SBIC_RID_ER)
169 debug("EnableReselection, ");
170 if (idata & SBIC_RID_ES)
171 debug("EnableSelection, ");
172 if (idata & SBIC_RID_DSP)
173 debug("DisableSelectParity, ");
174 if (idata & SBIC_RID_SIV)
175 debug("SourceIDValid, ");
176
177 debug("id %i", idata & SBIC_RID_MASK);
178 break;
179
180 case SBIC_cmd:
181 debug(" (cmd): 0x%02x => ", (int)idata);
182
183 /* SBT = Single Byte Transfer */
184 if (idata & SBIC_CMD_SBT)
185 debug("SBT, ");
186
187 /* Handle commands: */
188 switch (idata & SBIC_CMD_MASK) {
189 case SBIC_CMD_RESET:
190 debug("RESET");
191 d->irq_pending = 1;
192 d->reg[SBIC_csr] = SBIC_CSR_RESET;
193 break;
194 case SBIC_CMD_ABORT:
195 debug("ABORT");
196 break;
197 case SBIC_CMD_SEL_ATN:
198 debug("SEL_ATN");
199 d->irq_pending = 1;
200 d->reg[SBIC_csr] = SBIC_CSR_SEL_TIMEO;
201 if (d->controller_nr == 0 && diskimage_exist(
202 cpu->machine, d->reg[SBIC_selid] &
203 SBIC_SID_IDMASK)) {
204 if (d->xfer != NULL)
205 scsi_transfer_free(d->xfer);
206 d->xfer = scsi_transfer_alloc();
207
208 /* According to NetBSD, we can go either to
209 SBIC_CSR_MIS_2 | CMD_PHASE, or
210 SBIC_CSR_MIS_2 | MESG_OUT_PHASE. */
211
212 d->reg[SBIC_csr] = SBIC_CSR_MIS_2 | CMD_PHASE;
213
214 d->current_phase = CMD_PHASE;
215 }
216 break;
217 case SBIC_CMD_XFER_INFO:
218 debug("XFER_INFO");
219
220 if (d->buf != NULL)
221 free(d->buf);
222
223 d->buf_allocatedlen = (d->reg[SBIC_count_hi] << 16)
224 + (d->reg[SBIC_count_med] << 8) +
225 d->reg[SBIC_count_lo];
226
227 d->buf = malloc(d->buf_allocatedlen);
228 if (d->buf == NULL) {
229 fprintf(stderr, "out of memory in wdsc\n");
230 exit(1);
231 }
232
233 d->buf_curptr = 0;
234 d->irq_pending = 0;
235 break;
236 default:
237 debug("unimplemented command");
238 }
239 break;
240
241 case SBIC_data:
242 debug(" (data): 0x%02x", (int)idata);
243
244 switch (d->reg[SBIC_cmd] & ~SBIC_CMD_SBT) {
245 case SBIC_CMD_XFER_INFO:
246 if (d->buf == NULL || d->buf_curptr >=
247 d->buf_allocatedlen) {
248 fprintf(stderr, "fatal error in wdsc\n");
249 exit(1);
250 }
251
252 d->buf[d->buf_curptr++] = idata;
253
254 if (d->buf_curptr >= d->buf_allocatedlen) {
255 int res;
256
257 /*
258 * Transfer buf to/from the SCSI unit:
259 */
260
261 switch (d->current_phase) {
262 case CMD_PHASE:
263 scsi_transfer_allocbuf(
264 &d->xfer->cmd_len, &d->xfer->cmd,
265 d->buf_allocatedlen, 1);
266 memcpy(d->xfer->cmd, d->buf,
267 d->buf_allocatedlen);
268 break;
269 default:
270 fatal("wdsc: unimplemented phase %i!\n",
271 d->current_phase);
272 }
273
274 res = diskimage_scsicommand(cpu,
275 d->reg[SBIC_selid] & SBIC_SID_IDMASK,
276 d->xfer);
277 debug("{ res = %i }", res);
278
279 d->irq_pending = 1;
280
281 if (res == 2)
282 d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
283 DATA_OUT_PHASE;
284 else
285 d->reg[SBIC_csr] = SBIC_CSR_XFERRED |
286 DATA_IN_PHASE;
287
288 /* status phase? msg in and msg out? */
289 }
290 break;
291 default:
292 fatal("[ wdsc: don't know how to handle data for "
293 "cmd = 0x%02x ]\n", d->reg[SBIC_cmd]);
294 }
295
296 break;
297
298 default:
299 debug(" (TODO): 0x%02x", (int)idata);
300 }
301
302 debug(" ]\n");
303
304 /* After writing to a register, advance to the next: */
305 d->register_select ++;
306 }
307
308
309 /*
310 * dev_wdsc_access():
311 */
312 int dev_wdsc_access(struct cpu *cpu, struct memory *mem,
313 uint64_t relative_addr, unsigned char *data, size_t len,
314 int writeflag, void *extra)
315 {
316 int i;
317 struct wdsc_data *d = extra;
318 uint64_t idata = 0, odata = 0;
319
320 idata = memory_readmax64(cpu, data, len);
321
322 /*
323 * All registers on the WDSC seem to be accessed by writing the
324 * register number to one address (SBIC_ADDR), and then reading/
325 * writing another address (SBIC_VAL).
326 *
327 * On SGI-IP22, these are at offset 3 and 7, respectively.
328 *
329 * TODO: If this device is to be used by other machine types, then
330 * this needs to be conditionalized.
331 */
332 relative_addr = (relative_addr - 3) / 4;
333
334 switch (relative_addr) {
335
336 case SBIC_ADDR:
337 /*
338 * Reading the combined ADDR/ASR returns the Status
339 * Register, writing selects which register to access
340 * via SBIC_VAL.
341 */
342 if (writeflag == MEM_READ) {
343 odata = SBIC_ASR_DBR;
344 if (d->irq_pending)
345 odata |= SBIC_ASR_INT;
346
347 debug("[ wdsc: read from Status Register: %02x ]\n",
348 (int)odata);
349 } else {
350 d->register_select = idata & (DEV_WDSC_NREGS - 1);
351 }
352 break;
353
354 case SBIC_VAL:
355 if (writeflag == MEM_READ) {
356 odata = d->reg[d->register_select];
357
358 if (d->register_select == SBIC_csr) {
359 /* TODO: when should interrupts actually be
360 ack:ed? */
361 d->irq_pending = 0;
362 }
363
364 debug("[ wdsc: read from register %i: 0x%02x ]\n",
365 d->register_select, (int)odata);
366 } else {
367 dev_wdsc_regwrite(cpu, d, idata & 0xff);
368 }
369 break;
370
371 default:
372 /* These should never occur: */
373 if (writeflag==MEM_READ) {
374 fatal("[ wdsc: read from 0x%x:", (int)relative_addr);
375 for (i=0; i<len; i++)
376 fatal(" %02x", data[i]);
377 fatal(" (len=%i) ]\n", len);
378 } else {
379 fatal("[ wdsc: write to 0x%x:", (int)relative_addr);
380 for (i=0; i<len; i++)
381 fatal(" %02x", data[i]);
382 fatal(" (len=%i) ]\n", len);
383 }
384 }
385
386 if (writeflag == MEM_READ)
387 memory_writemax64(cpu, data, len, odata);
388
389 dev_wdsc_tick(cpu, extra);
390
391 return 1;
392 }
393
394
395 /*
396 * dev_wdsc_init():
397 */
398 void dev_wdsc_init(struct machine *machine, struct memory *mem,
399 uint64_t baseaddr, int controller_nr, int irq_nr)
400 {
401 struct wdsc_data *d;
402
403 d = malloc(sizeof(struct wdsc_data));
404 if (d == NULL) {
405 fprintf(stderr, "out of memory\n");
406 exit(1);
407 }
408 memset(d, 0, sizeof(struct wdsc_data));
409 d->irq_nr = irq_nr;
410 d->controller_nr = controller_nr;
411
412 memory_device_register(mem, "wdsc", baseaddr, DEV_WDSC_LENGTH,
413 dev_wdsc_access, d, MEM_DEFAULT, NULL);
414
415 machine_add_tickfunction(machine, dev_wdsc_tick, d, 14);
416 }
417

  ViewVC Help
Powered by ViewVC 1.1.26