Patchwork [7/7] megasas: Update to 1.10

login
register
mail settings
Submitter Hannes Reinecke
Date June 15, 2010, 3:16 p.m.
Message ID <20100615151638.12D1C2B964@ochil.suse.de>
Download mbox | patch
Permalink /patch/55732/
State New
Headers show

Comments

Hannes Reinecke - June 15, 2010, 3:16 p.m.
This patchset updates the megasas HBA emulation to version 1.10.
The main changes are:
- Range checking for IO vecs and frames
- Fixed frame address and frame count resolution
- Unmap existing frames on reset
- Round sge size to nearest power-of-two value

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 hw/megasas.c |  148 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 74 insertions(+), 74 deletions(-)
Nicholas A. Bellinger - June 16, 2010, 9:01 a.m.
On Tue, 2010-06-15 at 17:16 +0200, Hannes Reinecke wrote:
> This patchset updates the megasas HBA emulation to version 1.10.
> The main changes are:
> - Range checking for IO vecs and frames
> - Fixed frame address and frame count resolution
> - Unmap existing frames on reset
> - Round sge size to nearest power-of-two value
> 
> Signed-off-by: Hannes Reinecke <hare@suse.de>
> ---
>  hw/megasas.c |  148 +++++++++++++++++++++++++++++-----------------------------
>  1 files changed, 74 insertions(+), 74 deletions(-)
> 

Commited and pushed,  thank you Dr. Hannes!

--nab

Patch

