4 * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
5 * Copyright (C) 2005 Stefan Reinauer <stepan@openbios.org>
7 * Credit goes to Hale Landis for his excellent ata demo software
8 * OF node handling and some fixes by Stefan Reinauer
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
17 #include "libopenbios/bindings.h"
18 #include "kernel/kernel.h"
19 #include "libc/byteorder.h"
20 #include "libc/vsprintf.h"
22 #include "drivers/drivers.h"
27 #include "libopenbios/ofmem.h"
31 #ifdef CONFIG_DEBUG_ESP
32 #define DPRINTF(fmt, args...) \
33 do { printk(fmt , ##args); } while (0)
35 #define DPRINTF(fmt, args...)
39 volatile struct sparc_dma_registers
*regs
;
40 enum dvma_rev revision
;
43 typedef struct sd_private
{
45 const char *media_str
[2];
54 unsigned char regs
[ESP_REG_SIZE
];
57 typedef struct esp_private
{
58 volatile struct esp_regs
*ll
;
60 unsigned int irq
; /* device IRQ number */
61 struct esp_dma espdma
;
62 unsigned char *buffer
;
66 static esp_private_t
*global_esp
;
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
*));
72 #ifdef CONFIG_DEBUG_ESP
73 static void dump_drive(sd_private_t
*drive
)
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
);
87 do_command(esp_private_t
*esp
, sd_private_t
*sd
, int cmdlen
, int replylen
)
92 esp
->ll
->regs
[ESP_BUSID
] = sd
->id
& 7;
94 esp
->espdma
.regs
->st_addr
= esp
->buffer_dvma
;
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 */;
105 status
= esp
->ll
->regs
[ESP_STATUS
];
106 // Clear interrupts to avoid guests seeing spurious interrupts
107 (void)esp
->ll
->regs
[ESP_INTRPT
];
109 DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd
->id
, esp
->buffer
[0], status
);
111 // Target didn't want all command data or went to status phase
112 // instead of data phase?
113 if ((status
& ESP_STAT_TCNT
) != ESP_STAT_TCNT
114 || (status
& ESP_STAT_PMASK
) == ESP_STATP
)
119 esp
->espdma
.regs
->st_addr
= esp
->buffer_dvma
;
121 esp
->ll
->regs
[ESP_TCLOW
] = replylen
& 0xff;
122 esp
->ll
->regs
[ESP_TCMED
] = (replylen
>> 8) & 0xff;
124 esp
->espdma
.regs
->cond_reg
= DMA_ST_WRITE
| DMA_ENABLE
;
126 esp
->ll
->regs
[ESP_CMD
] = ESP_CMD_TI
| ESP_CMD_DMA
;
127 // Wait for DMA to complete
128 while ((esp
->espdma
.regs
->cond_reg
& DMA_HNDL_INTR
) == 0) /* no-op */;
130 status
= esp
->ll
->regs
[ESP_STATUS
];
131 // Clear interrupts to avoid guests seeing spurious interrupts
132 (void)esp
->ll
->regs
[ESP_INTRPT
];
134 DPRINTF("do_command_reply: status 0x%x\n", status
);
136 if ((status
& ESP_STAT_TCNT
) != ESP_STAT_TCNT
)
142 // offset is in sectors
144 ob_sd_read_sector(esp_private_t
*esp
, sd_private_t
*sd
, int offset
)
146 DPRINTF("ob_sd_read_sector id %d sector=%d\n",
149 // Setup command = Read(10)
150 memset(esp
->buffer
, 0, 11);
151 esp
->buffer
[0] = 0x80;
152 esp
->buffer
[1] = READ_10
;
154 esp
->buffer
[3] = (offset
>> 24) & 0xff;
155 esp
->buffer
[4] = (offset
>> 16) & 0xff;
156 esp
->buffer
[5] = (offset
>> 8) & 0xff;
157 esp
->buffer
[6] = offset
& 0xff;
162 if (do_command(esp
, sd
, 11, sd
->bs
))
169 read_capacity(esp_private_t
*esp
, sd_private_t
*sd
)
171 // Setup command = Read Capacity
172 memset(esp
->buffer
, 0, 11);
173 esp
->buffer
[0] = 0x80;
174 esp
->buffer
[1] = READ_CAPACITY
;
176 if (do_command(esp
, sd
, 11, 8)) {
182 sd
->bs
= (esp
->buffer
[4] << 24) | (esp
->buffer
[5] << 16) | (esp
->buffer
[6] << 8) | esp
->buffer
[7];
183 sd
->sectors
= ((esp
->buffer
[0] << 24) | (esp
->buffer
[1] << 16) | (esp
->buffer
[2] << 8) | esp
->buffer
[3]) * (sd
->bs
/ 512);
189 inquiry(esp_private_t
*esp
, sd_private_t
*sd
)
191 const char *media
[2] = { "UNKNOWN", "UNKNOWN"};
193 // Setup command = Inquiry
194 memset(esp
->buffer
, 0, 7);
195 esp
->buffer
[0] = 0x80;
196 esp
->buffer
[1] = INQUIRY
;
200 if (do_command(esp
, sd
, 7, 36)) {
206 sd
->media
= esp
->buffer
[0];
218 sd
->media_str
[0] = media
[0];
219 sd
->media_str
[1] = media
[1];
220 memcpy(sd
->model
, &esp
->buffer
[16], 16);
221 sd
->model
[17] = '\0';
228 ob_sd_read_blocks(sd_private_t
**sd
)
230 cell n
= POP(), cnt
= n
;
232 char *dest
= (char*)POP();
233 int pos
, spb
, sect_offset
;
235 DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd
)->id
, (unsigned long)dest
, blk
, n
);
237 spb
= (*sd
)->bs
/ 512;
239 sect_offset
= blk
/ spb
;
240 pos
= (blk
- sect_offset
* spb
) * 512;
242 if (ob_sd_read_sector(global_esp
, *sd
, sect_offset
)) {
243 DPRINTF("ob_sd_read_blocks: error\n");
246 while (n
&& pos
< spb
* 512) {
247 memcpy(dest
, global_esp
->buffer
+ pos
, 512);
258 ob_sd_block_size(__attribute__((unused
))sd_private_t
**sd
)
264 ob_sd_open(__attribute__((unused
))sd_private_t
**sd
)
271 POP(); // unit id is 2 ints but we only need one.
272 *sd
= &global_esp
->sd
[id
];
274 #ifdef CONFIG_DEBUG_ESP
279 args
= pop_fstr_copy();
280 DPRINTF("opening drive %d args %s\n", id
, args
);
285 selfword("open-deblocker");
287 /* interpose disk-label */
288 ph
= find_dev("/packages/disk-label");
297 ob_sd_close(__attribute__((unused
)) sd_private_t
**sd
)
299 selfword("close-deblocker");
302 NODE_METHODS(ob_sd
) = {
303 { "open", ob_sd_open
},
304 { "close", ob_sd_close
},
305 { "read-blocks", ob_sd_read_blocks
},
306 { "block-size", ob_sd_block_size
},
311 espdma_init(unsigned int slot
, uint64_t base
, unsigned long offset
,
312 struct esp_dma
*espdma
)
314 espdma
->regs
= (void *)ofmem_map_io(base
+ (uint64_t)offset
, 0x10);
316 if (espdma
->regs
== NULL
) {
317 DPRINTF("espdma_init: cannot map registers\n");
323 switch ((espdma
->regs
->cond_reg
) & DMA_DEVICE_ID
) {
325 espdma
->revision
= dvmarev0
;
326 DPRINTF("Revision 0 ");
329 espdma
->revision
= dvmaesc1
;
330 DPRINTF("ESC Revision 1 ");
333 espdma
->revision
= dvmarev1
;
334 DPRINTF("Revision 1 ");
337 espdma
->revision
= dvmarev2
;
338 DPRINTF("Revision 2 ");
341 espdma
->revision
= dvmahme
;
342 DPRINTF("HME DVMA gate array ");
345 espdma
->revision
= dvmarevplus
;
346 DPRINTF("Revision 1 PLUS ");
349 DPRINTF("unknown dma version %x",
350 (espdma
->regs
->cond_reg
) & DMA_DEVICE_ID
);
351 /* espdma->allocated = 1; */
356 push_str("/iommu/sbus/espdma");
357 fword("find-device");
375 ob_esp_initialize(__attribute__((unused
)) esp_private_t
**esp
)
377 phandle_t ph
= get_cur_dev();
379 set_int_property(ph
, "#address-cells", 2);
380 set_int_property(ph
, "#size-cells", 0);
382 /* set device type */
384 fword("device-type");
386 /* QEMU's ESP emulation does not support mixing DMA and FIFO messages. By
387 setting this attribute, we prevent the Solaris ESP kernel driver from
388 trying to use this feature when booting a disk image (and failing) */
391 push_str("scsi-options");
404 ob_esp_decodeunit(__attribute__((unused
)) esp_private_t
**esp
)
406 fword("decode-unit-scsi");
411 ob_esp_encodeunit(__attribute__((unused
)) esp_private_t
**esp
)
413 fword("encode-unit-scsi");
416 NODE_METHODS(ob_esp
) = {
417 { NULL
, ob_esp_initialize
},
418 { "decode-unit", ob_esp_decodeunit
},
419 { "encode-unit", ob_esp_encodeunit
},
423 add_alias(const char *device
, const char *alias
)
425 DPRINTF("add_alias dev \"%s\" = alias \"%s\"\n", device
, alias
);
426 push_str("/aliases");
427 fword("find-device");
429 fword("encode-string");
435 ob_esp_init(unsigned int slot
, uint64_t base
, unsigned long espoffset
,
436 unsigned long dmaoffset
)
438 int id
, diskcount
= 0, cdcount
= 0, *counter_ptr
;
439 char nodebuff
[256], aliasbuff
[256];
442 DPRINTF("Initializing SCSI...");
444 esp
= malloc(sizeof(esp_private_t
));
446 DPRINTF("Can't allocate ESP private structure\n");
452 if (espdma_init(slot
, base
, dmaoffset
, &esp
->espdma
) != 0) {
455 /* Get the IO region */
456 esp
->ll
= (void *)ofmem_map_io(base
+ (uint64_t)espoffset
,
457 sizeof(struct esp_regs
));
458 if (esp
->ll
== NULL
) {
459 DPRINTF("Can't map ESP registers\n");
463 esp
->buffer
= (void *)dvma_alloc(BUFSIZE
, &esp
->buffer_dvma
);
464 if (!esp
->buffer
|| !esp
->buffer_dvma
) {
465 DPRINTF("Can't get a DVMA buffer\n");
470 esp
->ll
->regs
[ESP_CMD
] = ESP_CMD_RC
;
472 DPRINTF("ESP at 0x%lx, buffer va 0x%lx dva 0x%lx\n", (unsigned long)esp
,
473 (unsigned long)esp
->buffer
, (unsigned long)esp
->buffer_dvma
);
475 DPRINTF("Initializing SCSI devices...");
477 for (id
= 0; id
< 8; id
++) {
479 if (!inquiry(esp
, &esp
->sd
[id
]))
481 read_capacity(esp
, &esp
->sd
[id
]);
483 #ifdef CONFIG_DEBUG_ESP
484 dump_drive(&esp
->sd
[id
]);
488 REGISTER_NAMED_NODE(ob_esp
, "/iommu/sbus/espdma/esp");
491 push_str("/iommu/sbus/espdma/esp");
492 fword("find-device");
506 push_str("clock-frequency");
509 for (id
= 0; id
< 8; id
++) {
510 if (!esp
->sd
[id
].present
)
512 push_str("/iommu/sbus/espdma/esp");
513 fword("find-device");
516 fword("device-name");
518 fword("device-type");
519 fword("is-deblocker");
527 fword("finish-device");
528 snprintf(nodebuff
, sizeof(nodebuff
), "/iommu/sbus/espdma/esp/sd@%d,0",
530 REGISTER_NODE_METHODS(ob_sd
, nodebuff
);
531 if (esp
->sd
[id
].media
== TYPE_ROM
) {
532 counter_ptr
= &cdcount
;
534 counter_ptr
= &diskcount
;
536 if (*counter_ptr
== 0) {
537 add_alias(nodebuff
, esp
->sd
[id
].media_str
[0]);
538 add_alias(nodebuff
, esp
->sd
[id
].media_str
[1]);
540 snprintf(aliasbuff
, sizeof(aliasbuff
), "%s%d",
541 esp
->sd
[id
].media_str
[0], *counter_ptr
);
542 add_alias(nodebuff
, aliasbuff
);
543 snprintf(aliasbuff
, sizeof(aliasbuff
), "%s%d",
544 esp
->sd
[id
].media_str
[1], *counter_ptr
);
545 add_alias(nodebuff
, aliasbuff
);
546 snprintf(aliasbuff
, sizeof(aliasbuff
), "sd(0,%d,0)", id
);
547 add_alias(nodebuff
, aliasbuff
);
548 snprintf(aliasbuff
, sizeof(aliasbuff
), "sd(0,%d,0)@0,0", id
);
549 add_alias(nodebuff
, aliasbuff
);