[Top][All Lists]
[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
- [Qemu-devel] [PATCH 2/7] megasas: Update to 1.02,
Hannes Reinecke <=