[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tyndur-devel] [PATCH v2 13/24] cdi/scsi: Neu geschrieben



On Sun, Dec 13, 2015 at 01:10:58AM +0100, Max Reitz wrote:
> * Die týndur-Implementierung von cdi/scsi war im Prinzip nur zur
>   Benutzung mit dem CDI-ATAPI-Treiber geeignet. Dieser Patch macht die
>   Implementierung allgemeiner und auch für andere (zukünftige)
>   SCSI-CDI-Treiber einsatzfähig.
> 
> Signed-off-by: Max Reitz <max@xxxxxxxxxx>
> ---
>  src/modules/cdi/lib/cdi.c       |  26 ++-
>  src/modules/cdi/lib/scsi/disk.c | 506 ++++++++++++++++++++++++++++++----------
>  2 files changed, 404 insertions(+), 128 deletions(-)
> 
> diff --git a/src/modules/cdi/lib/cdi.c b/src/modules/cdi/lib/cdi.c
> index 5d519b4..11b3009 100644
> --- a/src/modules/cdi/lib/cdi.c
> +++ b/src/modules/cdi/lib/cdi.c
> @@ -19,13 +19,17 @@
>  #include "cdi.h"
>  #include "cdi/audio.h"
>  #include "cdi/fs.h"
> +#include "cdi/misc.h"
>  #include "cdi/pci.h"
> +#include "cdi/scsi.h"
>  #include "cdi/storage.h"
>  
>  extern void cdi_storage_driver_register(struct cdi_storage_driver* driver);
>  extern void cdi_audio_driver_register(struct cdi_audio_driver* driver);
>  extern void cdi_tyndur_net_device_init(struct cdi_device* device);
>  
> +void cdi_osdep_new_device(struct cdi_driver* drv, struct cdi_device* dev);
> +
>  static list_t* drivers = NULL;
>  
>  static void cdi_tyndur_run_drivers(void);
> @@ -149,6 +153,7 @@ static void cdi_tyndur_init_pci_devices(void)
>          }
>  
>          if (device != NULL) {
> +            cdi_osdep_new_device(driver, device);
>              cdi_list_push(driver->devices, device);

Hier wird das Gerät immer noch in die Liste des Treibers gesteckt...

>              printf("cdi: %x.%x.%x: Benutze Treiber %s\n",
>                  pci->bus, pci->dev, pci->function, driver->name);
> @@ -214,9 +219,8 @@ static void cdi_tyndur_run_drivers(void)
>              }
>          }
>  
> -        /* Netzwerk ist schon initialisiert und SCSI hat kein RPC-Interface,
> -         * sondern muss mit scsidisk gelinkt werden. */
> -        if (driver->type != CDI_NETWORK && driver->type != CDI_SCSI) {
> +        /* Netzwerk ist schon initialisiert */
> +        if (driver->type != CDI_NETWORK) {
>              init_service_register((char*) driver->name);
>          }

Commit a4514ab beschreibt diesen Hunk mit "Diese Änderung beseitigt den
nutzlosen atapi-Service." Mit dieser Serie ist der Service wieder da
(mit leerem Verzeichnisbaum), und zwar interessanterweise gleich zweimal:

[  INIT  ] service_register 'ata' = 3
[  INIT  ] service_register 'atapi' = 3
[  INIT  ] service_register 'atapi' = 3

Dafür ist jetzt der nutzlose scsidisk-Service weg, auch was wert. ;-)

