[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 7/7] megasas: Update to 1.10
From: |
Hannes Reinecke |
Subject: |
[Qemu-devel] [PATCH 7/7] megasas: Update to 1.10 |
Date: |
Tue, 15 Jun 2010 17:16:38 +0200 |
User-agent: |
Heirloom mailx 12.2 01/07/07 |
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 <address@hidden>
---
hw/megasas.c | 148 +++++++++++++++++++++++++++++-----------------------------
1 files changed, 74 insertions(+), 74 deletions(-)
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;
--
1.6.6.1
- [Qemu-devel] [PATCH 7/7] megasas: Update to 1.10,
Hannes Reinecke <=