qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 2/7] megasas: Update to 1.02


From: Hannes Reinecke
Subject: [Qemu-devel] [PATCH 2/7] megasas: Update to 1.02
Date: Tue, 15 Jun 2010 17:16:13 +0200
User-agent: Heirloom mailx 12.2 01/07/07

This patchset updates the megasas HBA emulation to v1.02.
Fixed issues;
- Fixup frame context handling
- Endianness fixes
- Implement reset function
- Improve DCMD bounds checking
- Improve dump_frame() output
- Sanitize I/O settings
- Return correct SCSI status codes

Signed-off-by: Hannes Reinecke <address@hidden>
---
 hw/megasas.c |  155 +++++++++++++++++++++++++++++++++++-----------------------
 hw/mfi.h     |    1 +
 2 files changed, 95 insertions(+), 61 deletions(-)

diff --git a/hw/megasas.c b/hw/megasas.c
index 19569a8..753d5dc 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -40,11 +40,12 @@ do { fprintf(stderr, "megasas: error: " fmt , ## 
__VA_ARGS__);} while (0)
 #endif
 
 /* Static definitions */
-#define MEGASAS_VERSION "1.01"
+#define MEGASAS_VERSION "1.02"
 #define MEGASAS_MAX_FRAMES 2048                /* Firmware limit at 65535 */
 #define MEGASAS_DEFAULT_FRAMES 1000    /* Windows requires this */
 #define MEGASAS_MAX_SGE 255            /* Firmware limit */
 #define MEGASAS_DEFAULT_SGE 80