>      }
> @@ -277,6 +281,22 @@ list_t* cdi_tyndur_get_drivers(void)
>      return drivers;
>  }
>  
> +void cdi_osdep_new_device(struct cdi_driver* drv, struct cdi_device* dev)
> +{
> +    if (!dev) {
> +        return;
> +    }
> +
> +    dev->driver = drv;
> +    cdi_list_push(drv->devices, dev);

...aber hier ist das schon einmal passiert. Ich vermute,
cdi_tyndur_init_pci_devices() sollte das dann bleiben lassen.

> +    switch ((int)drv->type) {
> +        case CDI_SCSI:
> +            cdi_scsi_device_init(CDI_UPCAST(dev, struct cdi_scsi_device, dev));
> +            break;
> +    }
> +}
> +
>  /**
>   * Wenn main nicht von einem Treiber ueberschrieben wird, ist hier der
>   * Einsprungspunkt. Die Standardfunktion ruft nur cdi_init() auf. Treiber, die
> diff --git a/src/modules/cdi/lib/scsi/disk.c b/src/modules/cdi/lib/scsi/disk.c
> index 49f408e..2f2b7bd 100644
> --- a/src/modules/cdi/lib/scsi/disk.c
> +++ b/src/modules/cdi/lib/scsi/disk.c
> @@ -1,6 +1,7 @@
>  /*
>   * Copyright (C) 2008 Mathias Gottschlag
>   * Copyright (C) 2009 Kevin Wolf
> + * Copyright (C) 2015 Max Reitz
>   *
>   * Permission is hereby granted, free of charge, to any person obtaining a copy
>   * of this software and associated documentation files (the "Software"), to
> @@ -26,14 +27,10 @@
>  #include <stdlib.h>
>  
>  #include <cdi/lists.h>
> +#include <cdi/misc.h>
>  #include <cdi/scsi.h>
>  #include <cdi/storage.h>
>  
> -#define big_endian_word(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8))
> -#define big_endian_dword(x) \
> -    ((big_endian_word((x) & 0xFFFF) << 16) | \
> -    (big_endian_word((x) >> 16)))
> -
>  static int cdi_scsi_disk_read(struct cdi_storage_device* device,
>      uint64_t start, uint64_t count, void* buffer);
>  
> @@ -44,84 +41,272 @@ struct cdi_storage_driver cdi_scsi_disk_driver = {
>      .drv = {
>          .name       = "scsidisk",
>          .type       = CDI_STORAGE,
> +        .bus        = CDI_SCSI,
>      },
>      .read_blocks    = cdi_scsi_disk_read,
>      .write_blocks   = cdi_scsi_disk_write,
>  };
>  
> -// TODO: This is kind of incomplete... -.-
> -// FIXME Das ist alles sehr CD-ROM-spezifisch hartkodiert...
>  
> -union cdrom_command
> +typedef struct scsi_storage_device {
> +    struct cdi_storage_device dev;
> +    struct cdi_scsi_device* backend;
> +    int lun;
> +} scsi_storage_device_t;
> +
> +
> +#define SCSI_REQUEST_SENSE      0x03
> +#define SCSI_INQUIRY            0x12
> +#define SCSI_START_STOP_UNIT    0x1b
> +#define SCSI_READ_CAPACITY      0x25
> +#define SCSI_READ10             0x28
> +#define SCSI_WRITE10            0x2a
> +#define SCSI_READ16             0x88
> +#define SCSI_WRITE16            0x8a
> +
> +struct scsi_cmd {
> +    uint8_t operation;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_request_sense {
> +    struct scsi_cmd cmd;
> +    uint8_t rsvd1;
> +    uint16_t rsvd2;
> +    uint8_t alloc_len;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_inquiry {
> +    struct scsi_cmd cmd;
> +    uint8_t rsvd;
> +    uint8_t page;
> +    uint16_t alloc_len;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_start_stop_unit {
> +    struct scsi_cmd cmd;
> +    uint8_t immed;
> +    uint8_t rsvd;
> +    uint8_t power_condition_modifier;
> +    uint8_t flags_power_condition;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_read_capacity {
> +    struct scsi_cmd cmd;
> +    uint8_t rsvd1;
> +    uint32_t lba;
> +    uint32_t rsvd2;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_read10 {
> +    struct scsi_cmd cmd;
> +    uint8_t rsvd1;
> +    uint32_t lba;
> +    uint8_t rsvd2;
> +    uint16_t length;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_write10 {
> +    struct scsi_cmd cmd;
> +    uint8_t rsvd1;
> +    uint32_t lba;
> +    uint8_t rsvd2;
> +    uint16_t length;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_read16 {
> +    struct scsi_cmd cmd;
> +    uint8_t flags;
> +    uint64_t lba;
> +    uint32_t length;
> +    uint8_t group;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_cmd_write16 {
> +    struct scsi_cmd cmd;
> +    uint8_t flags;
> +    uint64_t lba;
> +    uint32_t length;
> +    uint8_t group;
> +    uint8_t control;
> +} __attribute__((packed));
> +
> +struct scsi_sense {
> +    uint8_t resp_code;
> +    uint8_t segment;
> +    uint8_t flags;
> +    uint32_t information;
> +    uint8_t add_sense_length;
> +    uint32_t cmd_spec_info;
> +    uint8_t add_sense_code;
> +    uint8_t add_sense_code_qual;
> +    uint8_t field_replacable_unit_code;
> +    uint8_t sense_key_spec1;
> +    uint8_t sense_key_spec2;
> +    uint8_t sense_key_spec3;
> +} __attribute__((packed));

Diese Struct sieht unbenutzt aus.

> +struct scsi_inq_answer {
> +    uint8_t dev_type;
> +    uint8_t type_mod;
> +    uint8_t version;
> +    uint8_t resp_data_format;
> +    uint8_t add_length;
> +    uint8_t flags1, flags2, flags3;
> +    char vendor[8];
> +    char product[16];
> +    uint32_t revision;
> +    char serial[8];
> +    uint8_t vendor_unique[12];
> +    uint8_t clocking;
> +    uint8_t rsvd1;
> +    uint16_t version_desc[8];
> +    uint8_t rsvd2[22];
> +} __attribute__((packed));
> +
> +
> +static int scsi_read10(scsi_storage_device_t* dev, uint32_t sector,
> +                       uint16_t nb_sectors, char* buffer)
>  {
> -    struct
> -    {
> -        uint8_t opcode;
> -        uint8_t reserved0;
> -        uint32_t address;
> -        uint8_t reserved1;
> -        uint16_t length;
> -        uint8_t reserved2;
> -    } __attribute__ ((packed)) dfl;
> -    struct
> -    {
> -        uint8_t opcode;
> -        uint8_t reserved0;
> -        uint32_t address;
> -        uint32_t length;
> -        uint16_t reserved1;
> -    } __attribute__ ((packed)) ext;
> -};
> -
> -static int cdrom_read_partial(
> -    struct cdi_scsi_device *device, uint32_t sector, uint64_t nb_sectors,
> -     char *buffer)
> -{
> -    struct cdi_scsi_packet packet;
> -    struct cdi_scsi_driver* drv = (struct cdi_scsi_driver*) device->dev.driver;
> -    union cdrom_command* cmd = (union cdrom_command*) &packet.command;
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    struct scsi_cmd_read10 r10 = {
> +        .cmd = {
> +            .operation = SCSI_READ10
> +        },
> +        .lba    = cdi_cpu_to_be32(sector),
> +        .length = cdi_cpu_to_be16(nb_sectors)

Mach doch gleich ein Komma auch hinter das letzte initialisierte Feld,
dann muss der nächste Patch, der ein neues Feld setzt, keine Zeile
anfassen, die ihn gar nicht interessiert. (Gilt für alle
Initialisierungen im ganzen Patch.)

> +    };
> +    struct cdi_scsi_packet pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = buffer,
> +        .bufsize    = (size_t)nb_sectors * dev->dev.block_size,
> +        .direction  = CDI_SCSI_READ,
> +        .cmdsize    = sizeof(r10)
> +    };
> +    memcpy(pkt.command, &r10, sizeof(r10));
> +
> +    if (drv->request(dev->backend, &pkt)) {
> +        return -1;
> +    }
>  
> -    nb_sectors = (uint32_t) nb_sectors;
> +    return 0;
> +}
>  
> -    memset(&packet, 0, sizeof(packet));
> -    packet.direction = CDI_SCSI_READ;
> -    packet.buffer = buffer;
> -    packet.bufsize = 2048 * nb_sectors;
> -    packet.cmdsize = 12;
> +static int scsi_write10(scsi_storage_device_t* dev, uint32_t sector,
> +                        uint16_t nb_sectors, char* buffer)
> +{
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    struct scsi_cmd_write10 w10 = {
> +        .cmd = {
> +            .operation = SCSI_WRITE10
> +        },
> +        .lba    = cdi_cpu_to_be32(sector),
> +        .length = cdi_cpu_to_be16(nb_sectors)
> +    };
> +    struct cdi_scsi_packet pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = buffer,
> +        .bufsize    = (size_t)nb_sectors * dev->dev.block_size,
> +        .direction  = CDI_SCSI_WRITE,
> +        .cmdsize    = sizeof(w10)
> +    };
> +    memcpy(pkt.command, &w10, sizeof(w10));
> +
> +    if (drv->request(dev->backend, &pkt)) {
> +        return -1;
> +    }
>  
> -    cmd->ext.opcode = 0xA8;
> -    cmd->ext.address = big_endian_dword(sector);
> -    cmd->ext.length = big_endian_dword(nb_sectors);
> +    return 0;
> +}
>  
> -    if (drv->request(device, &packet)) {
> +static int scsi_read16(scsi_storage_device_t* dev, uint64_t sector,
> +                       uint32_t nb_sectors, char* buffer)
> +{
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    struct scsi_cmd_read16 r16 = {
> +        .cmd = {
> +            .operation = SCSI_READ16
> +        },
> +        .lba    = cdi_cpu_to_be64(sector),
> +        .length = cdi_cpu_to_be32(nb_sectors)
> +    };
> +    struct cdi_scsi_packet pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = buffer,
> +        .bufsize    = (size_t)nb_sectors * dev->dev.block_size,
> +        .direction  = CDI_SCSI_READ,
> +        .cmdsize    = sizeof(r16)
> +    };
> +    memcpy(pkt.command, &r16, sizeof(r16));
> +
> +    if (drv->request(dev->backend, &pkt)) {
>          return -1;
>      }
>  
> -    return nb_sectors;
> +    return 0;
>  }
>  
> -static int cdrom_capacity(struct cdi_scsi_device *device,
> -    uint32_t* num_sectors, uint32_t* sector_size)
> +static int scsi_write16(scsi_storage_device_t* dev, uint64_t sector,
> +                        uint32_t nb_sectors, char* buffer)
>  {
> -    uint32_t buffer[32];
> -    struct cdi_scsi_packet packet;
> -    struct cdi_scsi_driver* drv = (struct cdi_scsi_driver*) device->dev.driver;
> -    union cdrom_command* cmd = (union cdrom_command*) &packet.command;
> -
> -    memset(&packet, 0, sizeof(packet));
> -    packet.direction = CDI_SCSI_READ;
> -    packet.buffer = buffer;
> -    packet.bufsize = sizeof(buffer);
> -    packet.cmdsize = 12;
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    struct scsi_cmd_write16 w16 = {
> +        .cmd = {
> +            .operation = SCSI_WRITE16
> +        },
> +        .lba    = cdi_cpu_to_be64(sector),
> +        .length = cdi_cpu_to_be32(nb_sectors)
> +    };
> +    struct cdi_scsi_packet pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = buffer,
> +        .bufsize    = (size_t)nb_sectors * dev->dev.block_size,
> +        .direction  = CDI_SCSI_WRITE,
> +        .cmdsize    = sizeof(w16)
> +    };
> +    memcpy(pkt.command, &w16, sizeof(w16));
> +
> +    if (drv->request(dev->backend, &pkt)) {
> +        return -1;
> +    }
>  
> -    cmd->ext.opcode = 0x25;
> +    return 0;
> +}
>  
> -    if (drv->request(device, &packet)) {
> +static int scsi_get_capacity(scsi_storage_device_t* dev)
> +{
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    uint32_t capacity[2] = { 0 };
> +    struct scsi_cmd_read_capacity read_cap = {
> +        .cmd = {
> +            .operation = SCSI_READ_CAPACITY
> +        }
> +    };
> +    struct cdi_scsi_packet pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = capacity,
> +        .bufsize    = sizeof(capacity),
> +        .direction  = CDI_SCSI_READ,
> +        .cmdsize    = sizeof(read_cap)
> +    };
> +    memcpy(pkt.command, &read_cap, sizeof(read_cap));
> +
> +    if (drv->request(dev->backend, &pkt)) {
>          return -1;
>      }
>  
> -    *num_sectors = big_endian_dword(buffer[0]);
> -    *sector_size = big_endian_dword(buffer[1]);
> +    dev->dev.block_count = (uint64_t)cdi_be32_to_cpu(capacity[0]) + 1;
> +    dev->dev.block_size  = cdi_be32_to_cpu(capacity[1]);
>  
>      return 0;
>  }
> @@ -160,27 +345,28 @@ static void cdrom_sense(FsSCSIDevice *device, uint32_t index)
>  }
>  #endif
>  
> -int cdrom_init(struct cdi_scsi_device* device)
> +static int scsi_init(scsi_storage_device_t* dev)
>  {
> -    // Send inquiry command
> -    struct cdi_scsi_driver* drv = (struct cdi_scsi_driver*) device->dev.driver;
> -    struct cdi_scsi_packet packet;
> -    uint32_t status;
> -    unsigned char inqdata[96];
> -
> -    memset(&packet, 0, sizeof(packet));
> -    memset(inqdata, 0xF0, sizeof(inqdata));
> -
> -    packet.direction = CDI_SCSI_READ;
> -    packet.buffer = inqdata;
> -    packet.bufsize = 96;
> -    packet.cmdsize = 12;
> -
> -    ((union cdrom_command*)packet.command)->dfl.opcode = 0x12;
> -    packet.command[4] = 96;
> -    status = drv->request(device, &packet);
> -    if (status)
> -    {
> +    struct cdi_scsi_driver* drv = CDI_UPCAST(dev->backend->dev.driver,
> +                                             struct cdi_scsi_driver, drv);
> +    struct scsi_inq_answer inqdata;
> +
> +    struct scsi_cmd_inquiry inq = {
> +        .cmd = {
> +            .operation = SCSI_INQUIRY,
> +        },
> +        .alloc_len = cdi_cpu_to_be16(sizeof(inqdata))
> +    };
> +    struct cdi_scsi_packet inq_pkt = {
> +        .lun        = dev->lun,
> +        .buffer     = &inqdata,
> +        .bufsize    = sizeof(inqdata),
> +        .direction  = CDI_SCSI_READ,
> +        .cmdsize    = sizeof(inq)
> +    };
> +    memcpy(inq_pkt.command, &inq, sizeof(inq));
> +
> +    if (drv->request(dev->backend, &inq_pkt)) {
>          return -1;
>      }
>  
> @@ -189,56 +375,109 @@ int cdrom_init(struct cdi_scsi_device* device)
>          return KE_ERROR_UNKNOWN;
>  #endif
>  
> -    // Start drive
> -    packet.direction = CDI_SCSI_NODATA;
> -    ((union cdrom_command*)packet.command)->dfl.opcode = 0x1B;
> -    packet.buffer = 0;
> -    packet.bufsize = 0;
> -    packet.command[4] = 0;
> -    packet.command[4] = 3;
> -    packet.cmdsize = 12;
> -
> -    status = drv->request(device, &packet);
> -    if (status)
> -    {
> -        printf("cdrom %d: Start failed, %x\n", index, status);
> -        return -1;
> +    struct scsi_cmd_start_stop_unit ssu = {
> +        .cmd = {
> +            .operation = SCSI_START_STOP_UNIT,
> +        },
> +        .flags_power_condition = 0x3 // LOEJ+START
> +    };
> +    struct cdi_scsi_packet ssu_pkt = {
> +        .lun        = dev->lun,
> +        .direction  = CDI_SCSI_NODATA,
> +        .cmdsize    = sizeof(ssu)
> +    };
> +    memcpy(ssu_pkt.command, &ssu, sizeof(ssu));
> +
> +    if ((inqdata.dev_type & 0x1f) == 0x05) { // CD/DVD
> +        if (drv->request(dev->backend, &ssu_pkt)) {
> +            printf("cdrom: Start failed\n");
> +            return -1;
> +        }
> +        dev->dev.block_size = 2048;
> +    } else {
> +        dev->dev.block_size = 512;
>      }
>  
>      return 0;
>  }
>  
> -static int cdi_scsi_disk_read(struct cdi_storage_device* device,
> -    uint64_t start, uint64_t count, void* buffer)
> +static int cdi_scsi_disk_read(struct cdi_storage_device* dev, uint64_t start,
> +                              uint64_t count, void* buffer)
>  {
> -    struct cdi_scsi_device* dev = device->dev.backdev;
> +    scsi_storage_device_t* scsi_dev = CDI_UPCAST(dev, scsi_storage_device_t,
> +                                                 dev);
> +    bool read16 = (start >> 32) || ((start + count) >> 32);
>  
>      while (count > 0) {
>          int ret;
> +        uint32_t it_count;
> +
> +        if (read16) {
> +            it_count = count > 0xffffffffu ? 0xffffffffu : count;
> +        } else {
> +            it_count = count > 0xffff ? 0xffff : count;
> +        }
>  
> -        ret = cdrom_read_partial(dev, start, count, buffer);
> -        if (ret <= 0) {
> +        if (read16) {
> +            ret = scsi_read16(scsi_dev, start, it_count, buffer);
> +        } else {
> +            ret = scsi_read10(scsi_dev, start, it_count, buffer);
> +        }

Die zwei if-Blöcke könnte man eigentlich auch in einen zusammenpacken.

> +        if (ret < 0) {
>              return -1;
>          }
> -        start += ret;
> -        buffer += ret;
> -        count -= ret;
> +
> +        start += it_count;
> +        count -= it_count;
> +
> +        buffer = (void*) ((uintptr_t)buffer + it_count * dev->block_size);
>      }
>  
>      return 0;
>  }
>  
> -static int cdi_scsi_disk_write(struct cdi_storage_device* device,
> -    uint64_t start, uint64_t count, void* buffer)
> +static int cdi_scsi_disk_write(struct cdi_storage_device* dev, uint64_t start,
> +                               uint64_t count, void* buffer)
>  {
> -    return -1;
> +    scsi_storage_device_t* scsi_dev = CDI_UPCAST(dev, scsi_storage_device_t,
> +                                                 dev);
> +    bool write16 = (start >> 32) || ((start + count) >> 32);
> +
> +    while (count > 0) {
> +        int ret;
> +        uint32_t it_count;
> +
> +        if (write16) {
> +            it_count = count > 0xffffffffu ? 0xffffffffu : count;
> +        } else {
> +            it_count = count > 0xffff ? 0xffff : count;
> +        }
> +
> +        if (write16) {
> +            ret = scsi_write16(scsi_dev, start, it_count, buffer);
> +        } else {
> +            ret = scsi_write10(scsi_dev, start, it_count, buffer);
> +        }
> +        if (ret < 0) {
> +            return -1;
> +        }
> +
> +        start += it_count;
> +        count -= it_count;
> +
> +        buffer = (void*) ((uintptr_t)buffer + it_count * dev->block_size);
> +    }
> +
> +    return 0;
>  }

Und bis auf scsi_read10/16 durch scsi_write10/16 zu ersetzen scheint das
das gleiche zu sein wie oben. Mit je einem Funktionspointer für die
beiden Varianten müsste man das doch in eine einzige Instanz eindampfen
können.

> -static void driver_init(void)
> +static void driver_init(struct cdi_driver* drv)
>  {
>      static int initialised = 0;
>  
>      if (!initialised) {
> +        cdi_scsi_disk_driver.drv.name = strdup(drv->name);
> +
>          cdi_driver_register(&cdi_scsi_disk_driver.drv);
>          cdi_storage_driver_init(&cdi_scsi_disk_driver);
>      }

Aha, hier kommt der zweite atapi-Service her. Das ist also einfach nur
der umbenannte scsidisk. :-)

> @@ -246,30 +485,47 @@ static void driver_init(void)
>  
>  int cdi_scsi_disk_init(struct cdi_scsi_device* device)
>  {
> -    struct cdi_storage_device* frontdev;
> -    uint32_t num_sectors = 0, sector_size = 0;
> +    int luns = device->lun_count ?: 1;
>  
> -    driver_init();
> +    driver_init(device->dev.driver);
>  
> -    if (cdrom_init(device)) {
> -        return -1;
> -    }
> +    for (int lun = 0; lun < luns; lun++) {
> +        scsi_storage_device_t* dev = calloc(1, sizeof(*dev));
> +        bool inquiry_failed;
> +
> +        dev->backend = device;
> +        dev->lun = lun;
> +
> +        inquiry_failed = scsi_init(dev) < 0;
>  
> -    frontdev = calloc(1, sizeof(*frontdev));
> -    frontdev->dev.driver = (struct cdi_driver*) &cdi_scsi_disk_driver;
> -    frontdev->dev.name = device->dev.name;
> +        if (scsi_get_capacity(dev) < 0) {
> +            if (inquiry_failed) {
> +                /* We're fine as long as either INQUIRY or READ_CAPACITY work -
> +                 * but if both fail, there's not a lot we can do. */
> +                fprintf(stderr,
> +                        "[scsi] Failed to initialize LUN %i of device %s\n",
> +                        lun, device->dev.name);
>  
> -    // Groesse des Mediums bestimmen. Falls keins eingelegt ist, brauchen wir
> -    // trotzdem zumindest eine Sektorgroesse.
> -    cdrom_capacity(device, &num_sectors, &sector_size);
> -    frontdev->block_size = sector_size ? sector_size : 2048;
> -    frontdev->block_count = num_sectors;
> +                free(dev);
> +                continue;
> +            }
>  
> -    frontdev->dev.backdev = device;
> -    device->frontdev = frontdev;
> +            /* Apparently this is common for CD-ROM devices; at least the old
> +             * SCSI implementation didn't care about it. A default block_size
> +             * has been set by scsi_init(). */
> +            dev->dev.block_count = 0xffffffffu;

Ich weiß nicht, ob es an diesem Default liegt, aber ata:/atapi10 hat bei
mir mit leerem Laufwerk jetzt eine Dateigröße von -2048. Das finde ich
eher nicht so geschickt.

> +        }
> +
> +        dev->dev.dev.driver = (struct cdi_driver*) &cdi_scsi_disk_driver;
> +        if (luns > 1) {
> +            asprintf((char**) &dev->dev.dev.name, "%s_l%i",
> +                     device->dev.name, lun);
> +        } else {
> +            dev->dev.dev.name = strdup(device->dev.name);
> +        }
>  
> -    // LostIO-Verzeichnisknoten anlegen
> -    cdi_storage_device_init(frontdev);
> +        cdi_storage_device_init(&dev->dev);
> +    }
>  
>      return 0;
>  }

Kevin