diff --git a/hw/megasas.c b/hw/megasas.c
index a75872b..506a450 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -70,10 +70,10 @@  do { fprintf(stderr, "megasas: error: " fmt , ## __VA_ARGS__);} while (0)
 #endif
 
 /* Static definitions */
-#define MEGASAS_VERSION "1.02"
+#define MEGASAS_VERSION "1.10"
 #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_MAX_SGE 256             /* Firmware limit */
 #define MEGASAS_DEFAULT_SGE 80
 #define MEGASAS_MAX_SECTORS 0xFFFF      /* No real limit */
 #define MEGASAS_MAX_ARRAYS 128
@@ -85,8 +85,10 @@  const char *mfi_frame_desc[] = {
 struct megasas_cmd_t {
     int index;
     int context;
+    int count;
 
     target_phys_addr_t pa;
+    target_phys_addr_t pa_size;
     union mfi_frame *frame;
     SCSIRequest *req;
     QEMUSGList sg;
@@ -136,9 +138,6 @@  typedef struct megasas_state_t {
 #define megasas_frame_set_cmd_status(f,v)		\
     stb_phys((f) + offsetof(struct mfi_frame_header, cmd_status), v);
 
-#define megasas_frame_set_sense_len(f,v)		\
-    stb_phys((f) + offsetof(struct mfi_frame_header, sense_len), v);
-
 #define megasas_frame_set_scsi_status(f,v)		\
     stb_phys((f) + offsetof(struct mfi_frame_header, scsi_status), v);
 
@@ -156,18 +155,30 @@  static void megasas_map_sgl(struct megasas_cmd_t *cmd, int pa_offset)
     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);
+    size_t iov_count = 0;
 
     qemu_sglist_init(&cmd->sg, cmd->frame->header.sge_count);
     for (i = 0; i < cmd->frame->header.sge_count; i++) {
-        target_phys_addr_t pa, iov_pa;
+        target_phys_addr_t pa, iov_pa, iov_size;
 
         pa = cmd->pa + pa_offset;
         if (is_sgl64)
             iov_pa = ldq_phys(pa);
         else
             iov_pa = ldl_phys(pa);
-        qemu_sglist_add(&cmd->sg, iov_pa, ldl_phys(pa + sgl_addr_size));
+        iov_size = ldl_phys(pa + sgl_addr_size);
+        qemu_sglist_add(&cmd->sg, iov_pa, iov_size);
         pa_offset += sgl_addr_size + sizeof(uint32_t);
+        iov_count += iov_size;
+    }
+    if (pa_offset > (cmd->count + 1) * MFI_FRAME_SIZE) {
+        DPRINTF("frame %d: iov list overflow count %d sge %d offset %x\n",
+                cmd->context, cmd->count, cmd->frame->header.sge_count,
+                pa_offset);
+    }
+    if (iov_count > cmd->iov_size * cmd->sdev->blocksize) {
+        DPRINTF("iov list too long: is %ld should be %ld\n",
+                iov_count, cmd->iov_size * cmd->sdev->blocksize);
     }
 }
 
@@ -275,10 +286,10 @@  static uint64_t megasas_gen_sas_addr(uint64_t id)
 
 static void megasas_dump_frame(struct megasas_cmd_t *cmd)
 {
-    DPRINTF("Frame %x: p%p context %x\n"
+    DPRINTF("Frame %x: count %d pa %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,
+            cmd->index, cmd->count, 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]),
@@ -326,9 +337,6 @@  static inline struct megasas_cmd_t *megasas_next_frame(MPTState *s,
     cmd = megasas_lookup_frame(s, frame);
     if (cmd) {
         DPRINTF_QUEUE("Found mapped frame %x pa %lx\n", cmd->index, cmd->pa);
-        if (cmd->context != -1)
-            DPRINTF("Frame %x context %x not finished\n",
-                    cmd->index, cmd->context);
         return cmd;
     }
     index = s->reply_queue_index;
@@ -346,10 +354,10 @@  static inline struct megasas_cmd_t *megasas_next_frame(MPTState *s,
 }
 
 static struct megasas_cmd_t *
-megasas_enqueue_frame(MPTState *s, target_phys_addr_t frame)
+megasas_enqueue_frame(MPTState *s, target_phys_addr_t frame, int count)
 {
     struct megasas_cmd_t *cmd = NULL;
-    uint8_t frame_size = sizeof(cmd->frame);
+    uint8_t frame_size = MFI_FRAME_SIZE;
     target_phys_addr_t frame_size_p = frame_size;
 
     cmd = megasas_next_frame(s, frame);
@@ -369,19 +377,15 @@  megasas_enqueue_frame(MPTState *s, target_phys_addr_t frame)
             s->event_count++;
             return NULL;
         }
+        cmd->pa_size = frame_size_p;
+        cmd->context = le32_to_cpu(cmd->frame->header.context);
     }
-
-    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;
-    }
+    cmd->count = count;
     s->busy++;
 
-    DPRINTF_QUEUE("Enqueue frame %x context %x tail %x busy %d\n",
-                  cmd->index, cmd->context, s->reply_queue_index, s->busy);
+    DPRINTF_QUEUE("Enqueue frame %x count %d context %x tail %x busy %d\n",
+                  cmd->index, cmd->count, cmd->context,
+                  s->reply_queue_index, s->busy);
 
     return cmd;
 }
@@ -413,21 +417,6 @@  static void megasas_dequeue_frame(MPTState *s, int context)
     }
 }
 