+#define MEGASAS_MAX_SECTORS 0xFFFF     /* No real limit */
 #define MEGASAS_MAX_ARRAYS 128
 
 const char *mfi_frame_desc[] = {
@@ -53,6 +54,7 @@ const char *mfi_frame_desc[] = {
 
 struct megasas_cmd_t {
     int index;
+    int context;
 
     target_phys_addr_t pa;
     union mfi_frame *frame;
@@ -121,7 +123,8 @@ static void megasas_soft_reset(MPTState *s);
 static void megasas_map_sgl(struct megasas_cmd_t *cmd, int pa_offset)
 {
     int i;
-    int is_sgl64 = (cmd->frame->header.flags & MFI_FRAME_SGL64) ? 1 : 0;
+    uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
+    int is_sgl64 = (flags & MFI_FRAME_SGL64) ? 1 : 0;
     int sgl_addr_size = is_sgl64 ? sizeof(uint64_t) : sizeof(uint32_t);
 
     qemu_sglist_init(&cmd->sg, cmd->frame->header.sge_count);
@@ -152,7 +155,8 @@ static void megasas_build_sense(struct megasas_cmd_t *cmd, 
SCSISense sense)
     uint8_t *sense_ptr;
     uint8_t sense_len;
     target_phys_addr_t pa, pa_hi = 0, pa_lo;
-    int is_sense64 = (cmd->frame->header.flags & MFI_FRAME_SENSE64) ? 1 : 0;
+    uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
+    int is_sense64 = (flags & MFI_FRAME_SENSE64) ? 1 : 0;
 
     sense_ptr = qemu_mallocz(cmd->frame->header.sense_len);
     sense_len = scsi_build_sense(SENSE_CODE(INVALID_OPCODE), sense_ptr,
@@ -216,6 +220,22 @@ static uint64_t megasas_gen_sas_addr(unsigned long id)
  * Frame handling
  */
 
+static void megasas_dump_frame(struct megasas_cmd_t *cmd)
+{
+    DPRINTF("Frame %x: p%p context %x\n"
+           "\t%016lx %016lx\n\t%016lx %016lx\n"
+           "\t%016lx %016lx\n\t%016lx %016lx\n",
+           cmd->index, cmd->frame, cmd->context,
+           be64_to_cpu(cmd->frame->raw[0]),
+           be64_to_cpu(cmd->frame->raw[1]),
+           be64_to_cpu(cmd->frame->raw[2]),
+           be64_to_cpu(cmd->frame->raw[3]),
+           be64_to_cpu(cmd->frame->raw[4]),
+           be64_to_cpu(cmd->frame->raw[5]),
+           be64_to_cpu(cmd->frame->raw[6]),
+           be64_to_cpu(cmd->frame->raw[7]));
+}
+
 static inline int megasas_next_index(MPTState *s, int index)
 {
     index++;
@@ -253,9 +273,11 @@ static inline struct megasas_cmd_t 
*megasas_next_frame(MPTState *s,
     cmd = megasas_lookup_frame(s, frame);
     if (cmd) {
 #ifdef DEBUG_MEGASAS_QUEUE
-       DPRINTF("Found mapped frame %x context %x pa %lx\n", cmd->index,
-               cmd->frame->header.context, cmd->pa);
+       DPRINTF("Found mapped frame %x pa %lx\n", cmd->index, cmd->pa);
 #endif
+       if (cmd->context != -1)
+           DPRINTF("Frame %x context %x not finished\n",
+                   cmd->index, cmd->context);
        return cmd;
     }
     index = s->reply_queue_index;
@@ -300,15 +322,18 @@ megasas_enqueue_frame(MPTState *s, target_phys_addr_t 
frame)
        }
     }
 
-    cmd->frame->header.context = le32_to_cpu(cmd->frame->header.context);
-    cmd->frame->header.flags = le16_to_cpu(cmd->frame->header.flags);
-    cmd->frame->header.timeout = le16_to_cpu(cmd->frame->header.timeout);
-    cmd->frame->header.data_len = le32_to_cpu(cmd->frame->header.data_len);
+    cmd->context = le32_to_cpu(cmd->frame->header.context);
+    if (cmd->context != cmd->index) {
+       DPRINTF("Non-matching context %x, correcting to %x\n",
+               cmd->context, cmd->index);
+       megasas_dump_frame(cmd);
+       cmd->context = cmd->index;
+    }
     s->busy++;
 
 #ifdef DEBUG_MEGASAS_QUEUE
-    DPRINTF("Enqueue frame context %x tail %d busy %d\n",
-           cmd->frame->header.context, s->reply_queue_index, s->busy);
+    DPRINTF("Enqueue frame %x context %x tail %x busy %d\n",
+           cmd->index, cmd->context, s->reply_queue_index, s->busy);
 #endif
 
     return cmd;
@@ -334,7 +359,7 @@ static void megasas_dequeue_frame(MPTState *s, int context)
 
     s->reply_queue_index = megasas_next_index(s, tail);
 #ifdef DEBUG_MEGASAS_QUEUE
-    DPRINTF("Complete frame context %x tail %d busy %d doorbell %d\n",
+    DPRINTF("Complete frame context %x tail %x busy %d doorbell %d\n",
            context, tail, s->busy, s->doorbell);
 #endif
 
@@ -345,14 +370,6 @@ static void megasas_dequeue_frame(MPTState *s, int context)
     }
 }
 
-static void megasas_dump_frame(struct megasas_cmd_t *cmd)
-{
-    DPRINTF("Frame %d: cmd %x cdb %d sges %d ctx %x data_len %d\n",
-           cmd->index, cmd->frame->header.frame_cmd,
-           cmd->frame->header.cdb_len, cmd->frame->header.sge_count,
-           cmd->frame->header.context, cmd->frame->header.data_len);
-}
-
 static int megasas_finish_command(MPTState *s, struct megasas_cmd_t *cmd)
 {
     int context = -1;
@@ -364,8 +381,8 @@ static int megasas_finish_command(MPTState *s, struct 
megasas_cmd_t *cmd)
        s->event_count++;
        return -1;
     }
-    if (cmd->frame)
-       context = cmd->frame->header.context;
+    context = cmd->context;
+    cmd->context = -1;
 
     return context;
 }
@@ -395,6 +412,8 @@ static int megasas_init_firmware(MPTState *s, struct 
megasas_cmd_t *cmd)
     initq = cpu_physical_memory_map(iq_pa, &initq_size, 0);
     if (initq_size != sizeof(*initq)) {
        DPRINTF("MFI init firmware: failed to map queue mem\n");
+       if (initq)
+           cpu_physical_memory_unmap(initq, initq_size, 0, 0);
        s->fw_state = MFI_FWSTATE_FAULT;
        s->event_count++;
        goto out;
@@ -424,9 +443,22 @@ out:
 static int megasas_map_dcmd(struct megasas_cmd_t *cmd)
 {
     target_phys_addr_t iov_pa, iov_size_p;
-    uint32_t iov_size;
-    int is_sgl64 = (cmd->frame->header.flags & MFI_FRAME_SGL64) ? 1 : 0;
+    uint32_t iov_size = 0;
+    uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
+    int is_sgl64 = (flags & MFI_FRAME_SGL64) ? 1 : 0;
 
+    if (cmd->frame->header.sge_count == 0) {
+#ifdef DEBUG_MEGASAS_DCMD
+       DPRINTF("Zero DCMD sge count\n");
+#endif
+       cmd->iov_size = 0;
+       cmd->iov_buf = NULL;
+       return 0;
+    } else if (cmd->frame->header.sge_count > 1) {
+       DPRINTF("Invalid DCMD sge count %d\n",
+               cmd->frame->header.sge_count);
+       return -1;
+    }
     if (is_sgl64) {
        iov_pa = le64_to_cpu(cmd->frame->dcmd.sgl.sg64[0].addr);
        iov_size = le32_to_cpu(cmd->frame->dcmd.sgl.sg64[0].len);
@@ -451,7 +483,8 @@ static int megasas_map_dcmd(struct megasas_cmd_t *cmd)
 
 static int megasas_finish_dcmd(struct megasas_cmd_t *cmd, uint32_t size)
 {
-    int is_sgl64 = (cmd->frame->header.flags & MFI_FRAME_SGL64) ? 1 : 0;
+    uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
+    int is_sgl64 = (flags & MFI_FRAME_SGL64) ? 1 : 0;
     int sgl_addr_size = is_sgl64 ? sizeof(uint64_t) : sizeof(uint32_t);
 
     if (size > cmd->iov_size) {
@@ -459,6 +492,9 @@ static int megasas_finish_dcmd(struct megasas_cmd_t *cmd, 
uint32_t size)
                size, cmd->iov_size);
        size = cmd->iov_size;
     }
+    if (!cmd->iov_buf)
+       return 0;
+
     cpu_physical_memory_unmap(cmd->iov_buf, cmd->iov_size, 1, size);
     if (cmd->iov_size > size)
        stl_phys(cmd->pa + offsetof(struct mfi_dcmd_frame,sgl) + sgl_addr_size, 
size);
@@ -512,7 +548,7 @@ static int megasas_ctrl_get_info(MPTState *s, struct 
megasas_cmd_t *cmd)
     info->max_lds = s->fw_luns;
     info->max_cmds = s->fw_cmds;
     info->max_sg_elements = s->fw_sge;
-    info->max_request_size = 8192;
+    info->max_request_size = MEGASAS_MAX_SECTORS;
     info->lds_present = num_ld_disks;
     info->pd_present = num_ld_disks + 1;
     info->pd_disks_present = num_ld_disks;
@@ -529,9 +565,9 @@ static int megasas_ctrl_get_info(MPTState *s, struct 
megasas_cmd_t *cmd)
         MFI_INFO_LDOPS_IO_POLICY |
         MFI_INFO_LDOPS_WRITE_POLICY |
         MFI_INFO_LDOPS_READ_POLICY;
-    info->max_strips_per_io = 42;
-    info->stripe_sz_ops.min = 4;
-    info->stripe_sz_ops.max = 0xf;
+    info->max_strips_per_io = s->fw_sge;
+    info->stripe_sz_ops.min = 3;
+    info->stripe_sz_ops.max = ffs(MEGASAS_MAX_SECTORS + 1) - 1;
     info->properties.pred_fail_poll_interval = 300;
     info->properties.intr_throttle_cnt = 16;
     info->properties.intr_throttle_timeout = 50;
@@ -564,7 +600,7 @@ static int megasas_mfc_get_defaults(MPTState *s, struct 
megasas_cmd_t *cmd)
        return MFI_STAT_INVALID_PARAMETER;
     }
 
-    info->stripe_size = 8;
+    info->stripe_size = 3;
     info->flush_time = 4;
     info->background_rate = 30;
     info->allow_mix_in_enclosure = 1;
@@ -867,7 +903,7 @@ static int megasas_dcmd_ld_get_info(MPTState *s, struct 
megasas_cmd_t *cmd)
     info->ld_config.properties.ld.v.target_id = ld_id;
 
     if (sdev) {
-       info->ld_config.params.stripe_size = 64;
+       info->ld_config.params.stripe_size = 3;
        info->ld_config.params.num_drives = 1;
        info->ld_config.params.state = MFI_LD_STATE_OFFLINE;
        info->ld_config.params.is_consistent = 1;
@@ -892,8 +928,7 @@ static int megasas_dcmd_get_properties(MPTState *s, struct 
megasas_cmd_t *cmd)
     }
 
 #ifdef DEBUG_MEGASAS_DCMD
-    DPRINTF("DCMD get properties: xfer_len %d sge_count %d\n",
-           cmd->frame->header.data_len, cmd->frame->header.sge_count);
+    DPRINTF("DCMD get properties\n");
 #endif
     info->pred_fail_poll_interval = 300;
     info->intr_throttle_cnt = 16;
@@ -934,23 +969,10 @@ static int megasas_ctrl_shutdown(MPTState *s, struct 
megasas_cmd_t *cmd)
 static int megasas_dcmd_set_properties(MPTState *s, struct megasas_cmd_t *cmd)
 {
     uint8_t *dummy;
-    target_phys_addr_t iov_pa;
-    uint32_t iov_size;
-    int is_sgl64 = (cmd->frame->header.flags & MFI_FRAME_SGL64) ? 1 : 0;
 
 #ifdef DEBUG_MEGASAS_DCMD
-    DPRINTF("DCMD get properties: xfer_len %d sge_count %d\n",
-           cmd->frame->header.data_len, cmd->frame->header.sge_count);
+    DPRINTF("DCMD set properties\n");
 #endif
-    if (is_sgl64) {
-       iov_pa = le64_to_cpu(cmd->frame->dcmd.sgl.sg64[0].addr);
-       iov_size = le32_to_cpu(cmd->frame->dcmd.sgl.sg64[0].len);
-    } else {
-       iov_pa = le32_to_cpu(cmd->frame->dcmd.sgl.sg32[0].addr);
-       iov_size = le32_to_cpu(cmd->frame->dcmd.sgl.sg32[0].len);
-    }
-
-    cpu_physical_memory_read(iov_pa, cmd->iov_buf, 64);
     dummy = cmd->iov_buf;
     DPRINTF("Properties dump\n");
     DPRINTF("%02x %02x %02x %0x2 %02x %02x %02x %02x\n",
@@ -983,10 +1005,9 @@ static int megasas_dcmd_set_properties(MPTState *s, 
struct megasas_cmd_t *cmd)
 static int megasas_dcmd_dummy(MPTState *s, struct megasas_cmd_t *cmd)
 {
 #ifdef DEBUG_MEGASAS_DCMD
-    DPRINTF("DCMD dummy: xfer_len %d sge_count %d\n",
-           cmd->frame->header.data_len, cmd->frame->header.sge_count);
+    DPRINTF("DCMD dummy: xfer_len %ld\n", cmd->iov_size);
 #endif
-    memset(cmd->iov_buf, 0, cmd->frame->header.data_len);
+    memset(cmd->iov_buf, 0, cmd->iov_size);
 
     return MFI_STAT_OK;
 }
@@ -1146,7 +1167,7 @@ static int megasas_handle_scsi(MPTState *s, struct 
megasas_cmd_t *cmd, int is_lo
                cmd->frame->header.target_id, cmd->frame->header.lun_id,
                cmd->frame->header.cdb_len);
        megasas_build_sense(cmd, SENSE_CODE(INVALID_OPCODE));
-       megasas_frame_set_scsi_status(cmd->pa, CHECK_CONDITION);
+       megasas_frame_set_scsi_status(cmd->pa, CHECK_CONDITION << 1);
        s->event_count++;
        return MFI_STAT_SCSI_DONE_WITH_ERROR;
     }
@@ -1157,7 +1178,6 @@ static int megasas_handle_scsi(MPTState *s, struct 
megasas_cmd_t *cmd, int is_lo
     if (cmd->frame->header.data_len != cmd->req->cmd.xfer) {
        DPRINTF("xfer length mismatch, frame %u cdb %u\n",
                cmd->frame->header.data_len, (unsigned)cmd->req->cmd.xfer);
-       cmd->frame->header.data_len = cmd->req->cmd.xfer;
        s->event_count++;
     }
 
@@ -1202,7 +1222,7 @@ static int megasas_handle_io(MPTState *s, struct 
megasas_cmd_t *cmd)
                cmd->frame->header.target_id, cmd->frame->header.lun_id,
                cmd->frame->header.cdb_len);
        megasas_build_sense(cmd, SENSE_CODE(INVALID_OPCODE));
-       megasas_frame_set_scsi_status(cmd->pa, CHECK_CONDITION);
+       megasas_frame_set_scsi_status(cmd->pa, CHECK_CONDITION << 1);
        s->event_count++;
        return MFI_STAT_SCSI_DONE_WITH_ERROR;
     }
@@ -1263,7 +1283,7 @@ static void megasas_command_complete(SCSIRequest *req)
                mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd, 
cmd->sdev,
                req->status, (unsigned)req->xferlen);
 #endif
-       if (req->status == CHECK_CONDITION) {
+       if (req->status == CHECK_CONDITION << 1) {
            megasas_build_sense(cmd, cmd->sdev->sense);
            cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
            scsi_dev_clear_sense(cmd->sdev);
@@ -1317,7 +1337,7 @@ static void megasas_handle_frame(MPTState *s, 
target_phys_addr_t frame_addr,
 {
     uint8_t frame_cmd;
     uint8_t frame_status = MFI_STAT_INVALID_CMD;
-    uint32_t frame_context = 0;
+    uint32_t frame_context;
     struct megasas_cmd_t *cmd;
 
     frame_cmd = megasas_frame_get_cmd(frame_addr);
@@ -1331,7 +1351,7 @@ static void megasas_handle_frame(MPTState *s, 
target_phys_addr_t frame_addr,
     cmd = megasas_enqueue_frame(s, frame_addr);
     if (!cmd) {
        /* reply queue full */
-       megasas_frame_set_scsi_status(frame_addr, BUSY);
+       megasas_frame_set_scsi_status(frame_addr, BUSY << 1);
        frame_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
        s->event_count++;
        goto frame_done;
@@ -1466,7 +1486,7 @@ static void megasas_mmio_writel(void *opaque, 
target_phys_addr_t addr,
        case MFI_ODCR0:
            /* Update reply queue pointer */
 #ifdef DEBUG_MEGASAS_QUEUE
-           DPRINTF("Update reply queue head %d busy %d\n",
+           DPRINTF("Update reply queue head %x busy %d\n",
                    s->reply_queue_index, s->busy);
 #endif
            stl_phys(s->producer_pa, s->reply_queue_index);
@@ -1651,6 +1671,17 @@ static void megasas_queue_mapfunc(PCIDevice *pci_dev, 
int region_num,
     s->event_count++;
 }
 
+static void megasas_scsi_reset(DeviceState *dev)
+{
+    MPTState *s = DO_UPCAST(MPTState, dev.qdev, dev);
+    int i;
+
+    for (i = 0; i <= s->fw_cmds; i++)
+           megasas_abort_command(&s->frames[i]);
+
+    megasas_soft_reset(s);
+}
+
 static void megasas_scsi_save(QEMUFile *f, void *opaque)
 {
     MPTState *s = opaque;
@@ -1748,12 +1779,11 @@ static int megasas_scsi_init(PCIDevice *dev)
     s->consumer_pa = 0;
     for (i = 0; i < s->fw_cmds; i++) {
        s->frames[i].index = i;
+       s->frames[i].context = -1;
        s->frames[i].pa = 0;
        s->frames[i].state = s;
     }
 
-    megasas_soft_reset(s);
-
     scsi_bus_new(&s->bus, &dev->qdev, 1, s->fw_luns, megasas_command_complete);
     scsi_bus_legacy_handle_cmdline(&s->bus);
     register_savevm("megasas", -1, 0, megasas_scsi_save, megasas_scsi_load, s);
@@ -1764,11 +1794,14 @@ static PCIDeviceInfo megasas_info = {
     .qdev.name  = "LSI MegaRAID SAS 1078",
     .qdev.alias = "megasas",
     .qdev.size  = sizeof(MPTState),
+    .qdev.reset = megasas_scsi_reset,
     .init       = megasas_scsi_init,
     .exit       = megasas_scsi_uninit,
     .qdev.props = (Property[]) {
-       DEFINE_PROP_UINT32("max_sge", MPTState, fw_sge, MEGASAS_DEFAULT_SGE),
-       DEFINE_PROP_UINT32("max_cmds", MPTState, fw_cmds, 
MEGASAS_DEFAULT_FRAMES),
+       DEFINE_PROP_UINT32("max_sge", MPTState, fw_sge,
+                          MEGASAS_DEFAULT_SGE),
+       DEFINE_PROP_UINT32("max_cmds", MPTState, fw_cmds,
+                          MEGASAS_DEFAULT_FRAMES),
        DEFINE_PROP_STRING("mode", MPTState, raid_mode_str),
        DEFINE_PROP_END_OF_LIST(),
     },
diff --git a/hw/mfi.h b/hw/mfi.h
index 90334b1..cc71af3 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -489,6 +489,7 @@ union mfi_frame {
        struct mfi_abort_frame  abort;
        struct mfi_smp_frame    smp;
        struct mfi_stp_frame    stp;
+       uint64_t                raw[8];
        uint8_t                 bytes[MFI_FRAME_SIZE];
 };
 
-- 
1.6.6.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]