1 /*
2 * OpenBIOS ESP driver
3 *
4 * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
5 * Copyright (C) 2005 Stefan Reinauer
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
dump_drive(sd_private_t * drive)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
do_command(esp_private_t * esp,sd_private_t * sd,int cmdlen,int replylen)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[1], 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
ob_sd_read_sector(esp_private_t * esp,sd_private_t * sd,int offset)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
read_capacity(esp_private_t * esp,sd_private_t * sd)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
test_unit_ready(esp_private_t * esp,sd_private_t * sd)197 test_unit_ready(esp_private_t *esp, sd_private_t *sd)
198 {
199 /* Setup command = Test Unit Ready */
200 memset(esp->buffer, 0, 7);
201 esp->buffer[0] = 0x80;
202 esp->buffer[1] = TEST_UNIT_READY;
203
204 if (do_command(esp, sd, 7, 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
inquiry(esp_private_t * esp,sd_private_t * sd)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 static void
ob_esp_dma_alloc(esp_private_t ** esp)252 ob_esp_dma_alloc(__attribute__((unused)) esp_private_t **esp)
253 {
254 call_parent_method("dma-alloc");
255 }
256
257 static void
ob_esp_dma_free(esp_private_t ** esp)258 ob_esp_dma_free(__attribute__((unused)) esp_private_t **esp)
259 {
260 call_parent_method("dma-free");
261 }
262
263 static void
ob_esp_dma_map_in(esp_private_t ** esp)264 ob_esp_dma_map_in(__attribute__((unused)) esp_private_t **esp)
265 {
266 call_parent_method("dma-map-in");
267 }
268
269 static void
ob_esp_dma_map_out(esp_private_t ** esp)270 ob_esp_dma_map_out(__attribute__((unused)) esp_private_t **esp)
271 {
272 call_parent_method("dma-map-out");
273 }
274
275 static void
ob_esp_dma_sync(esp_private_t ** esp)276 ob_esp_dma_sync(__attribute__((unused)) esp_private_t **esp)
277 {
278 call_parent_method("dma-sync");
279 }
280
281 static void
ob_sd_read_blocks(sd_private_t ** sd)282 ob_sd_read_blocks(sd_private_t **sd)
283 {
284 cell n = POP(), cnt = n;
285 ucell blk = POP();
286 char *dest = (char*)POP();
287 int pos, spb, sect_offset;
288
289 DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd)->id, (unsigned long)dest, blk, n );
290
291 if ((*sd)->bs == 0) {
292 PUSH(0);
293 return;
294 }
295 spb = (*sd)->bs / 512;
296 while (n) {
297 sect_offset = blk / spb;
298 pos = (blk - sect_offset * spb) * 512;
299
300 if (ob_sd_read_sector(global_esp, *sd, sect_offset)) {
301 DPRINTF("ob_sd_read_blocks: error\n");
302 RET(0);
303 }
304 while (n && pos < spb * 512) {
305 memcpy(dest, global_esp->buffer + pos, 512);
306 pos += 512;
307 dest += 512;
308 n--;
309 blk++;
310 }
311 }
312 PUSH(cnt);
313 }
314
315 static void
ob_sd_block_size(sd_private_t ** sd)316 ob_sd_block_size(__attribute__((unused))sd_private_t **sd)
317 {
318 PUSH(512);
319 }
320
321 static void
ob_sd_open(sd_private_t ** sd)322 ob_sd_open(__attribute__((unused))sd_private_t **sd)
323 {
324 int ret = 1, id;
325 phandle_t ph;
326
327 fword("my-unit");
328 id = POP();
329 POP(); // unit id is 2 ints but we only need one.
330 *sd = &global_esp->sd[id];
331
332 #ifdef CONFIG_DEBUG_ESP
333 {
334 char *args;
335
336 fword("my-args");
337 args = pop_fstr_copy();
338 DPRINTF("opening drive %d args %s\n", id, args);
339 free(args);
340 }
341 #endif
342
343 selfword("open-deblocker");
344
345 /* interpose disk-label */
346 ph = find_dev("/packages/disk-label");
347 fword("my-args");
348 PUSH_ph( ph );
349 fword("interpose");
350
351 RET ( -ret );
352 }
353
354 static void
ob_sd_close(sd_private_t ** sd)355 ob_sd_close(__attribute__((unused)) sd_private_t **sd)
356 {
357 selfword("close-deblocker");
358 }
359
360 NODE_METHODS(ob_sd) = {
361 { "open", ob_sd_open },
362 { "close", ob_sd_close },
363 { "read-blocks", ob_sd_read_blocks },
364 { "block-size", ob_sd_block_size },
365 { "dma-alloc", ob_esp_dma_alloc },
366 { "dma-free", ob_esp_dma_free },
367 { "dma-map-in", ob_esp_dma_map_in },
368 { "dma-map-out", ob_esp_dma_map_out },
369 { "dma-sync", ob_esp_dma_sync },
370 };
371
372
373 static int
espdma_init(unsigned int slot,uint64_t base,unsigned long offset,struct esp_dma * espdma)374 espdma_init(unsigned int slot, uint64_t base, unsigned long offset,
375 struct esp_dma *espdma)
376 {
377 espdma->regs = (void *)ofmem_map_io(base + (uint64_t)offset, 0x10);
378
379 if (espdma->regs == NULL) {
380 DPRINTF("espdma_init: cannot map registers\n");
381 return -1;
382 }
383
384 DPRINTF("dma1: ");
385
386 switch ((espdma->regs->cond_reg) & DMA_DEVICE_ID) {
387 case DMA_VERS0:
388 espdma->revision = dvmarev0;
389 DPRINTF("Revision 0 ");
390 break;
391 case DMA_ESCV1:
392 espdma->revision = dvmaesc1;
393 DPRINTF("ESC Revision 1 ");
394 break;
395 case DMA_VERS1:
396 espdma->revision = dvmarev1;
397 DPRINTF("Revision 1 ");
398 break;
399 case DMA_VERS2:
400 espdma->revision = dvmarev2;
401 DPRINTF("Revision 2 ");
402 break;
403 case DMA_VERHME:
404 espdma->revision = dvmahme;
405 DPRINTF("HME DVMA gate array ");
406 break;
407 case DMA_VERSPLUS:
408 espdma->revision = dvmarevplus;
409 DPRINTF("Revision 1 PLUS ");
410 break;
411 default:
412 DPRINTF("unknown dma version %x",
413 (espdma->regs->cond_reg) & DMA_DEVICE_ID);
414 /* espdma->allocated = 1; */
415 break;
416 }
417 DPRINTF("\n");
418
419 push_str("/iommu/sbus/espdma");
420 fword("find-device");
421
422 /* set reg */
423 PUSH(slot);
424 fword("encode-int");
425 PUSH(offset);
426 fword("encode-int");
427 fword("encode+");
428 PUSH(0x00000010);
429 fword("encode-int");
430 fword("encode+");
431 push_str("reg");
432 fword("property");
433
434 return 0;
435 }
436
437 static void
ob_esp_decodeunit(esp_private_t ** esp)438 ob_esp_decodeunit(__attribute__((unused)) esp_private_t **esp)
439 {
440 fword("decode-unit-scsi");
441 }
442
443
444 static void
ob_esp_encodeunit(esp_private_t ** esp)445 ob_esp_encodeunit(__attribute__((unused)) esp_private_t **esp)
446 {
447 fword("encode-unit-scsi");
448 }
449
450 NODE_METHODS(ob_esp) = {
451 { "decode-unit", ob_esp_decodeunit },
452 { "encode-unit", ob_esp_encodeunit },
453 { "dma-alloc", ob_esp_dma_alloc },
454 { "dma-free", ob_esp_dma_free },
455 { "dma-map-in", ob_esp_dma_map_in },
456 { "dma-map-out", ob_esp_dma_map_out },
457 { "dma-sync", ob_esp_dma_sync },
458 };
459
460 static void
add_alias(const char * device,const char * alias)461 add_alias(const char *device, const char *alias)
462 {
463 DPRINTF("add_alias dev \"%s\" = alias \"%s\"\n", device, alias);
464 push_str("/aliases");
465 fword("find-device");
466 push_str(device);
467 fword("encode-string");
468 push_str(alias);
469 fword("property");
470 }
471
472 int
ob_esp_init(unsigned int slot,uint64_t base,unsigned long espoffset,unsigned long dmaoffset)473 ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset,
474 unsigned long dmaoffset)
475 {
476 int id, diskcount = 0, cdcount = 0, *counter_ptr;
477 char nodebuff[256], aliasbuff[256];
478 esp_private_t *esp;
479 ucell addr;
480 unsigned int i;
481
482 DPRINTF("Initializing SCSI...");
483
484 esp = malloc(sizeof(esp_private_t));
485 if (!esp) {
486 DPRINTF("Can't allocate ESP private structure\n");
487 return -1;
488 }
489
490 global_esp = esp;
491
492 if (espdma_init(slot, base, dmaoffset, &esp->espdma) != 0) {
493 return -1;
494 }
495 /* Get the IO region */
496 esp->ll = (void *)ofmem_map_io(base + (uint64_t)espoffset,
497 sizeof(struct esp_regs));
498 if (esp->ll == NULL) {
499 DPRINTF("Can't map ESP registers\n");
500 return -1;
501 }
502
503 push_str("/iommu/sbus/espdma");
504 fword("find-device");
505 fword("new-device");
506
507 push_str("esp");
508 fword("device-name");
509
510 /* set device type */
511 push_str("scsi");
512 fword("device-type");
513
514 /* QEMU's ESP emulation does not support mixing DMA and FIFO messages. By
515 setting this attribute, we prevent the Solaris ESP kernel driver from
516 trying to use this feature when booting a disk image (and failing) */
517 PUSH(0x58);
518 fword("encode-int");
519 push_str("scsi-options");
520 fword("property");
521
522 PUSH(0x24);
523 fword("encode-int");
524 PUSH(0);
525 fword("encode-int");
526 fword("encode+");
527 push_str("intr");
528 fword("property");
529
530 PUSH(slot);
531 fword("encode-int");
532 PUSH(espoffset);
533 fword("encode-int");
534 fword("encode+");
535 PUSH(0x00000010);
536 fword("encode-int");
537 fword("encode+");
538 push_str("reg");
539 fword("property");
540
541 PUSH(0x02625a00);
542 fword("encode-int");
543 push_str("clock-frequency");
544 fword("property");
545
546 REGISTER_NODE_METHODS(ob_esp, "/iommu/sbus/espdma/esp");
547
548 fword("finish-device");
549
550 fword("my-self");
551 push_str("/iommu/sbus/espdma/esp");
552 feval("open-dev to my-self");
553 PUSH(BUFSIZE);
554 feval("dma-alloc");
555 addr = POP();
556 esp->buffer = cell2pointer(addr);
557
558 PUSH(addr);
559 PUSH(BUFSIZE);
560 PUSH(1);
561 feval("dma-map-in");
562 addr = POP();
563 esp->buffer_dvma = addr;
564 feval("to my-self");
565
566 if (!esp->buffer || !esp->buffer_dvma) {
567 DPRINTF("Can't get a DVMA buffer\n");
568 return -1;
569 }
570
571 // Chip reset
572 esp->ll->regs[ESP_CMD] = ESP_CMD_RC;
573
574 DPRINTF("ESP at 0x%lx, buffer va 0x%lx dva 0x%lx\n", (unsigned long)esp,
575 (unsigned long)esp->buffer, (unsigned long)esp->buffer_dvma);
576 DPRINTF("done\n");
577 DPRINTF("Initializing SCSI devices...");
578
579 for (id = 0; id < 8; id++) {
580 esp->sd[id].id = id;
581 if (!inquiry(esp, &esp->sd[id])) {
582 DPRINTF("Unit %d not present\n", id);
583 continue;
584 }
585 /* Clear Unit Attention condition from reset */
586 for (i = 0; i < 5; i++) {
587 if (test_unit_ready(esp, &esp->sd[id])) {
588 break;
589 }
590 }
591 if (i == 5) {
592 DPRINTF("Unit %d present but won't become ready\n", id);
593 continue;
594 }
595 DPRINTF("Unit %d present\n", id);
596 read_capacity(esp, &esp->sd[id]);
597
598 #ifdef CONFIG_DEBUG_ESP
599 dump_drive(&esp->sd[id]);
600 #endif
601 }
602
603 for (id = 0; id < 8; id++) {
604 if (!esp->sd[id].present)
605 continue;
606 push_str("/iommu/sbus/espdma/esp");
607 fword("find-device");
608 fword("new-device");
609 push_str("sd");
610 fword("device-name");
611 push_str("block");
612 fword("device-type");
613 fword("is-deblocker");
614 PUSH(id);
615 fword("encode-int");
616 PUSH(0);
617 fword("encode-int");
618 fword("encode+");
619 push_str("reg");
620 fword("property");
621 fword("finish-device");
622 snprintf(nodebuff, sizeof(nodebuff), "/iommu/sbus/espdma/esp/sd@%d,0",
623 id);
624 REGISTER_NODE_METHODS(ob_sd, nodebuff);
625 if (esp->sd[id].media == TYPE_ROM) {
626 counter_ptr = &cdcount;
627 } else {
628 counter_ptr = &diskcount;
629 }
630 if (*counter_ptr == 0) {
631 add_alias(nodebuff, esp->sd[id].media_str[0]);
632 add_alias(nodebuff, esp->sd[id].media_str[1]);
633 }
634 snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
635 esp->sd[id].media_str[0], *counter_ptr);
636 add_alias(nodebuff, aliasbuff);
637 snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
638 esp->sd[id].media_str[1], *counter_ptr);
639 add_alias(nodebuff, aliasbuff);
640 snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)", id);
641 add_alias(nodebuff, aliasbuff);
642 snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)@0,0", id);
643 add_alias(nodebuff, aliasbuff);
644 (*counter_ptr)++;
645 }
646 DPRINTF("done\n");
647
648 return 0;
649 }
650