-static int megasas_finish_command(MPTState *s, struct megasas_cmd_t *cmd)
-{
-    int context = -1;
-
-    if (!cmd) {
-        DPRINTF_QUEUE("No frame to complete\n");
-        s->event_count++;
-        return -1;
-    }
-    context = cmd->context;
-    cmd->context = -1;
-
-    return context;
-}
-
 static void megasas_abort_command(struct megasas_cmd_t *cmd)
 {
     if (cmd->req) {
@@ -1126,12 +1115,12 @@  static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd, int is_lo
     if (cmd->frame->header.target_id < s->fw_luns) {
         cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
     }
-
+    cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
     DPRINTF_IO("%s %s dev %x lun %x sdev %p xfer %d\n",
                mfi_frame_desc[cmd->frame->header.frame_cmd],
                is_logical ? "logical" : "physical",
                cmd->frame->header.target_id, cmd->frame->header.lun_id,
-               cmd->sdev, cmd->frame->header.data_len);
+               cmd->sdev, cmd->iov_size);
 
     if (!cmd->sdev || (s->is_jbod && is_logical)) {
         DPRINTF_IO("%s %s dev %x/%x target not present\n",
@@ -1153,10 +1142,10 @@  static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd, int is_lo
         return MFI_STAT_SCSI_DONE_WITH_ERROR;
     }
 
-    cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.context, cmd->frame->header.lun_id);
+    cmd->req = scsi_req_get(cmd->sdev, cmd->context, cmd->frame->header.lun_id);
     cmd->req->hba_private = cmd;
     scsi_req_parse(cmd->req, cdb);
-    if (cmd->frame->header.data_len != cmd->req->cmd.xfer) {
+    if (cmd->iov_size != cmd->req->cmd.xfer) {
         DPRINTF("xfer length mismatch, frame %u cdb %u\n",
                 cmd->frame->header.data_len, (unsigned)cmd->req->cmd.xfer);
         s->event_count++;
@@ -1182,6 +1171,8 @@  static int megasas_handle_io(MPTState *s, struct megasas_cmd_t *cmd)
     if (cmd->frame->header.target_id < s->fw_luns) {
         cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
     }
+    cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len) *
+        cmd->sdev->blocksize;
 
     DPRINTF_IO("%s dev %x lun %x lba %lx count %lx\n",
                mfi_frame_desc[cmd->frame->header.frame_cmd],
@@ -1205,11 +1196,16 @@  static int megasas_handle_io(MPTState *s, struct megasas_cmd_t *cmd)
         return MFI_STAT_SCSI_DONE_WITH_ERROR;
     }
 
-    cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.context, cmd->frame->header.lun_id);
+    cmd->req = scsi_req_get(cmd->sdev, cmd->context, cmd->frame->header.lun_id);
     cmd->req->hba_private = cmd;
-    megasas_map_sgl(cmd, offsetof(struct mfi_io_frame, sgl));
-
     scsi_req_setup(cmd->req, write, lba_start, lba_count);
+    if (cmd->iov_size != cmd->req->cmd.xfer) {
+        DPRINTF("xfer length mismatch, frame %lu cdb %lu\n",
+                cmd->iov_size * cmd->sdev->blocksize,
+                (unsigned long)cmd->req->cmd.xfer);
+        s->event_count++;
+    }
+    megasas_map_sgl(cmd, offsetof(struct mfi_io_frame, sgl));
     scsi_req_sgl(cmd->req, &cmd->sg);
 
     return MFI_STAT_INVALID_STATUS;
@@ -1234,7 +1230,6 @@  static void megasas_command_complete(SCSIRequest *req)
 {
     struct megasas_cmd_t *cmd;
     uint8_t cmd_status = MFI_STAT_OK;
-    int context;
 
     cmd = req->hba_private;
     if (!cmd) {
@@ -1267,17 +1262,12 @@  static void megasas_command_complete(SCSIRequest *req)
         }
 
         megasas_unmap_sgl(cmd);
-        megasas_frame_set_scsi_status(cmd->pa, cmd->req->status);
+        cmd->frame->header.scsi_status = req->status;
         scsi_req_put(cmd->req);
         cmd->req = NULL;
     }
-    context = megasas_finish_command(cmd->state, cmd);
-    if (context == -1) {
-        DPRINTF("Invalid context for cmd %p\n", cmd);
-    } else {
-        megasas_frame_set_cmd_status(cmd->pa, cmd_status);
-        megasas_dequeue_frame(cmd->state, context);
-    }
+    cmd->frame->header.cmd_status = cmd_status;
+    megasas_dequeue_frame(cmd->state, cmd->context);
 }
 
 static int megasas_handle_abort(MPTState *s, struct megasas_cmd_t *cmd)
@@ -1296,9 +1286,9 @@  static int megasas_handle_abort(MPTState *s, struct megasas_cmd_t *cmd)
         s->event_count++;
         return MFI_STAT_OK;
     }
-    if (abort_cmd->frame->header.context != abort_ctx) {
+    if (abort_cmd->context != abort_ctx) {
         DPRINTF("abort frame %x: invalid context %x\n", abort_cmd->index,
-                abort_cmd->frame->header.context);
+                abort_cmd->context);
         s->event_count++;
         return MFI_STAT_ABORT_NOT_POSSIBLE;
     }
