diff mbox

[2/7] megasas: Update to 1.02

Message ID 20100615151613.24B7E2B964@ochil.suse.de
State New
Headers show

Commit Message

Hannes Reinecke June 15, 2010, 3:16 p.m. UTC
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 <hare@suse.de>
---
 hw/megasas.c |  155 +++++++++++++++++++++++++++++++++++-----------------------
 hw/mfi.h     |    1 +
 2 files changed, 95 insertions(+), 61 deletions(-)

Comments

Nicholas A. Bellinger June 16, 2010, 8:57 a.m. UTC | #1
On Tue, 2010-06-15 at 17:16 +0200, Hannes Reinecke wrote:
> 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 <hare@suse.de>
> ---
>  hw/megasas.c |  155 +++++++++++++++++++++++++++++++++++-----------------------
>  hw/mfi.h     |    1 +
>  2 files changed, 95 insertions(+), 61 deletions(-)
> 

Commited, Thanks!

--nab
diff mbox

Patch

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];
 };