From patchwork Tue Jun 15 15:16:38 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 55732 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C2BA6B7D5E for ; Wed, 16 Jun 2010 01:56:01 +1000 (EST) Received: from localhost ([127.0.0.1]:52860 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOYTI-0007Jl-Pk for incoming@patchwork.ozlabs.org; Tue, 15 Jun 2010 11:54:40 -0400 Received: from [140.186.70.92] (port=46687 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOXsW-0005gu-UC for qemu-devel@nongnu.org; Tue, 15 Jun 2010 11:16:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OOXsV-0002NE-5G for qemu-devel@nongnu.org; Tue, 15 Jun 2010 11:16:40 -0400 Received: from cantor2.suse.de ([195.135.220.15]:44914 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OOXsU-0002N7-Kq for qemu-devel@nongnu.org; Tue, 15 Jun 2010 11:16:39 -0400 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.221.2]) by mx2.suse.de (Postfix) with ESMTP id 31FFD89FC6; Tue, 15 Jun 2010 17:16:38 +0200 (CEST) Date: Tue, 15 Jun 2010 17:16:38 +0200 To: Nicholas A.Bellinger User-Agent: Heirloom mailx 12.2 01/07/07 MIME-Version: 1.0 Message-Id: <20100615151638.12D1C2B964@ochil.suse.de> From: hare@suse.de (Hannes Reinecke) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH 7/7] megasas: Update to 1.10 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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;