@@ -1323,13 +1313,14 @@  static void megasas_handle_frame(MPTState *s, target_phys_addr_t frame_addr,
     DPRINTF_MFI("MFI cmd %x context %x count %d\n",
                 frame_cmd, frame_context, frame_count);
 
-    cmd = megasas_enqueue_frame(s, frame_addr);
+    cmd = megasas_enqueue_frame(s, frame_addr, frame_count);
     if (!cmd) {
         /* reply queue full */
         megasas_frame_set_scsi_status(frame_addr, BUSY);
-        frame_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
+        megasas_frame_set_cmd_status(frame_addr, MFI_STAT_SCSI_DONE_WITH_ERROR);
+        megasas_dequeue_frame(s, frame_context);
         s->event_count++;
-        goto frame_done;
+        return;
     }
     switch (cmd->frame->header.frame_cmd) {
         case MFI_CMD_INIT:
@@ -1357,11 +1348,9 @@  static void megasas_handle_frame(MPTState *s, target_phys_addr_t frame_addr,
             s->event_count++;
             break;
     }
-frame_done:
     if (frame_status != MFI_STAT_INVALID_STATUS) {
-        megasas_frame_set_cmd_status(frame_addr, frame_status);
-        megasas_finish_command(s, cmd);
-        megasas_dequeue_frame(s, frame_context);
+        cmd->frame->header.cmd_status = frame_status;
+        megasas_dequeue_frame(s, cmd->context);
     }
 }
 
@@ -1459,12 +1448,12 @@  static void megasas_mmio_writel(void *opaque, target_phys_addr_t addr,
             break;
         case MFI_IQPL:
         case MFI_IQP:
-            /* Received MFI frames; up to 8 contiguous frames */
-            frame_addr = (val & ~0xF);
+            /* Received MFI frame address */
+            frame_addr = (val & ~0xFF);
             /* Add possible 64 bit offset */
             frame_addr |= (uint64_t)s->frame_hi;
             s->frame_hi = 0;
-            frame_count = (val >> 1) & 0x7;
+            frame_count = (val >> 1) & 0x7F;
             DPRINTF_MFI("Received frame addr %lx count %d\n",
                         (unsigned long)frame_addr, frame_count);
             megasas_handle_frame(s, frame_addr, frame_count);
@@ -1559,8 +1548,19 @@  static CPUWriteMemoryFunc * const megasas_queue_writefn[3] = {
 
 static void megasas_soft_reset(MPTState *s)
 {
-    DPRINTF("Reset\n");
+    int i;
+    struct megasas_cmd_t *cmd;
 
+    DPRINTF("Reset\n");
+    for (i = 0; i <= s->fw_cmds; i++) {
+        cmd = &s->frames[i];
+        megasas_abort_command(cmd);
+        if (cmd->frame) {
+            cpu_physical_memory_unmap(cmd->frame, cmd->pa_size, 0, 0);
+            cmd->frame = NULL;
+            cmd->pa = 0;
+        }
+    }
     s->reply_queue_len = 0;
     s->reply_queue_pa = 0;
     s->consumer_pa = 0;
@@ -1611,10 +1611,6 @@  static void megasas_queue_mapfunc(PCIDevice *pci_dev, int region_num,
 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);
 }
@@ -1698,8 +1694,12 @@  static int megasas_scsi_init(PCIDevice *dev)
                            PCI_BASE_ADDRESS_SPACE_IO, megasas_io_mapfunc);
     pci_register_bar((struct PCIDevice *)s, 3, 0x40000,
                            PCI_BASE_ADDRESS_SPACE_MEMORY, megasas_queue_mapfunc);
-    if (s->fw_sge > MEGASAS_MAX_SGE) {
-        s->fw_sge = MEGASAS_MAX_SGE;
+    if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
+        s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
+    } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
+        s->fw_sge = 128 - MFI_PASS_FRAME_SIZE;
+    } else {
+        s->fw_sge = 64 - MFI_PASS_FRAME_SIZE;
     }
     if (s->fw_cmds > MEGASAS_MAX_FRAMES) {
         s->fw_cmds = MEGASAS_MAX_FRAMES;