Annotation of qemu/roms/openbios/drivers/esp.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.