[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] megasas: Update to version 1.01
From: |
Hannes Reinecke |
Subject: |
[Qemu-devel] [PATCH] megasas: Update to version 1.01 |
Date: |
Tue, 08 Jun 2010 16:15:06 +0200 |
User-agent: |
Heirloom mailx 12.2 01/07/07 |
This patch updates the megasas HBA emulation to version 1.01.
It fixes the following issues:
- Remove hand-crafted inquiry command
- Remove bounce-buffer for direct commands
- Implements qdev properties to set 'max_sge', 'max_cmds'.
- Implement JBOD mode
- Improve direct command handling
- Minor cleanups
Signed-off-by: Hannes Reinecke <address@hidden>
diff --git a/hw/megasas.c b/hw/megasas.c
index 250c3fb..19569a8 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -40,38 +40,17 @@ do { fprintf(stderr, "megasas: error: " fmt , ##
__VA_ARGS__);} while (0)
#endif
/* Static definitions */
-#define MEGASAS_MAX_FRAMES 1000
-#define MEGASAS_MAX_SGE 8
-#define MEGASAS_MAX_LUNS 128
-
-/* Frame definitions */
-#define MEGASAS_FRAME_CMD_OFFSET 0x00
-#define MEGASAS_FRAME_SENSE_LEN_OFFSET 0x01
-#define MEGASAS_FRAME_CMD_STATUS_OFFSET 0x02
-#define MEGASAS_FRAME_SCSI_STATUS_OFFSET 0x03
-#define MEGASAS_FRAME_TARGET_ID_OFFSET 0x04
-#define MEGASAS_FRAME_LUN_ID_OFFSET 0x05
-#define MEGASAS_FRAME_CDB_LEN_OFFSET 0x06
-#define MEGASAS_FRAME_SGE_COUNT_OFFSET 0x07
-#define MEGASAS_FRAME_CONTEXT_OFFSET 0x08
-#define MEGASAS_FRAME_FLAGS_OFFSET 0x10
-#define MEGASAS_FRAME_XFER_LEN_OFFSET 0x14
-
-#define MEGASAS_DCMD_SGL_OFFSET 0x28
-
-#define MEGASAS_PTHRU_SGL_OFFSET 0x30
-
-#define MEGASAS_IO_SGL_OFFSET 0x28
+#define MEGASAS_VERSION "1.01"
+#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_ARRAYS 128
const char *mfi_frame_desc[] = {
"MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI",
"MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"};
-struct megasas_lun_t {
- SCSIDevice *sdev;
- BlockDriverAIOCB *aiocb;
-};
-
struct megasas_cmd_t {
int index;
@@ -81,8 +60,8 @@ struct megasas_cmd_t {
QEMUSGList sg;
void *iov_buf;
long iov_size;
+ SCSIDevice *sdev;
struct megasas_state_t *state;
- struct megasas_lun_t *lun;
};
typedef struct megasas_state_t {
@@ -93,12 +72,14 @@ typedef struct megasas_state_t {
uint32_t frame_hi;
int fw_state;
- int fw_sge;
- int fw_cmds;
+ uint32_t fw_sge;
+ uint32_t fw_cmds;
int fw_luns;
int intr_mask;
int doorbell;
int busy;
+ char *raid_mode_str;
+ int is_jbod;
int event_count;
int shutdown_event;
@@ -113,8 +94,6 @@ typedef struct megasas_state_t {
struct megasas_cmd_t frames[MEGASAS_MAX_FRAMES];
- struct megasas_lun_t luns[MEGASAS_MAX_LUNS];
-
SCSIBus bus;
} MPTState;
@@ -123,13 +102,19 @@ typedef struct megasas_state_t {
#define MEGASAS_INTR_ENABLED(s) (((s)->intr_mask & MEGASAS_INTR_DISABLED_MASK
) != MEGASAS_INTR_DISABLED_MASK)
#define megasas_frame_set_cmd_status(f,v) \
- stb_phys((f) + MEGASAS_FRAME_CMD_STATUS_OFFSET, v);
+ stb_phys((f) + offsetof(struct mfi_frame_header, cmd_status), v);
#define megasas_frame_set_sense_len(f,v) \
- stb_phys((f) + MEGASAS_FRAME_SENSE_LEN_OFFSET, v);
+ stb_phys((f) + offsetof(struct mfi_frame_header, sense_len), v);
#define megasas_frame_set_scsi_status(f,v) \
- stb_phys((f) + MEGASAS_FRAME_SCSI_STATUS_OFFSET, v);
+ stb_phys((f) + offsetof(struct mfi_frame_header, scsi_status), v);
+
+#define megasas_frame_get_cmd(f) \
+ ldub_phys((f) + offsetof(struct mfi_frame_header, frame_cmd))
+
+#define megasas_frame_get_context(f) \
+ ldl_phys(frame_addr + offsetof(struct mfi_frame_header, context));
static void megasas_soft_reset(MPTState *s);
@@ -181,37 +166,20 @@ static void megasas_build_sense(struct megasas_cmd_t
*cmd, SCSISense sense)
qemu_free(sense_ptr);
}
-static int megasas_get_inq(SCSIDevice *sdev, int pg, uint8_t *buf, int buflen)
-{
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
-
- memset(buf, 0, buflen);
- if (pg == 0) {
- memcpy(&buf[16], "QEMU HARDDISK ", 16);
- memcpy(&buf[8], "QEMU ", 8);
- memcpy(&buf[32], QEMU_VERSION, 4);
- /* Identify device as SCSI-3 rev 1 */
- buf[2] = 3;
- buf[3] = 2; /* Format 2 */
- buf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
- /* Sync data transfer and TCQ. */
- buf[7] = 0x10 | (bus->tcq ? 0x02 : 0);
- } else if (pg == 0x83) {
- int id_len = strlen(bdrv_get_device_name(sdev->conf.dinfo->bdrv));
-
- buflen = 0;
- buf[buflen++] = 0;
- buf[buflen++] = pg;
- buf[buflen++] = 0x00;
- buf[buflen++] = 3 + id_len;
- buf[buflen++] = 0x2; // ASCII
- buf[buflen++] = 0; // not officially assigned
- buf[buflen++] = 0; // reserved
- buf[buflen++] = id_len; // length of data following
- memcpy(buf + buflen, bdrv_get_device_name(sdev->conf.dinfo->bdrv),
id_len);
- buflen += id_len;
+static int megasas_setup_inquiry(SCSIRequest *req, int pg,
+ uint8_t *buf, int len)
+{
+ uint8_t cdb[6] = { INQUIRY, 0, 0, 0, 0, 0};
+
+ if (pg > 0) {
+ cdb[1] = 0x1;
+ cdb[2] = pg;
}
- return buflen;
+ cdb[3] = (len >> 8) & 0xff;
+ cdb[4] = (len & 0xff);
+ scsi_req_parse(req, cdb);
+ scsi_req_buf(req, buf);
+ return len;
}
/*
@@ -234,6 +202,16 @@ static uint64_t megasas_fw_time(void)
return bcd_time;
}
+static uint64_t megasas_gen_sas_addr(unsigned long id)
+{
+ uint64_t addr;
+
+ addr = ((uint64_t)0x5001a4a << 36);
+ addr |= ((uint64_t)id & 0xfffffffff);
+
+ return addr;
+}
+
/*
* Frame handling
*/
@@ -254,7 +232,7 @@ static inline struct megasas_cmd_t
*megasas_lookup_frame(MPTState *s,
index = s->reply_queue_index;
- while (num < MEGASAS_MAX_FRAMES) {
+ while (num < s->fw_cmds) {
if (s->frames[index].pa && s->frames[index].pa == frame) {
cmd = &s->frames[index];
break;
@@ -282,7 +260,7 @@ static inline struct megasas_cmd_t
*megasas_next_frame(MPTState *s,
}
index = s->reply_queue_index;
num = 0;
- while (num < MEGASAS_MAX_FRAMES) {
+ while (num < s->fw_cmds) {
if (!s->frames[index].pa) {
cmd = &s->frames[index];
break;
@@ -377,7 +355,7 @@ static void megasas_dump_frame(struct megasas_cmd_t *cmd)
static int megasas_finish_command(MPTState *s, struct megasas_cmd_t *cmd)
{
- int context;
+ int context = -1;
if (!cmd) {
#ifdef DEBUG_MEGASAS_QUEUE
@@ -386,8 +364,8 @@ static int megasas_finish_command(MPTState *s, struct
megasas_cmd_t *cmd)
s->event_count++;
return -1;
}
- context = cmd->frame->header.context;
- cmd->lun = NULL;
+ if (cmd->frame)
+ context = cmd->frame->header.context;
return context;
}
@@ -483,14 +461,14 @@ static int megasas_finish_dcmd(struct megasas_cmd_t *cmd,
uint32_t size)
}
cpu_physical_memory_unmap(cmd->iov_buf, cmd->iov_size, 1, size);
if (cmd->iov_size > size)
- stl_phys(cmd->pa + MEGASAS_DCMD_SGL_OFFSET + sgl_addr_size, size);
+ stl_phys(cmd->pa + offsetof(struct mfi_dcmd_frame,sgl) + sgl_addr_size,
size);
return size;
}
static int megasas_ctrl_get_info(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_ctrl_info info;
+ struct mfi_ctrl_info *info = cmd->iov_buf;
int n, num_ld_disks = 0;
for (n = 0; n < s->fw_luns; n++) {
@@ -498,134 +476,189 @@ static int megasas_ctrl_get_info(MPTState *s, struct
megasas_cmd_t *cmd)
num_ld_disks++;
}
- memset(&info, 0x0, sizeof(info));
- info.pci.vendor = PCI_VENDOR_ID_LSI_LOGIC;
- info.pci.device = PCI_DEVICE_ID_LSI_SAS1078;
- info.pci.subvendor = PCI_VENDOR_ID_LSI_LOGIC;
- info.pci.subdevice = 0x1013;
-
- info.host.type = MFI_INFO_HOST_PCIX;
- info.device.type = MFI_INFO_DEV_SAS3G;
- info.device.port_count = 2;
-
- memcpy(info.product_name,"MegaRAID SAS 8708EM2", 20);
- sprintf(info.package_version,"%s-QEMU", QEMU_VERSION);
- info.current_fw_time = megasas_fw_time();
- info.max_arms = 32;
- info.max_spans = 8;
- info.max_arrays = MEGASAS_MAX_LUNS;
- 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.lds_present = num_ld_disks;
- info.pd_present = num_ld_disks + 1;
- info.pd_disks_present = num_ld_disks;
- info.memory_size = 512;
- info.nvram_size = 32;
- info.flash_size = 16;
- info.raid_levels = MFI_INFO_RAID_0;
- info.adapter_ops = MFI_INFO_AOPS_RBLD_RATE |
+ memset(cmd->iov_buf, 0x0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_ctrl_info)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("Ctrl Get Info: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("MFI DCMD get controller info\n");
+#endif
+ info->pci.vendor = PCI_VENDOR_ID_LSI_LOGIC;
+ info->pci.device = PCI_DEVICE_ID_LSI_SAS1078;
+ info->pci.subvendor = PCI_VENDOR_ID_LSI_LOGIC;
+ info->pci.subdevice = 0x1013;
+
+ info->host.type = MFI_INFO_HOST_PCIX;
+ info->device.type = MFI_INFO_DEV_SAS3G;
+ info->device.port_count = 2;
+ info->device.port_addr[0] = megasas_gen_sas_addr((unsigned long)s);
+
+ memcpy(info->product_name,"MegaRAID SAS 8708EM2", 20);
+ sprintf(info->serial_number,"QEMU%08lx",(unsigned long)s & 0xFFFFFFFF);
+ sprintf(info->package_version,"%s-QEMU", QEMU_VERSION);
+ strcpy(info->image_component[0].name, "APP");
+ strcpy(info->image_component[0].version, MEGASAS_VERSION "-QEMU");
+ strcpy(info->image_component[0].build_date, __DATE__);
+ strcpy(info->image_component[0].build_time, __TIME__);
+ info->image_component_count = 1;
+ info->current_fw_time = megasas_fw_time();
+ info->max_arms = 32;
+ info->max_spans = 8;
+ info->max_arrays = MEGASAS_MAX_ARRAYS;
+ 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->lds_present = num_ld_disks;
+ info->pd_present = num_ld_disks + 1;
+ info->pd_disks_present = num_ld_disks;
+ info->hw_present = MFI_INFO_HW_NVRAM | MFI_INFO_HW_MEM | MFI_INFO_HW_FLASH;
+ info->memory_size = 512;
+ info->nvram_size = 32;
+ info->flash_size = 16;
+ info->raid_levels = MFI_INFO_RAID_0;
+ info->adapter_ops = MFI_INFO_AOPS_RBLD_RATE |
MFI_INFO_AOPS_SELF_DIAGNOSTIC |
MFI_INFO_AOPS_MIXED_ARRAY;
- info.ld_ops = MFI_INFO_LDOPS_DISK_CACHE_POLICY |
+ info->ld_ops = MFI_INFO_LDOPS_DISK_CACHE_POLICY |
MFI_INFO_LDOPS_ACCESS_POLICY |
MFI_INFO_LDOPS_IO_POLICY |
MFI_INFO_LDOPS_WRITE_POLICY |
MFI_INFO_LDOPS_READ_POLICY;
- info.stripe_sz_ops.min = 4;
- info.stripe_sz_ops.max = 0xf;
- info.properties.pred_fail_poll_interval = 300;
- info.properties.intr_throttle_cnt = 16;
- info.pd_ops = 0x3;
- info.pd_mix_support = MFI_INFO_PDMIX_SAS | MFI_INFO_PDMIX_LD;
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
+ info->max_strips_per_io = 42;
+ info->stripe_sz_ops.min = 4;
+ info->stripe_sz_ops.max = 0xf;
+ info->properties.pred_fail_poll_interval = 300;
+ info->properties.intr_throttle_cnt = 16;
+ info->properties.intr_throttle_timeout = 50;
+ info->properties.rebuild_rate = 30;
+ info->properties.patrol_read_rate = 30;
+ info->properties.bgi_rate = 30;
+ info->properties.cc_rate = 30;
+ info->properties.recon_rate = 30;
+ info->properties.cache_flush_interval = 4;
+ info->properties.spinup_drv_cnt = 2;
+ info->properties.spinup_delay = 6;
+ info->properties.ecc_bucket_size = 15;
+ info->properties.ecc_bucket_leak_rate = 1440;
+ info->properties.expose_encl_devices = 1;
+ info->pd_ops = MFI_INFO_PDOPS_FORCE_ONLINE | MFI_INFO_PDOPS_FORCE_OFFLINE;
+ info->pd_mix_support = MFI_INFO_PDMIX_SAS | MFI_INFO_PDMIX_SATA |
MFI_INFO_PDMIX_LD;
- return sizeof(info);
+ return MFI_STAT_OK;
}
static int megasas_mfc_get_defaults(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_defaults info;
+ struct mfi_defaults *info = cmd->iov_buf;
- memset(&info, 0x0, sizeof(info));
+ memset(cmd->iov_buf, 0x0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_defaults)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("MFC Get defaults: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
- info.stripe_size = 8;
- info.flush_time = 4;
- info.background_rate = 30;
- info.allow_mix_in_enclosure = 1;
- info.allow_mix_in_ld = 1;
- info.direct_pd_mapping = 1;
- info.bios_enumerate_lds = 1;
- info.disable_ctrl_r = 1;
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
+ info->stripe_size = 8;
+ info->flush_time = 4;
+ info->background_rate = 30;
+ info->allow_mix_in_enclosure = 1;
+ info->allow_mix_in_ld = 1;
+ info->direct_pd_mapping = 1;
+ info->bios_enumerate_lds = 1;
+ info->disable_ctrl_r = 1;
+ info->expose_enclosure_devices = 1;
+ info->disable_preboot_cli = 1;
+ info->cluster_disable = 1;
- return sizeof(info);
+ return MFI_STAT_OK;
}
-static int megasas_dcmd_get_bios_info(MPTState *d, struct megasas_cmd_t *cmd)
+static int megasas_dcmd_get_bios_info(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_bios_data info;
+ struct mfi_bios_data *info = cmd->iov_buf;
- memset(&info, 0x0, sizeof(info));
- info.continue_on_error = 1;
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
+ memset(cmd->iov_buf, 0x0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_bios_data)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("Get BIOS info: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+ info->continue_on_error = 1;
-return sizeof(info);
+ return MFI_STAT_OK;
}
-static int megasas_dcmd_get_fw_time(MPTState *d, struct megasas_cmd_t *cmd)
+static int megasas_dcmd_get_fw_time(MPTState *s, struct megasas_cmd_t *cmd)
{
uint64_t fw_time;
fw_time = megasas_fw_time();
- memcpy(cmd->iov_buf, (uint8_t *)&fw_time, sizeof(fw_time));
- return sizeof(fw_time);
+ memcpy(cmd->iov_buf, &fw_time, sizeof(fw_time));
+ return MFI_STAT_OK;
}
-static int megasas_dcmd_set_fw_time(MPTState *d, struct megasas_cmd_t *cmd)
+static int megasas_dcmd_set_fw_time(MPTState *s, struct megasas_cmd_t *cmd)
{
uint64_t fw_time;
+ memset(cmd->iov_buf, 0x0, cmd->iov_size);
memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
DPRINTF("set fw time %lx\n", fw_time);
fw_time = megasas_fw_time();
- memcpy(cmd->iov_buf, (uint8_t *)&fw_time, sizeof(fw_time));
-
- return sizeof(fw_time);
+ memcpy(cmd->iov_buf, &fw_time, sizeof(fw_time));
+ return MFI_STAT_OK;
}
-
static int megasas_event_info(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_evt_log_state info;
+ struct mfi_evt_log_state *info = cmd->iov_buf;
- memset(&info, 0, sizeof(info));
- info.newest_seq_num = s->event_count;
- info.shutdown_seq_num = s->shutdown_event;
- info.boot_seq_num = s->boot_event;
+ memset(info, 0, cmd->iov_size);
+ info->newest_seq_num = s->event_count;
+ info->shutdown_seq_num = s->shutdown_event;
+ info->boot_seq_num = s->boot_event;
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
-
- return sizeof(info);
+ return MFI_STAT_OK;
}
static int megasas_dcmd_pd_get_list(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_pd_list info;
- uint32_t offset, num_pd_disks = 0;
+ struct mfi_pd_list *info = cmd->iov_buf;
+ uint32_t offset, num_pd_disks = 0, max_luns;
uint16_t dev_id;
- memset(&info, 0x0, sizeof(info));
+ memset(cmd->iov_buf, 0, cmd->iov_size);
offset = 8;
- for (dev_id = 0; dev_id < s->fw_luns; dev_id++) {
+ if (cmd->iov_size < (offset + sizeof(struct mfi_pd_address))) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get list: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+
+ max_luns = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
+ if (max_luns > s->fw_luns)
+ max_luns = s->fw_luns;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get list: returning info for %d PDs\n", max_luns);
+#endif
+
+ for (dev_id = 0; dev_id < max_luns; dev_id++) {
SCSIDevice *sdev;
sdev = s->bus.devs[dev_id];
if (sdev) {
- info.addr[num_pd_disks].device_id = dev_id;
- info.addr[num_pd_disks].encl_device_id = dev_id;
+ info->addr[num_pd_disks].device_id = dev_id;
+ info->addr[num_pd_disks].encl_device_id = dev_id;
+ info->addr[num_pd_disks].sas_addr[0] =
megasas_gen_sas_addr((unsigned long)sdev);
num_pd_disks ++;
offset += sizeof(struct mfi_pd_address);
}
@@ -634,19 +667,87 @@ static int megasas_dcmd_pd_get_list(MPTState *s, struct
megasas_cmd_t *cmd)
DPRINTF("PD get list: %d PDs, size %d\n", num_pd_disks, offset);
#endif
- info.size = offset;
- info.count = num_pd_disks;
- memcpy(cmd->iov_buf, (uint8_t *)&info, offset);
+ info->size = offset;
+ info->count = num_pd_disks;
- return offset;
+ return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_pd_list_query(MPTState *s, struct megasas_cmd_t *cmd)
+{
+ uint16_t flags;
+
+ /* mbox0 contains flags */
+ flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD query list: flags %x\n", flags);
+#endif
+
+ if (flags == MR_PD_QUERY_TYPE_ALL || s->is_jbod)
+ return megasas_dcmd_pd_get_list(s, cmd);
+
+ return MFI_STAT_OK;
+}
+
+static int megasas_pd_get_info_submit(SCSIDevice * sdev, int lun,
+ struct megasas_cmd_t *cmd)
+{
+ struct mfi_pd_info * info = cmd->iov_buf;
+ SCSIRequest *req;
+
+ if (info->inquiry_data[4] == 0) {
+ /* Additional length is zero, resubmit */
+ req = scsi_req_get(sdev, (uint32_t) -1, lun);
+ if (!req)
+ return MFI_STAT_FLASH_ALLOC_FAIL;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get info submit std inquiry to dev %d\n", lun);
+#endif
+ req->hba_private = cmd;
+ megasas_setup_inquiry(req, 0, info->inquiry_data,
+ sizeof(info->inquiry_data));
+ return MFI_STAT_INVALID_STATUS;
+ } else if (info->vpd_page83[3] == 0) {
+ /* Additional length is zero, resubmit */
+ req = scsi_req_get(sdev, (uint32_t) -1, lun);
+ if (!req)
+ return MFI_STAT_FLASH_ALLOC_FAIL;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get info submit vpd inquiry to dev %d\n", lun);
+#endif
+ req->hba_private = cmd;
+ megasas_setup_inquiry(req, 0x83,(uint8_t *)info->vpd_page83,
+ sizeof(info->vpd_page83));
+ return MFI_STAT_INVALID_STATUS;
+ }
+
+ /* Finished, set FW state */
+ if (cmd->state->is_jbod)
+ info->fw_state = MFI_PD_STATE_SYSTEM;
+ else
+ info->fw_state = MFI_PD_STATE_ONLINE;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get info set state for dev %d to %x\n", lun, info->fw_state);
+#endif
+ return MFI_STAT_OK;
}
static int megasas_dcmd_pd_get_info(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_pd_info info;
+ struct mfi_pd_info *info = cmd->iov_buf;
uint64_t pd_size;
uint16_t pd_id;
SCSIDevice *sdev = NULL;
+ int retval = MFI_STAT_OK;
+
+ memset(cmd->iov_buf, 0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_pd_info)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("PD get info: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
/* mbox0 has the ID */
pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
@@ -655,64 +756,106 @@ static int megasas_dcmd_pd_get_info(MPTState *s, struct
megasas_cmd_t *cmd)
DPRINTF("PD get info for dev %d\n", pd_id);
#endif
sdev = s->bus.devs[pd_id];
- memset((uint8_t *)&info, 0x0, sizeof(info));
- info.ref.v.device_id = pd_id;
+ info->ref.v.device_id = pd_id;
if (sdev) {
- /* Submit inquiry */
- megasas_get_inq(sdev, 0, (uint8_t *)&info.inquiry_data,
- sizeof(info.inquiry_data));
- megasas_get_inq(sdev, 0x83, (uint8_t *)&info.vpd_page83,
- sizeof(info.vpd_page83));
- info.fw_state = 0;
- info.state.ddf.v.pd_type.in_vd = 1;
- info.state.ddf.v.pd_type.intf = 0x2;
+ info->state.ddf.v.pd_type.in_vd = 1;
+ info->state.ddf.v.pd_type.intf = 0x2;
bdrv_get_geometry(sdev->conf.dinfo->bdrv, &pd_size);
- info.raw_size = pd_size;
- info.non_coerced_size = pd_size;
- info.coerced_size = pd_size;
+ info->raw_size = pd_size;
+ info->non_coerced_size = pd_size;
+ info->coerced_size = pd_size;
+ info->fw_state = MFI_PD_STATE_OFFLINE;
+ info->path_info.count = 1;
+ info->path_info.sas_addr[0] = megasas_gen_sas_addr((unsigned long)sdev);
+ /* Submit inquiry */
+ retval = megasas_pd_get_info_submit(cmd->sdev, pd_id, cmd);
}
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
- return sizeof(info);
+ return retval;
}
static int megasas_dcmd_ld_get_list(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_ld_list info;
- uint32_t num_ld_disks = 0;
+ struct mfi_ld_list *info = cmd->iov_buf;
+ uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
uint64_t ld_size;
uint8_t n;
int offset;
- memset(&info, 0x0, sizeof(info));
- offset = 8;
- for (n = 0; n < s->fw_luns; n++) {
+ memset(cmd->iov_buf, 0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_ld_list)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("LD get list: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+
+ if (s->is_jbod)
+ max_ld_disks = 0;
+
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("LD get list: returning info for %d LDs\n", max_ld_disks);
+#endif
+ for (n = 0; n < max_ld_disks; n++) {
SCSIDevice *sdev;
sdev = s->bus.devs[n];
if (sdev) {
bdrv_get_geometry(sdev->conf.dinfo->bdrv, &ld_size);
ld_size *= 512;
- info.ld_list[num_ld_disks].ld.v.target_id = n;
- info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
- info.ld_list[num_ld_disks].size = ld_size;
+ info->ld_list[num_ld_disks].ld.v.target_id = n;
+ info->ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
+ info->ld_list[num_ld_disks].size = ld_size;
num_ld_disks ++;
offset += 18;
}
}
- info.ld_count = num_ld_disks;
- memcpy(cmd->iov_buf, (uint8_t *)&info, offset);
+ info->ld_count = num_ld_disks;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("LD get list: found %d LDs\n", num_ld_disks);
+#endif
+
+ return MFI_STAT_OK;
+}
+
+static int megasas_ld_get_info_submit(SCSIDevice * sdev, int lun,
+ struct megasas_cmd_t *cmd)
+{
+ struct mfi_ld_info * info = cmd->iov_buf;
+ SCSIRequest *req;
- return offset;
+ if (info->vpd_page83[3] == 0) {
+ req = scsi_req_get(sdev, (uint32_t) -1, lun);
+ if (!req)
+ return MFI_STAT_FLASH_ALLOC_FAIL;
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("LD get info submit vpd inquiry to dev %d\n", lun);
+#endif
+ req->hba_private = cmd;
+ megasas_setup_inquiry(req, 0x83,(uint8_t *)info->vpd_page83,
+ sizeof(info->vpd_page83));
+ return MFI_STAT_INVALID_STATUS;
+ }
+ info->ld_config.params.state = MFI_LD_STATE_OPTIMAL;
+ return MFI_STAT_OK;
}
static int megasas_dcmd_ld_get_info(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_ld_info info;
+ struct mfi_ld_info *info = cmd->iov_buf;
uint64_t ld_size;
uint16_t ld_id;
SCSIDevice *sdev = NULL;
+ int retval = MFI_STAT_OK;
+
+ memset(cmd->iov_buf, 0, cmd->iov_size);
+ if (cmd->iov_size != sizeof(struct mfi_ld_info)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("LD get info: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ return MFI_STAT_INVALID_PARAMETER;
+ }
/* mbox0 has the ID */
ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
@@ -721,51 +864,71 @@ static int megasas_dcmd_ld_get_info(MPTState *s, struct
megasas_cmd_t *cmd)
DPRINTF("LD get info for dev %d\n", ld_id);
#endif
sdev = s->bus.devs[ld_id];
- memset((void *)&info, 0x0, sizeof(info));
- info.ld_config.properties.ld.v.target_id = ld_id;
+ info->ld_config.properties.ld.v.target_id = ld_id;
if (sdev) {
- memcpy(&info.ld_config.properties.name, "QEMU HARDDISK ", 16);
- info.ld_config.params.stripe_size = 64;
- info.ld_config.params.num_drives = 1;
- info.ld_config.params.state = MFI_LD_STATE_OPTIMAL;
- info.ld_config.params.is_consistent = 1;
+ info->ld_config.params.stripe_size = 64;
+ info->ld_config.params.num_drives = 1;
+ info->ld_config.params.state = MFI_LD_STATE_OFFLINE;
+ info->ld_config.params.is_consistent = 1;
bdrv_get_geometry(sdev->conf.dinfo->bdrv, &ld_size);
- info.size = ld_size;
- megasas_get_inq(sdev, 0x83, (uint8_t *)&info.vpd_page83,
- sizeof(info.vpd_page83));
+ info->size = ld_size;
+ retval = megasas_ld_get_info_submit(cmd->sdev, ld_id, cmd);
}
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
- return sizeof(info);
+ return retval;
}
static int megasas_dcmd_get_properties(MPTState *s, struct megasas_cmd_t *cmd)
{
- struct mfi_ctrl_props info;
+ struct mfi_ctrl_props *info = cmd->iov_buf;
-#ifdef DEBUG_MEGASAS_MFI
+ if (cmd->iov_size != sizeof(struct mfi_ctrl_props)) {
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("DCMD get properties: invalid xfer_len %ld\n", cmd->iov_size);
+#endif
+ memset(cmd->iov_buf, 0, cmd->iov_size);
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+
+#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);
#endif
- info.pred_fail_poll_interval = 300;
- info.intr_throttle_cnt = 16;
- info.intr_throttle_timeout = 50;
- info.rebuild_rate = 30;
- info.patrol_read_rate = 30;
- info.bgi_rate = 30;
- info.cc_rate = 30;
- info.recon_rate = 30;
- info.cache_flush_interval = 4;
- info.spinup_drv_cnt = 2;
- info.spinup_delay = 6;
- info.ecc_bucket_size = 15;
- info.ecc_bucket_leak_rate = 1440;
- info.expose_encl_devices = 1;
-
- memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
-
- return sizeof(info);
+ info->pred_fail_poll_interval = 300;
+ info->intr_throttle_cnt = 16;
+ info->intr_throttle_timeout = 50;
+ info->rebuild_rate = 30;
+ info->patrol_read_rate = 30;
+ info->bgi_rate = 30;
+ info->cc_rate = 30;
+ info->recon_rate = 30;
+ info->cache_flush_interval = 4;
+ info->spinup_drv_cnt = 2;
+ info->spinup_delay = 6;
+ info->ecc_bucket_size = 15;
+ info->ecc_bucket_leak_rate = 1440;
+ info->expose_encl_devices = 1;
+
+ return MFI_STAT_OK;
+}
+
+static int megasas_cache_flush(MPTState *s, struct megasas_cmd_t *cmd)
+{
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("MFI DCMD Cache flush\n");
+#endif
+ qemu_aio_flush();
+ return MFI_STAT_OK;
+}
+
+static int megasas_ctrl_shutdown(MPTState *s, struct megasas_cmd_t *cmd)
+{
+#ifdef DEBUG_MEGASAS_DCMD
+ DPRINTF("MFI DCMD Controller shutdown\n");
+#endif
+ s->fw_state = MFI_FWSTATE_READY;
+ return MFI_STAT_OK;
}
static int megasas_dcmd_set_properties(MPTState *s, struct megasas_cmd_t *cmd)
@@ -814,7 +977,7 @@ static int megasas_dcmd_set_properties(MPTState *s, struct
megasas_cmd_t *cmd)
DPRINTF("%02x %02x %02x %0x2 %02x %02x %02x %02x\n",
dummy[0x38], dummy[0x39], dummy[0x3a], dummy[0x3b],
dummy[0x3c], dummy[0x3d], dummy[0x3e], dummy[0x3f]);
- return cmd->frame->header.data_len;
+ return MFI_STAT_OK;
}
static int megasas_dcmd_dummy(MPTState *s, struct megasas_cmd_t *cmd)
@@ -825,13 +988,67 @@ static int megasas_dcmd_dummy(MPTState *s, struct
megasas_cmd_t *cmd)
#endif
memset(cmd->iov_buf, 0, cmd->frame->header.data_len);
- return cmd->frame->header.data_len;
+ return MFI_STAT_OK;
}
+
+struct dcmd_cmd_tbl_t {
+ int opcode;
+ int (*func)(MPTState *s, struct megasas_cmd_t *cmd);
+} dcmd_cmd_tbl[] = {
+ {MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_GET_INFO, megasas_ctrl_get_info},
+ {MFI_DCMD_CTRL_GET_PROPERTIES, megasas_dcmd_get_properties},
+ {MFI_DCMD_CTRL_SET_PROPERTIES, megasas_dcmd_set_properties},
+ {MFI_DCMD_SPEAKER_GET, megasas_dcmd_dummy},
+ {MFI_DCMD_SPEAKER_ENABLE, megasas_dcmd_dummy},
+ {MFI_DCMD_SPEAKER_DISABLE, megasas_dcmd_dummy},
+ {MFI_DCMD_SPEAKER_SILENCE, megasas_dcmd_dummy},
+ {MFI_DCMD_SPEAKER_TEST, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_EVENT_GETINFO, megasas_event_info},
+ {MFI_DCMD_CTRL_EVENT_GET, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_EVENT_WAIT, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_SHUTDOWN, megasas_ctrl_shutdown},
+ {MFI_DCMD_HIBERNATE_SHUTDOWN, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_GET_TIME, megasas_dcmd_get_fw_time},
+ {MFI_DCMD_CTRL_SET_TIME, megasas_dcmd_set_fw_time},
+ {MFI_DCMD_CTRL_GET_BIOS_INFO, megasas_dcmd_get_bios_info},
+ {MFI_DCMD_CTRL_FACTORY_DEFAULTS, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_MFC_DEFAULTS_GET, megasas_mfc_get_defaults},
+ {MFI_DCMD_CTRL_MFC_DEFAULTS_SET, megasas_dcmd_dummy},
+ {MFI_DCMD_CTRL_CACHE_FLUSH, megasas_cache_flush},
+ {MFI_DCMD_PD_GET_LIST, megasas_dcmd_pd_get_list},
+ {MFI_DCMD_PD_LIST_QUERY, megasas_dcmd_pd_list_query},
+ {MFI_DCMD_PD_GET_INFO, megasas_dcmd_pd_get_info},
+ {MFI_DCMD_PD_STATE_SET, megasas_dcmd_dummy},
+ {MFI_DCMD_PD_REBUILD, megasas_dcmd_dummy},
+ {MFI_DCMD_PD_BLINK, megasas_dcmd_dummy},
+ {MFI_DCMD_PD_UNBLINK, megasas_dcmd_dummy},
+ {MFI_DCMD_LD_GET_LIST, megasas_dcmd_ld_get_list},
+ {MFI_DCMD_LD_GET_INFO, megasas_dcmd_ld_get_info},
+ {MFI_DCMD_LD_GET_PROP, megasas_dcmd_dummy},
+ {MFI_DCMD_LD_SET_PROP, megasas_dcmd_dummy},
+ {MFI_DCMD_LD_DELETE, megasas_dcmd_dummy},
+ {MFI_DCMD_CFG_READ, megasas_dcmd_dummy},
+ {MFI_DCMD_CFG_ADD, megasas_dcmd_dummy},
+ {MFI_DCMD_CFG_CLEAR, megasas_dcmd_dummy},
+ {MFI_DCMD_CFG_FOREIGN_READ, megasas_dcmd_dummy},
+ {MFI_DCMD_CFG_FOREIGN_IMPORT, megasas_dcmd_dummy},
+ {MFI_DCMD_BBU_STATUS, megasas_dcmd_dummy},
+ {MFI_DCMD_BBU_CAPACITY_INFO, megasas_dcmd_dummy},
+ {MFI_DCMD_BBU_DESIGN_INFO, megasas_dcmd_dummy},
+ {MFI_DCMD_BBU_PROP_GET, megasas_dcmd_dummy},
+ {MFI_DCMD_CLUSTER, megasas_dcmd_dummy},
+ {MFI_DCMD_CLUSTER_RESET_ALL, megasas_dcmd_dummy},
+ {MFI_DCMD_CLUSTER_RESET_LD, megasas_dcmd_dummy},
+ {-1, NULL}
+};
+
static int megasas_handle_dcmd(MPTState *s, struct megasas_cmd_t *cmd)
{
int opcode, size = 0, len;
int retval = 0;
+ struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
#ifdef DEBUG_MEGASAS_DCMD
@@ -841,158 +1058,83 @@ static int megasas_handle_dcmd(MPTState *s, struct
megasas_cmd_t *cmd)
if (len < 0) {
return MFI_STAT_MEMORY_NOT_AVAILABLE;
}
- switch (opcode) {
- case MFI_DCMD_CTRL_MFC_DEFAULTS_GET:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD get MFC defaults\n");
-#endif
- size = megasas_mfc_get_defaults(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_GET_INFO:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD get controller info\n");
-#endif
- size = megasas_ctrl_get_info(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_CACHE_FLUSH:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD Cache flush\n");
-#endif
- qemu_aio_flush();
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_SHUTDOWN:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD Controller shutdown\n");
-#endif
- s->fw_state = MFI_FWSTATE_READY;
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_PD_LIST_QUERY:
+ while (cmdptr->opcode != -1 && cmdptr->opcode != opcode)
+ cmdptr++;
+ if (cmdptr->opcode == -1) {
+ DPRINTF("MFI DCMD %x unhandled (len %d)\n", opcode, len);
+ retval = megasas_dcmd_dummy(s, cmd);
+ } else {
+ retval = cmdptr->func(s, cmd);
+ }
+ if (retval != MFI_STAT_INVALID_STATUS) {
+ size = megasas_finish_dcmd(cmd, cmd->iov_size);
#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD query physical devices\n");
+ DPRINTF("MFI DCMD wrote %d bytes\n", size);
#endif
- retval = MFI_STAT_INVALID_DCMD;
- break;
- case MFI_DCMD_PD_GET_LIST:
+ }
+ return retval;
+}
+
+static int megasas_finish_internal_dcmd(struct megasas_cmd_t *cmd,
+ SCSIRequest *req)
+{
+ int opcode;
+ int retval = MFI_STAT_OK;
+ int lun = req->lun;
+
+ opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
+ scsi_req_put(req);
#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD PD get list\n");
+ DPRINTF("DCMD finish internal cmd %x lun %d\n", opcode, lun);
#endif
- size = megasas_dcmd_pd_get_list(s, cmd);
- retval = MFI_STAT_OK;
- break;
+ switch (opcode) {
case MFI_DCMD_PD_GET_INFO:
#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD PD get info\n");
-#endif
- size = megasas_dcmd_pd_get_info(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_LD_GET_LIST:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD LD get list\n");
+ DPRINTF("Internal DCMD PD get info\n");
#endif
- size = megasas_dcmd_ld_get_list(s, cmd);
- retval = MFI_STAT_OK;
+ retval = megasas_pd_get_info_submit(cmd->sdev, lun, cmd);
break;
case MFI_DCMD_LD_GET_INFO:
#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD LD get info\n");
+ DPRINTF("Internal DCMD LD get info\n");
#endif
- size = megasas_dcmd_ld_get_info(s, cmd);
- retval = MFI_STAT_OK;
+ retval = megasas_ld_get_info_submit(cmd->sdev, lun, cmd);
break;
- case MFI_DCMD_CTRL_GET_PROPERTIES:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD Get Properties\n");
-#endif
- size = megasas_dcmd_get_properties(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_SET_PROPERTIES:
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD Set Properties\n");
-#endif
- size = megasas_dcmd_set_properties(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_EVENT_GETINFO:
- size = megasas_event_info(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CFG_READ:
- case MFI_DCMD_CFG_FOREIGN_READ:
- size = megasas_dcmd_dummy(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_EVENT_WAIT:
+ default:
#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD controller event wait\n");
+ DPRINTF("Invalid internal DCMD\n");
#endif
retval = MFI_STAT_INVALID_DCMD;
break;
- case MFI_DCMD_CLUSTER_RESET_ALL:
- case MFI_DCMD_CLUSTER_RESET_LD:
- /* Cluster reset commands have a size of 0 */
- size = 0;
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_GET_BIOS_INFO:
- size = megasas_dcmd_get_bios_info(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_GET_TIME:
- size = megasas_dcmd_get_fw_time(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case MFI_DCMD_CTRL_SET_TIME:
- size = megasas_dcmd_set_fw_time(s, cmd);
- retval = MFI_STAT_OK;
- break;
- case 0x010e0301:
- case 0x010e0302:
- case 0x010e8481:
- DPRINTF("MFI DCMD %x dummy return %d bytes\n", opcode, len);
- size = megasas_dcmd_dummy(s, cmd);
- retval = MFI_STAT_OK;
- break;
- default:
- DPRINTF("MFI DCMD %x unhandled (len %d)\n", opcode, len);
- retval = MFI_STAT_INVALID_DCMD;
- break;
}
- size = megasas_finish_dcmd(cmd, size);
-#ifdef DEBUG_MEGASAS_DCMD
- DPRINTF("MFI DCMD wrote %d bytes\n", size);
-#endif
+ if (retval != MFI_STAT_INVALID_STATUS)
+ megasas_finish_dcmd(cmd, cmd->iov_size);
return retval;
}
-static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd)
+static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd, int
is_logical)
{
uint8_t *cdb;
cdb = cmd->frame->pass.cdb;
if (cmd->frame->header.target_id < s->fw_luns)
- cmd->lun = &s->luns[cmd->frame->header.target_id];
-
- if (cmd->lun)
- cmd->lun->sdev = s->bus.devs[cmd->frame->header.target_id];
+ cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
#ifdef DEBUG_MEGASAS_IO
- DPRINTF("%s dev %x lun %x sdev %p xfer %d\n",
+ DPRINTF("%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->lun?cmd->lun->sdev:NULL, cmd->frame->header.data_len);
+ cmd->sdev, cmd->frame->header.data_len);
#endif
- if (!cmd->lun || !cmd->lun->sdev) {
+ if (!cmd->sdev || (s->is_jbod && is_logical)) {
#ifdef DEBUG_MEGASAS_IO
- DPRINTF("%s dev %x/%x target not present\n",
- mfi_frame_desc[cmd->frame->header.frame_cmd],
cmd->frame->header.target_id,
+ DPRINTF("%s %s dev %x/%x target not present\n",
+ mfi_frame_desc[cmd->frame->header.frame_cmd],
+ is_logical?"logical":"physical",
+ cmd->frame->header.target_id,
cmd->frame->header.lun_id);
#endif
return MFI_STAT_DEVICE_NOT_FOUND;
@@ -1009,7 +1151,7 @@ static int megasas_handle_scsi(MPTState *s, struct
megasas_cmd_t *cmd)
return MFI_STAT_SCSI_DONE_WITH_ERROR;
}
- cmd->req = scsi_req_get(cmd->lun->sdev, cmd->frame->header.context,
cmd->frame->header.lun_id);
+ cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.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) {
@@ -1019,7 +1161,7 @@ static int megasas_handle_scsi(MPTState *s, struct
megasas_cmd_t *cmd)
s->event_count++;
}
- megasas_map_sgl(cmd, MEGASAS_PTHRU_SGL_OFFSET);
+ megasas_map_sgl(cmd, offsetof(struct mfi_pass_frame, sgl));
scsi_req_sgl(cmd->req, &cmd->sg);
return MFI_STAT_INVALID_STATUS;
@@ -1037,10 +1179,7 @@ static int megasas_handle_io(MPTState *s, struct
megasas_cmd_t *cmd)
lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
if (cmd->frame->header.target_id < s->fw_luns)
- cmd->lun = &s->luns[cmd->frame->header.target_id];
-
- if (cmd->lun)
- cmd->lun->sdev = s->bus.devs[cmd->frame->header.target_id];
+ cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
#ifdef DEBUG_MEGASAS_IO
DPRINTF("%s dev %x lun %x lba %lx count %lx\n",
@@ -1048,7 +1187,7 @@ static int megasas_handle_io(MPTState *s, struct
megasas_cmd_t *cmd)
cmd->frame->header.target_id, cmd->frame->header.lun_id,
(unsigned long)lba_start, (unsigned long)lba_count);
#endif
- if (!cmd->lun || !cmd->lun->sdev) {
+ if (!cmd->sdev) {
#ifdef DEBUG_MEGSAS_IO
DPRINTF("%s dev %x/%x LUN not present\n",
mfi_frame_desc[cmd->frame->header.frame_cmd],
@@ -1068,9 +1207,9 @@ 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->lun->sdev, cmd->frame->header.context,
cmd->frame->header.lun_id);
+ cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.context,
cmd->frame->header.lun_id);
cmd->req->hba_private = cmd;
- megasas_map_sgl(cmd, MEGASAS_IO_SGL_OFFSET);
+ megasas_map_sgl(cmd, offsetof(struct mfi_io_frame, sgl));
scsi_req_setup(cmd->req, write, lba_start, lba_count);
scsi_req_sgl(cmd->req, &cmd->sg);
@@ -1078,6 +1217,21 @@ static int megasas_handle_io(MPTState *s, struct
megasas_cmd_t *cmd)
return MFI_STAT_INVALID_STATUS;
}
+static int megasas_finish_internal_command(struct megasas_cmd_t *cmd,
+ SCSIRequest *req)
+{
+ int retval = MFI_STAT_INVALID_CMD;
+
+ switch (cmd->frame->header.frame_cmd) {
+ case MFI_CMD_DCMD:
+ retval = megasas_finish_internal_dcmd(cmd, req);
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
static void megasas_command_complete(SCSIRequest *req)
{
struct megasas_cmd_t *cmd;
@@ -1095,24 +1249,38 @@ static void megasas_command_complete(SCSIRequest *req)
return;
}
+ if (cmd->req != req) {
+ /*
+ * Internal command complete
+ */
+ cmd_status = megasas_finish_internal_command(cmd, req);
+ if (cmd_status == MFI_STAT_INVALID_STATUS)
+ return;
+ } else {
+
#ifdef DEBUG_MEGASAS_IO
- DPRINTF("%s req %p cmd %p lun %p finished with status %x len %u\n",
- mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd,
cmd->lun->sdev,
- req->status, (unsigned)req->xferlen);
-#endif
- if (req->status == CHECK_CONDITION) {
- megasas_build_sense(cmd, cmd->lun->sdev->sense);
- cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
- scsi_dev_clear_sense(cmd->lun->sdev);
- }
+ DPRINTF("%s req %p cmd %p lun %p finished with status %x len %u\n",
+ mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd,
cmd->sdev,
+ req->status, (unsigned)req->xferlen);
+#endif
+ if (req->status == CHECK_CONDITION) {
+ megasas_build_sense(cmd, cmd->sdev->sense);
+ cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
+ scsi_dev_clear_sense(cmd->sdev);
+ }
- megasas_unmap_sgl(cmd);
- megasas_frame_set_scsi_status(cmd->pa, cmd->req->status);
- scsi_req_put(cmd->req);
- cmd->req = NULL;
+ megasas_unmap_sgl(cmd);
+ megasas_frame_set_scsi_status(cmd->pa, cmd->req->status);
+ scsi_req_put(cmd->req);
+ cmd->req = NULL;
+ }
context = megasas_finish_command(cmd->state, cmd);
- megasas_frame_set_cmd_status(cmd->pa, cmd_status);
- megasas_dequeue_frame(cmd->state, context);
+ 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);
+ }
}
static int megasas_handle_abort(MPTState *s, struct megasas_cmd_t *cmd)
@@ -1152,8 +1320,8 @@ static void megasas_handle_frame(MPTState *s,
target_phys_addr_t frame_addr,
uint32_t frame_context = 0;
struct megasas_cmd_t *cmd;
- frame_cmd = ldub_phys(frame_addr + MEGASAS_FRAME_CMD_OFFSET);
- frame_context = ldl_phys(frame_addr + MEGASAS_FRAME_CONTEXT_OFFSET);
+ frame_cmd = megasas_frame_get_cmd(frame_addr);
+ frame_context = megasas_frame_get_context(frame_addr);
#ifdef DEBUG_MEGASAS_MFI
DPRINTF("MFI cmd %x context %x count %d\n",
@@ -1180,8 +1348,10 @@ static void megasas_handle_frame(MPTState *s,
target_phys_addr_t frame_addr,
frame_status = megasas_handle_abort(s, cmd);
break;
case MFI_CMD_PD_SCSI_IO:
+ frame_status = megasas_handle_scsi(s, cmd, 0);
+ break;
case MFI_CMD_LD_SCSI_IO:
- frame_status = megasas_handle_scsi(s, cmd);
+ frame_status = megasas_handle_scsi(s, cmd, 1);
break;
case MFI_CMD_LD_READ:
case MFI_CMD_LD_WRITE:
@@ -1445,7 +1615,9 @@ static void megasas_mmio_mapfunc(PCIDevice *pci_dev, int
region_num,
{
MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
+#ifdef DEBUG_MEGASAS_REG
DPRINTF("Mapping MMIO region %d at %08lx\n", region_num, (unsigned
long)addr);
+#endif
cpu_register_physical_memory(addr, size, s->mmio_io_addr);
s->event_count++;
}
@@ -1455,8 +1627,9 @@ static void megasas_io_mapfunc(PCIDevice *pci_dev, int
region_num,
{
MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
+#ifdef DEBUG_MEGASAS_REG
DPRINTF("Mapping IO region %d at %08lx\n", region_num, (unsigned
long)addr);
-
+#endif
register_ioport_write(addr, size, 1, megasas_io_writeb, s);
register_ioport_write(addr, size, 2, megasas_io_writew, s);
register_ioport_write(addr, size, 4, megasas_io_writel, s);
@@ -1471,7 +1644,9 @@ static void megasas_queue_mapfunc(PCIDevice *pci_dev, int
region_num,
{
MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
+#ifdef DEBUG_MEGASAS_REG
DPRINTF("Mapping QUEUE region %d at %08lx\n", region_num, (unsigned
long)addr);
+#endif
cpu_register_physical_memory(addr, size, s->queue_addr);
s->event_count++;
}
@@ -1555,10 +1730,20 @@ 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);
- s->fw_sge = MEGASAS_MAX_SGE;
- s->fw_cmds = MEGASAS_MAX_FRAMES;
- s->fw_luns = (MEGASAS_MAX_LUNS > MAX_SCSI_DEVS) ?
- MAX_SCSI_DEVS : MEGASAS_MAX_LUNS;
+ if (s->fw_sge > MEGASAS_MAX_SGE)
+ s->fw_sge = MEGASAS_MAX_SGE;
+ if (s->fw_cmds > MEGASAS_MAX_FRAMES)
+ s->fw_cmds = MEGASAS_MAX_FRAMES;
+ if (s->raid_mode_str) {
+ if (!strcmp(s->raid_mode_str, "jbod"))
+ s->is_jbod = 1;
+ else
+ s->is_jbod = 0;
+ }
+ DPRINTF("Using %d sges, %d cmds, %s mode\n",
+ s->fw_sge, s->fw_cmds, s->is_jbod?"jbod":"raid");
+ s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
+ MAX_SCSI_DEVS : MFI_MAX_LD;
s->producer_pa = 0;
s->consumer_pa = 0;
for (i = 0; i < s->fw_cmds; i++) {
@@ -1581,6 +1766,12 @@ static PCIDeviceInfo megasas_info = {
.qdev.size = sizeof(MPTState),
.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_STRING("mode", MPTState, raid_mode_str),
+ DEFINE_PROP_END_OF_LIST(),
+ },
};
static void megaraid1078_register_devices(void)
diff --git a/hw/mfi.h b/hw/mfi.h
index e7a5fde..90334b1 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -167,7 +167,7 @@ typedef enum {
MFI_DCMD_CTRL_SHUTDOWN = 0x01050000,
MFI_DCMD_HIBERNATE_SHUTDOWN = 0x01060000,
MFI_DCMD_CTRL_GET_TIME = 0x01080101,
- MFI_DCMD_CTRL_SET_TIME = 0x01080102,
+ MFI_DCMD_CTRL_SET_TIME = 0x01080102,
MFI_DCMD_CTRL_GET_BIOS_INFO = 0x010c0100,
MFI_DCMD_CTRL_FACTORY_DEFAULTS = 0x010d0000,
MFI_DCMD_CTRL_MFC_DEFAULTS_GET = 0x010e0201,
@@ -644,7 +644,16 @@ struct mfi_defaults {
uint8_t restored_hot_spare_on_insertion;
uint8_t expose_enclosure_devices;
uint8_t maintain_pd_fail_history;
- uint8_t resv[28];
+ uint8_t disable_puncture;
+ uint8_t zero_based_enumeration;
+ uint8_t disable_preboot_cli;
+ uint8_t show_drive_led_on_activity;
+ uint8_t cluster_disable;
+ uint8_t sas_disable;
+ uint8_t auto_detect_backplane;
+ uint8_t fde_only;
+ uint8_t delay_during_post;
+ uint8_t resv[19];
} __attribute__ ((packed));
/* Controller default settings */
@@ -685,6 +694,8 @@ struct mfi_ctrl_info {
#define MFI_INFO_HW_ALARM 0x02
#define MFI_INFO_HW_NVRAM 0x04
#define MFI_INFO_HW_UART 0x08
+#define MFI_INFO_HW_MEM 0x10
+#define MFI_INFO_HW_FLASH 0x20
uint32_t current_fw_time;
uint16_t max_cmds;
uint16_t max_sg_elements;
- [Qemu-devel] [PATCH] megasas: Update to version 1.01,
Hannes Reinecke <=