|
|
1.1 root 1: /*
2: * OpenBIOS ESP driver
3: *
4: * Copyright (C) 2004 Jens Axboe <[email protected]>
5: * Copyright (C) 2005 Stefan Reinauer <[email protected]>
6: *
7: * Credit goes to Hale Landis for his excellent ata demo software
8: * OF node handling and some fixes by Stefan Reinauer
9: *
10: * This program is free software; you can redistribute it and/or
11: * modify it under the terms of the GNU General Public License
12: * version 2
13: *
14: */
15:
16: #include "config.h"
17: #include "libopenbios/bindings.h"
18: #include "kernel/kernel.h"
19: #include "libc/byteorder.h"
20: #include "libc/vsprintf.h"
21:
22: #include "drivers/drivers.h"
23: #include "asm/io.h"
24: #include "scsi.h"
25: #include "asm/dma.h"
26: #include "esp.h"
27: #include "libopenbios/ofmem.h"
28:
29: #define BUFSIZE 4096
30:
31: #ifdef CONFIG_DEBUG_ESP
32: #define DPRINTF(fmt, args...) \
33: do { printk(fmt , ##args); } while (0)
34: #else
35: #define DPRINTF(fmt, args...)
36: #endif
37:
38: struct esp_dma {
39: volatile struct sparc_dma_registers *regs;
40: enum dvma_rev revision;
41: };
42:
43: typedef struct sd_private {
44: unsigned int bs;
45: const char *media_str[2];
46: uint32_t sectors;
47: uint8_t media;
48: uint8_t id;
49: uint8_t present;
50: char model[40];
51: } sd_private_t;
52:
53: struct esp_regs {
54: unsigned char regs[ESP_REG_SIZE];
55: };
56:
57: typedef struct esp_private {
58: volatile struct esp_regs *ll;
59: uint32_t buffer_dvma;
60: unsigned int irq; /* device IRQ number */
61: struct esp_dma espdma;
62: unsigned char *buffer;
63: sd_private_t sd[8];
64: } esp_private_t;
65:
66: static esp_private_t *global_esp;
67:
68: /* DECLARE data structures for the nodes. */
69: DECLARE_UNNAMED_NODE(ob_sd, INSTALL_OPEN, sizeof(sd_private_t *));
70: DECLARE_UNNAMED_NODE(ob_esp, INSTALL_OPEN, sizeof(esp_private_t *));
71:
72: #ifdef CONFIG_DEBUG_ESP
73: static void dump_drive(sd_private_t *drive)
74: {
75: printk("SCSI DRIVE @%lx:\n", (unsigned long)drive);
76: printk("id: %d\n", drive->id);
77: printk("media: %s\n", drive->media_str[0]);
78: printk("media: %s\n", drive->media_str[1]);
79: printk("model: %s\n", drive->model);
80: printk("sectors: %d\n", drive->sectors);
81: printk("present: %d\n", drive->present);
82: printk("bs: %d\n", drive->bs);
83: }
84: #endif
85:
86: static int
87: do_command(esp_private_t *esp, sd_private_t *sd, int cmdlen, int replylen)
88: {
89: int status;
90:
91: // Set SCSI target
92: esp->ll->regs[ESP_BUSID] = sd->id & 7;
93: // Set DMA address
94: esp->espdma.regs->st_addr = esp->buffer_dvma;
95: // Set DMA length
96: esp->ll->regs[ESP_TCLOW] = cmdlen & 0xff;
97: esp->ll->regs[ESP_TCMED] = (cmdlen >> 8) & 0xff;
98: // Set DMA direction and enable DMA
99: esp->espdma.regs->cond_reg = DMA_ENABLE;
100: // Set ATN, issue command
101: esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA;
102: // Wait for DMA to complete. Can this fail?
103: while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */;
104: // Check status
105: status = esp->ll->regs[ESP_STATUS];
106: // Clear interrupts to avoid guests seeing spurious interrupts
107: (void)esp->ll->regs[ESP_INTRPT];
108:
109: DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd->id, esp->buffer[0], status);
110:
111: /* Target didn't want all command data? */
112: if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT) {
113: return status;
114: }
115: if (replylen == 0) {
116: return 0;
117: }
118: /* Target went to status phase instead of data phase? */
119: if ((status & ESP_STAT_PMASK) == ESP_STATP) {
120: return status;
121: }
122:
123: // Get reply
124: // Set DMA address
125: esp->espdma.regs->st_addr = esp->buffer_dvma;
126: // Set DMA length
127: esp->ll->regs[ESP_TCLOW] = replylen & 0xff;
128: esp->ll->regs[ESP_TCMED] = (replylen >> 8) & 0xff;
129: // Set DMA direction
130: esp->espdma.regs->cond_reg = DMA_ST_WRITE | DMA_ENABLE;
131: // Transfer
132: esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA;
133: // Wait for DMA to complete
134: while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */;
135: // Check status
136: status = esp->ll->regs[ESP_STATUS];
137: // Clear interrupts to avoid guests seeing spurious interrupts
138: (void)esp->ll->regs[ESP_INTRPT];
139:
140: DPRINTF("do_command_reply: status 0x%x\n", status);
141:
142: if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT)
143: return status;
144: else
145: return 0; // OK
146: }
147:
148: // offset is in sectors
149: static int
150: ob_sd_read_sector(esp_private_t *esp, sd_private_t *sd, int offset)
151: {
152: DPRINTF("ob_sd_read_sector id %d sector=%d\n",
153: sd->id, offset);
154:
155: // Setup command = Read(10)
156: memset(esp->buffer, 0, 11);
157: esp->buffer[0] = 0x80;
158: esp->buffer[1] = READ_10;
159:
160: esp->buffer[3] = (offset >> 24) & 0xff;
161: esp->buffer[4] = (offset >> 16) & 0xff;
162: esp->buffer[5] = (offset >> 8) & 0xff;
163: esp->buffer[6] = offset & 0xff;
164:
165: esp->buffer[8] = 0;
166: esp->buffer[9] = 1;
167:
168: if (do_command(esp, sd, 11, sd->bs))
169: return 0;
170:
171: return 0;
172: }
173:
174: static unsigned int
175: read_capacity(esp_private_t *esp, sd_private_t *sd)
176: {
177: // Setup command = Read Capacity
178: memset(esp->buffer, 0, 11);
179: esp->buffer[0] = 0x80;
180: esp->buffer[1] = READ_CAPACITY;
181:
182: if (do_command(esp, sd, 11, 8)) {
183: sd->sectors = 0;
184: sd->bs = 0;
185: DPRINTF("read_capacity id %d failed\n", sd->id);
186: return 0;
187: }
188: sd->bs = (esp->buffer[4] << 24) | (esp->buffer[5] << 16) | (esp->buffer[6] << 8) | esp->buffer[7];
189: sd->sectors = ((esp->buffer[0] << 24) | (esp->buffer[1] << 16) | (esp->buffer[2] << 8) | esp->buffer[3]) * (sd->bs / 512);
190:
191: DPRINTF("read_capacity id %d bs %d sectors %d\n", sd->id, sd->bs,
192: sd->sectors);
193: return 1;
194: }
195:
196: static unsigned int
197: test_unit_ready(esp_private_t *esp, sd_private_t *sd)
198: {
199: /* Setup command = Test Unit Ready */
200: memset(esp->buffer, 0, 6);
201: esp->buffer[0] = 0x80;
202: esp->buffer[1] = TEST_UNIT_READY;
203:
204: if (do_command(esp, sd, 6, 0)) {
205: DPRINTF("test_unit_ready id %d failed\n", sd->id);
206: return 0;
207: }
208:
209: DPRINTF("test_unit_ready id %d success\n", sd->id);
210: return 1;
211: }
212:
213: static unsigned int
214: inquiry(esp_private_t *esp, sd_private_t *sd)
215: {
216: const char *media[2] = { "UNKNOWN", "UNKNOWN"};
217:
218: // Setup command = Inquiry
219: memset(esp->buffer, 0, 7);
220: esp->buffer[0] = 0x80;
221: esp->buffer[1] = INQUIRY;
222:
223: esp->buffer[5] = 36;
224:
225: if (do_command(esp, sd, 7, 36)) {
226: sd->present = 0;
227: sd->media = -1;
228: return 0;
229: }
230: sd->present = 1;
231: sd->media = esp->buffer[0];
232:
233: switch (sd->media) {
234: case TYPE_DISK:
235: media[0] = "disk";
236: media[1] = "hd";
237: break;
238: case TYPE_ROM:
239: media[0] = "cdrom";
240: media[1] = "cd";
241: break;
242: }
243: sd->media_str[0] = media[0];
244: sd->media_str[1] = media[1];
245: memcpy(sd->model, &esp->buffer[16], 16);
246: sd->model[17] = '\0';
247:
248: return 1;
249: }
250:
251:
252: static void
253: ob_sd_read_blocks(sd_private_t **sd)
254: {
255: cell n = POP(), cnt = n;
256: ucell blk = POP();
257: char *dest = (char*)POP();
258: int pos, spb, sect_offset;
259:
260: DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd)->id, (unsigned long)dest, blk, n );
261:
262: if ((*sd)->bs == 0) {
263: PUSH(0);
264: return;
265: }
266: spb = (*sd)->bs / 512;
267: while (n) {
268: sect_offset = blk / spb;
269: pos = (blk - sect_offset * spb) * 512;
270:
271: if (ob_sd_read_sector(global_esp, *sd, sect_offset)) {
272: DPRINTF("ob_sd_read_blocks: error\n");
273: RET(0);
274: }
275: while (n && pos < spb * 512) {
276: memcpy(dest, global_esp->buffer + pos, 512);
277: pos += 512;
278: dest += 512;
279: n--;
280: blk++;
281: }
282: }
283: PUSH(cnt);
284: }
285:
286: static void
287: ob_sd_block_size(__attribute__((unused))sd_private_t **sd)
288: {
289: PUSH(512);
290: }
291:
292: static void
293: ob_sd_open(__attribute__((unused))sd_private_t **sd)
294: {
295: int ret = 1, id;
296: phandle_t ph;
297:
298: fword("my-unit");
299: id = POP();
300: POP(); // unit id is 2 ints but we only need one.
301: *sd = &global_esp->sd[id];
302:
303: #ifdef CONFIG_DEBUG_ESP
304: {
305: char *args;
306:
307: fword("my-args");
308: args = pop_fstr_copy();
309: DPRINTF("opening drive %d args %s\n", id, args);
310: free(args);
311: }
312: #endif
313:
314: selfword("open-deblocker");
315:
316: /* interpose disk-label */
317: ph = find_dev("/packages/disk-label");
318: fword("my-args");
319: PUSH_ph( ph );
320: fword("interpose");
321:
322: RET ( -ret );
323: }
324:
325: static void
326: ob_sd_close(__attribute__((unused)) sd_private_t **sd)
327: {
328: selfword("close-deblocker");
329: }
330:
331: NODE_METHODS(ob_sd) = {
332: { "open", ob_sd_open },
333: { "close", ob_sd_close },
334: { "read-blocks", ob_sd_read_blocks },
335: { "block-size", ob_sd_block_size },
336: };
337:
338:
339: static int
340: espdma_init(unsigned int slot, uint64_t base, unsigned long offset,
341: struct esp_dma *espdma)
342: {
343: espdma->regs = (void *)ofmem_map_io(base + (uint64_t)offset, 0x10);
344:
345: if (espdma->regs == NULL) {
346: DPRINTF("espdma_init: cannot map registers\n");
347: return -1;
348: }
349:
350: DPRINTF("dma1: ");
351:
352: switch ((espdma->regs->cond_reg) & DMA_DEVICE_ID) {
353: case DMA_VERS0:
354: espdma->revision = dvmarev0;
355: DPRINTF("Revision 0 ");
356: break;
357: case DMA_ESCV1:
358: espdma->revision = dvmaesc1;
359: DPRINTF("ESC Revision 1 ");
360: break;
361: case DMA_VERS1:
362: espdma->revision = dvmarev1;
363: DPRINTF("Revision 1 ");
364: break;
365: case DMA_VERS2:
366: espdma->revision = dvmarev2;
367: DPRINTF("Revision 2 ");
368: break;
369: case DMA_VERHME:
370: espdma->revision = dvmahme;
371: DPRINTF("HME DVMA gate array ");
372: break;
373: case DMA_VERSPLUS:
374: espdma->revision = dvmarevplus;
375: DPRINTF("Revision 1 PLUS ");
376: break;
377: default:
378: DPRINTF("unknown dma version %x",
379: (espdma->regs->cond_reg) & DMA_DEVICE_ID);
380: /* espdma->allocated = 1; */
381: break;
382: }
383: DPRINTF("\n");
384:
385: push_str("/iommu/sbus/espdma");
386: fword("find-device");
387:
388: /* set reg */
389: PUSH(slot);
390: fword("encode-int");
391: PUSH(offset);
392: fword("encode-int");
393: fword("encode+");
394: PUSH(0x00000010);
395: fword("encode-int");
396: fword("encode+");
397: push_str("reg");
398: fword("property");
399:
400: return 0;
401: }
402:
403: static void
404: ob_esp_initialize(__attribute__((unused)) esp_private_t **esp)
405: {
406: phandle_t ph = get_cur_dev();
407:
408: set_int_property(ph, "#address-cells", 2);
409: set_int_property(ph, "#size-cells", 0);
410:
411: /* set device type */
412: push_str("scsi");
413: fword("device-type");
414:
415: /* QEMU's ESP emulation does not support mixing DMA and FIFO messages. By
416: setting this attribute, we prevent the Solaris ESP kernel driver from
417: trying to use this feature when booting a disk image (and failing) */
418: PUSH(0x58);
419: fword("encode-int");
420: push_str("scsi-options");
421: fword("property");
422:
423: PUSH(0x24);
424: fword("encode-int");
425: PUSH(0);
426: fword("encode-int");
427: fword("encode+");
428: push_str("intr");
429: fword("property");
430: }
431:
432: static void
433: ob_esp_decodeunit(__attribute__((unused)) esp_private_t **esp)
434: {
435: fword("decode-unit-scsi");
436: }
437:
438:
439: static void
440: ob_esp_encodeunit(__attribute__((unused)) esp_private_t **esp)
441: {
442: fword("encode-unit-scsi");
443: }
444:
445: NODE_METHODS(ob_esp) = {
446: { NULL, ob_esp_initialize },
447: { "decode-unit", ob_esp_decodeunit },
448: { "encode-unit", ob_esp_encodeunit },
449: };
450:
451: static void
452: add_alias(const char *device, const char *alias)
453: {
454: DPRINTF("add_alias dev \"%s\" = alias \"%s\"\n", device, alias);
455: push_str("/aliases");
456: fword("find-device");
457: push_str(device);
458: fword("encode-string");
459: push_str(alias);
460: fword("property");
461: }
462:
463: int
464: ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset,
465: unsigned long dmaoffset)
466: {
467: int id, diskcount = 0, cdcount = 0, *counter_ptr;
468: char nodebuff[256], aliasbuff[256];
469: esp_private_t *esp;
470: unsigned int i;
471:
472: DPRINTF("Initializing SCSI...");
473:
474: esp = malloc(sizeof(esp_private_t));
475: if (!esp) {
476: DPRINTF("Can't allocate ESP private structure\n");
477: return -1;
478: }
479:
480: global_esp = esp;
481:
482: if (espdma_init(slot, base, dmaoffset, &esp->espdma) != 0) {
483: return -1;
484: }
485: /* Get the IO region */
486: esp->ll = (void *)ofmem_map_io(base + (uint64_t)espoffset,
487: sizeof(struct esp_regs));
488: if (esp->ll == NULL) {
489: DPRINTF("Can't map ESP registers\n");
490: return -1;
491: }
492:
493: esp->buffer = (void *)dvma_alloc(BUFSIZE, &esp->buffer_dvma);
494: if (!esp->buffer || !esp->buffer_dvma) {
495: DPRINTF("Can't get a DVMA buffer\n");
496: return -1;
497: }
498:
499: // Chip reset
500: esp->ll->regs[ESP_CMD] = ESP_CMD_RC;
501:
502: DPRINTF("ESP at 0x%lx, buffer va 0x%lx dva 0x%lx\n", (unsigned long)esp,
503: (unsigned long)esp->buffer, (unsigned long)esp->buffer_dvma);
504: DPRINTF("done\n");
505: DPRINTF("Initializing SCSI devices...");
506:
507: for (id = 0; id < 8; id++) {
508: esp->sd[id].id = id;
509: if (!inquiry(esp, &esp->sd[id])) {
510: DPRINTF("Unit %d not present\n", id);
511: continue;
512: }
513: /* Clear Unit Attention condition from reset */
514: for (i = 0; i < 5; i++) {
515: if (test_unit_ready(esp, &esp->sd[id])) {
516: break;
517: }
518: }
519: if (i == 5) {
520: DPRINTF("Unit %d present but won't become ready\n", id);
521: continue;
522: }
523: DPRINTF("Unit %d present\n", id);
524: read_capacity(esp, &esp->sd[id]);
525:
526: #ifdef CONFIG_DEBUG_ESP
527: dump_drive(&esp->sd[id]);
528: #endif
529: }
530:
531: REGISTER_NAMED_NODE(ob_esp, "/iommu/sbus/espdma/esp");
532: device_end();
533: /* set reg */
534: push_str("/iommu/sbus/espdma/esp");
535: fword("find-device");
536: PUSH(slot);
537: fword("encode-int");
538: PUSH(espoffset);
539: fword("encode-int");
540: fword("encode+");
541: PUSH(0x00000010);
542: fword("encode-int");
543: fword("encode+");
544: push_str("reg");
545: fword("property");
546:
547: PUSH(0x02625a00);
548: fword("encode-int");
549: push_str("clock-frequency");
550: fword("property");
551:
552: for (id = 0; id < 8; id++) {
553: if (!esp->sd[id].present)
554: continue;
555: push_str("/iommu/sbus/espdma/esp");
556: fword("find-device");
557: fword("new-device");
558: push_str("sd");
559: fword("device-name");
560: push_str("block");
561: fword("device-type");
562: fword("is-deblocker");
563: PUSH(id);
564: fword("encode-int");
565: PUSH(0);
566: fword("encode-int");
567: fword("encode+");
568: push_str("reg");
569: fword("property");
570: fword("finish-device");
571: snprintf(nodebuff, sizeof(nodebuff), "/iommu/sbus/espdma/esp/sd@%d,0",
572: id);
573: REGISTER_NODE_METHODS(ob_sd, nodebuff);
574: if (esp->sd[id].media == TYPE_ROM) {
575: counter_ptr = &cdcount;
576: } else {
577: counter_ptr = &diskcount;
578: }
579: if (*counter_ptr == 0) {
580: add_alias(nodebuff, esp->sd[id].media_str[0]);
581: add_alias(nodebuff, esp->sd[id].media_str[1]);
582: }
583: snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
584: esp->sd[id].media_str[0], *counter_ptr);
585: add_alias(nodebuff, aliasbuff);
586: snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
587: esp->sd[id].media_str[1], *counter_ptr);
588: add_alias(nodebuff, aliasbuff);
589: snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)", id);
590: add_alias(nodebuff, aliasbuff);
591: snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)@0,0", id);
592: add_alias(nodebuff, aliasbuff);
593: (*counter_ptr)++;
594: }
595: DPRINTF("done\n");
596:
597: return 0;
598: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.