diff options
author | adam radford <aradford@gmail.com> | 2010-12-21 13:34:31 -0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-22 23:26:53 -0600 |
commit | 9c915a8c99bce637226aa09cb05fc18486b229cb (patch) | |
tree | 7bc2330661366db6407548a12366f7340f1b31e9 /drivers/scsi/megaraid/megaraid_sas_base.c | |
parent | cd50ba8ede5cd3c4606a8e5d163913da5ff36ad7 (diff) |
[SCSI] megaraid_sas: Add 9565/9285 specific code
This patch adds MegaRAID 9265/9285 (Device id 0x5b) specific code
Signed-off-by: Adam Radford <aradford@gmail.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 362 |
1 files changed, 260 insertions, 102 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5938267e472..5d6d07bd1cd 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -53,6 +53,7 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> +#include "megaraid_sas_fusion.h" #include "megaraid_sas.h" /* @@ -81,7 +82,7 @@ MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux@lsi.com"); MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); -static int megasas_transition_to_ready(struct megasas_instance *instance); +int megasas_transition_to_ready(struct megasas_instance *instance); static int megasas_get_pd_list(struct megasas_instance *instance); static int megasas_issue_init_mfi(struct megasas_instance *instance); static int megasas_register_aen(struct megasas_instance *instance, @@ -109,6 +110,8 @@ static struct pci_device_id megasas_pci_table[] = { /* xscale IOP, vega */ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, /* xscale IOP */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)}, + /* Fusion */ {} }; @@ -122,15 +125,16 @@ static DEFINE_MUTEX(megasas_async_queue_mutex); static int megasas_poll_wait_aen; static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait); static u32 support_poll_for_event; -static u32 megasas_dbg_lvl; +u32 megasas_dbg_lvl; static u32 support_device_change; /* define lock for aen poll */ spinlock_t poll_aen_lock; -static void +void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); + static irqreturn_t megasas_isr(int irq, void *devp); static u32 megasas_init_adapter_mfi(struct megasas_instance *instance); @@ -138,6 +142,23 @@ u32 megasas_build_and_issue_cmd(struct megasas_instance *instance, struct scsi_cmnd *scmd); static void megasas_complete_cmd_dpc(unsigned long instance_addr); +void +megasas_release_fusion(struct megasas_instance *instance); +int +megasas_ioc_init_fusion(struct megasas_instance *instance); +void +megasas_free_cmds_fusion(struct megasas_instance *instance); +u8 +megasas_get_map_info(struct megasas_instance *instance); +int +megasas_sync_map_info(struct megasas_instance *instance); +int +wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd); +void megasas_reset_reply_desc(struct megasas_instance *instance); +u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, + struct LD_LOAD_BALANCE_INFO *lbInfo); +int megasas_reset_fusion(struct Scsi_Host *shost); +void megasas_fusion_ocr_wq(struct work_struct *work); void megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) @@ -152,7 +173,7 @@ megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) * * Returns a free command from the pool */ -static struct megasas_cmd *megasas_get_cmd(struct megasas_instance +struct megasas_cmd *megasas_get_cmd(struct megasas_instance *instance) { unsigned long flags; @@ -177,7 +198,7 @@ static struct megasas_cmd *megasas_get_cmd(struct megasas_instance * @instance: Adapter soft state * @cmd: Command packet to be returned to free command pool */ -static inline void +inline void megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) { unsigned long flags; @@ -185,6 +206,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) spin_lock_irqsave(&instance->cmd_pool_lock, flags); cmd->scmd = NULL; + cmd->frame_count = 0; list_add_tail(&cmd->list, &instance->cmd_pool); spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); @@ -796,6 +818,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { * specific to gen2 (deviceid : 0x78, 0x79) controllers */ +/* + * Template added for TB (Fusion) + */ +extern struct megasas_instance_template megasas_instance_template_fusion; + /** * megasas_issue_polled - Issues a polling command * @instance: Adapter soft state @@ -803,11 +830,9 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { * * For polling, MFI requires the cmd_status to be set to 0xFF before posting. */ -static int +int megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) { - int i; - u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000; struct megasas_header *frame_hdr = &cmd->frame->hdr; @@ -817,21 +842,12 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) /* * Issue the frame using inbound queue port */ - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, 0, instance->reg_set); + instance->instancet->issue_dcmd(instance, cmd); /* * Wait for cmd_status to change */ - for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) { - rmb(); - msleep(1); - } - - if (frame_hdr->cmd_status == 0xff) - return -ETIME; - - return 0; + return wait_and_poll(instance, cmd); } /** @@ -849,8 +865,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, { cmd->cmd_status = ENODATA; - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, 0, instance->reg_set); + instance->instancet->issue_dcmd(instance, cmd); wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); @@ -894,8 +909,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, cmd->sync_cmd = 1; cmd->cmd_status = 0xFF; - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, 0, instance->reg_set); + instance->instancet->issue_dcmd(instance, cmd); /* * Wait for this cmd to complete @@ -1291,7 +1305,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, * Called by megasas_queue_command to find out if the command to be queued * is a logical drive command */ -static inline int megasas_is_ldio(struct scsi_cmnd *cmd) +inline int megasas_is_ldio(struct scsi_cmnd *cmd) { if (!MEGASAS_IS_LOGICAL(cmd)) return 0; @@ -1551,15 +1565,44 @@ static int megasas_slave_alloc(struct scsi_device *sdev) return 0; } -static void megaraid_sas_kill_hba(struct megasas_instance *instance) +void megaraid_sas_kill_hba(struct megasas_instance *instance) { if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - writel(MFI_STOP_ADP, - &instance->reg_set->reserved_0[0]); + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) { + writel(MFI_STOP_ADP, &instance->reg_set->doorbell); } else { - writel(MFI_STOP_ADP, - &instance->reg_set->inbound_doorbell); + writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); + } +} + + /** + * megasas_check_and_restore_queue_depth - Check if queue depth needs to be + * restored to max value + * @instance: Adapter soft state + * + */ +void +megasas_check_and_restore_queue_depth(struct megasas_instance *instance) +{ + unsigned long flags; + if (instance->flag & MEGASAS_FW_BUSY + && time_after(jiffies, instance->last_time + 5 * HZ) + && atomic_read(&instance->fw_outstanding) < 17) { + + spin_lock_irqsave(instance->host->host_lock, flags); + instance->flag &= ~MEGASAS_FW_BUSY; + if ((instance->pdev->device == + PCI_DEVICE_ID_LSI_SAS0073SKINNY) || + (instance->pdev->device == + PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + instance->host->can_queue = + instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; + } else + instance->host->can_queue = + instance->max_fw_cmds - MEGASAS_INT_CMDS; + + spin_unlock_irqrestore(instance->host->host_lock, flags); } } @@ -1613,24 +1656,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) /* * Check if we can restore can_queue */ - if (instance->flag & MEGASAS_FW_BUSY - && time_after(jiffies, instance->last_time + 5 * HZ) - && atomic_read(&instance->fw_outstanding) < 17) { - - spin_lock_irqsave(instance->host->host_lock, flags); - instance->flag &= ~MEGASAS_FW_BUSY; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; - - spin_unlock_irqrestore(instance->host->host_lock, flags); - } + megasas_check_and_restore_queue_depth(instance); } static void @@ -1808,7 +1834,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { writel(MFI_STOP_ADP, - &instance->reg_set->reserved_0[0]); + &instance->reg_set->doorbell); } else { writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); @@ -1912,11 +1938,16 @@ static int megasas_reset_device(struct scsi_cmnd *scmd) static int megasas_reset_bus_host(struct scsi_cmnd *scmd) { int ret; + struct megasas_instance *instance; + instance = (struct megasas_instance *)scmd->device->host->hostdata; /* * First wait for all commands to complete */ - ret = megasas_generic_reset(scmd); + if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) + ret = megasas_reset_fusion(scmd->device->host); + else + ret = megasas_generic_reset(scmd); return ret; } @@ -2086,13 +2117,14 @@ megasas_complete_abort(struct megasas_instance *instance, * an alternate status (as in the case of aborted * commands) */ -static void +void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status) { int exception = 0; struct megasas_header *hdr = &cmd->frame->hdr; unsigned long flags; + struct fusion_context *fusion = instance->ctrl_context; /* flag for the retry reset */ cmd->retry_for_fw_reset = 0; @@ -2185,6 +2217,37 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, case MFI_CMD_SMP: case MFI_CMD_STP: case MFI_CMD_DCMD: + /* Check for LD map update */ + if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) && + (cmd->frame->dcmd.mbox.b[1] == 1)) { + spin_lock_irqsave(instance->host->host_lock, flags); + if (cmd->frame->hdr.cmd_status != 0) { + if (cmd->frame->hdr.cmd_status != + MFI_STAT_NOT_FOUND) + printk(KERN_WARNING "megasas: map sync" + "failed, status = 0x%x.\n", + cmd->frame->hdr.cmd_status); + else { + megasas_return_cmd(instance, cmd); + spin_unlock_irqrestore( + instance->host->host_lock, + flags); + break; + } + } else + instance->map_id++; + megasas_return_cmd(instance, cmd); + if (MR_ValidateMapInfo( + fusion->ld_map[(instance->map_id & 1)], + fusion->load_balance_info)) + fusion->fast_path_io = 1; + else + fusion->fast_path_io = 0; + megasas_sync_map_info(instance); + spin_unlock_irqrestore(instance->host->host_lock, + flags); + break; + } if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) { spin_lock_irqsave(&poll_aen_lock, flags); @@ -2523,7 +2586,7 @@ static irqreturn_t megasas_isr(int irq, void *devp) * states, driver must take steps to bring it to ready state. Otherwise, it * has to wait for the ready state. */ -static int +int megasas_transition_to_ready(struct megasas_instance* instance) { int i; @@ -2557,11 +2620,12 @@ megasas_transition_to_ready(struct megasas_instance* instance) if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - + PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device == + PCI_DEVICE_ID_LSI_FUSION)) { writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, - &instance->reg_set->reserved_0[0]); + &instance->reg_set->doorbell); } else { writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, @@ -2574,11 +2638,13 @@ megasas_transition_to_ready(struct megasas_instance* instance) case MFI_STATE_BOOT_MESSAGE_PENDING: if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + PCI_DEVICE_ID_LSI_SAS0073SKINNY) || + (instance->pdev->device == + PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device == + PCI_DEVICE_ID_LSI_FUSION)) { writel(MFI_INIT_HOTPLUG, - &instance->reg_set->reserved_0[0]); + &instance->reg_set->doorbell); } else writel(MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); @@ -2595,9 +2661,23 @@ megasas_transition_to_ready(struct megasas_instance* instance) if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device + == PCI_DEVICE_ID_LSI_FUSION)) { writel(MFI_RESET_FLAGS, - &instance->reg_set->reserved_0[0]); + &instance->reg_set->doorbell); + if (instance->pdev->device == + PCI_DEVICE_ID_LSI_FUSION) { + for (i = 0; i < (10 * 1000); i += 20) { + if (readl( + &instance-> + reg_set-> + doorbell) & 1) + msleep(20); + else + break; + } + } } else writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell); @@ -2681,7 +2761,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) static void megasas_teardown_frame_pool(struct megasas_instance *instance) { int i; - u32 max_cmd = instance->max_fw_cmds; + u32 max_cmd = instance->max_mfi_cmds; struct megasas_cmd *cmd; if (!instance->frame_dma_pool) @@ -2732,7 +2812,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) u32 frame_count; struct megasas_cmd *cmd; - max_cmd = instance->max_fw_cmds; + max_cmd = instance->max_mfi_cmds; /* * Size of our frame is 64 bytes for MFI frame, followed by max SG @@ -2819,14 +2899,15 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) * megasas_free_cmds - Free all the cmds in the free cmd pool * @instance: Adapter soft state */ -static void megasas_free_cmds(struct megasas_instance *instance) +void megasas_free_cmds(struct megasas_instance *instance) { int i; /* First free the MFI frame pool */ megasas_teardown_frame_pool(instance); /* Free all the commands in the cmd_list */ - for (i = 0; i < instance->max_fw_cmds; i++) + for (i = 0; i < instance->max_mfi_cmds; i++) + kfree(instance->cmd_list[i]); /* Free the cmd_list buffer itself */ @@ -2854,14 +2935,14 @@ static void megasas_free_cmds(struct megasas_instance *instance) * This array is used only to look up the megasas_cmd given the context. The * free commands themselves are maintained in a linked list called cmd_pool. */ -static int megasas_alloc_cmds(struct megasas_instance *instance) +int megasas_alloc_cmds(struct megasas_instance *instance) { int i; int j; u32 max_cmd; struct megasas_cmd *cmd; - max_cmd = instance->max_fw_cmds; + max_cmd = instance->max_mfi_cmds; /* * instance->cmd_list is an array of struct megasas_cmd pointers. @@ -2875,6 +2956,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance) return -ENOMEM; } + memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd); for (i = 0; i < max_cmd; i++) { instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), @@ -3288,6 +3370,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) * does not exceed max cmds that the FW can support */ instance->max_fw_cmds = instance->max_fw_cmds-1; + instance->max_mfi_cmds = instance->max_fw_cmds; instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 0x10; /* @@ -3381,6 +3464,9 @@ static int megasas_init_fw(struct megasas_instance *instance) reg_set = instance->reg_set; switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_FUSION: + instance->instancet = &megasas_instance_template_fusion; + break; case PCI_DEVICE_ID_LSI_SAS1078R: case PCI_DEVICE_ID_LSI_SAS1078DE: instance->instancet = &megasas_instance_template_ppc; @@ -3482,9 +3568,10 @@ fail_ready_state: */ static void megasas_release_mfi(struct megasas_instance *instance) { - u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1); + u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1); - pci_free_consistent(instance->pdev, reply_q_sz, + if (instance->reply_queue) + pci_free_consistent(instance->pdev, reply_q_sz, instance->reply_queue, instance->reply_queue_h); megasas_free_cmds(instance); @@ -3678,8 +3765,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, /* * Issue the aen registration frame */ - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, 0, instance->reg_set); + instance->instancet->issue_dcmd(instance, cmd); return 0; } @@ -3756,12 +3842,18 @@ static int megasas_io_attach(struct megasas_instance *instance) } host->max_sectors = instance->max_sectors_per_req; - host->cmd_per_lun = 128; + host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN; host->max_channel = MEGASAS_MAX_CHANNELS - 1; host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL; host->max_lun = MEGASAS_MAX_LUN; host->max_cmd_len = 16; + /* Fusion only supports host reset */ + if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) { + host->hostt->eh_device_reset_handler = NULL; + host->hostt->eh_bus_reset_handler = NULL; + } + /* * Notify the mid-layer about the new controller */ @@ -3846,20 +3938,45 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance = (struct megasas_instance *)host->hostdata; memset(instance, 0, sizeof(*instance)); atomic_set( &instance->fw_reset_no_pci_access, 0 ); + instance->pdev = pdev; - instance->producer = pci_alloc_consistent(pdev, sizeof(u32), - &instance->producer_h); - instance->consumer = pci_alloc_consistent(pdev, sizeof(u32), - &instance->consumer_h); + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_FUSION: + { + struct fusion_context *fusion; + + instance->ctrl_context = + kzalloc(sizeof(struct fusion_context), GFP_KERNEL); + if (!instance->ctrl_context) { + printk(KERN_DEBUG "megasas: Failed to allocate " + "memory for Fusion context info\n"); + goto fail_alloc_dma_buf; + } + fusion = instance->ctrl_context; + INIT_LIST_HEAD(&fusion->cmd_pool); + spin_lock_init(&fusion->cmd_pool_lock); + } + break; + default: /* For all other supported controllers */ + + instance->producer = + pci_alloc_consistent(pdev, sizeof(u32), + &instance->producer_h); + instance->consumer = + pci_alloc_consistent(pdev, sizeof(u32), + &instance->consumer_h); + + if (!instance->producer || !instance->consumer) { + printk(KERN_DEBUG "megasas: Failed to allocate" + "memory for producer, consumer\n"); + goto fail_alloc_dma_buf; + } - if (!instance->producer || !instance->consumer) { - printk(KERN_DEBUG "megasas: Failed to allocate memory for " - "producer, consumer\n"); - goto fail_alloc_dma_buf; + *instance->producer = 0; + *instance->consumer = 0; + break; } - *instance->producer = 0; - *instance->consumer = 0; megasas_poll_wait_aen = 0; instance->flag_ieee = 0; instance->ev = NULL; @@ -3895,11 +4012,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&poll_aen_lock); mutex_init(&instance->aen_mutex); + mutex_init(&instance->reset_mutex); /* * Initialize PCI related and misc parameters */ - instance->pdev = pdev; instance->host = host; instance->unique_id = pdev->bus->number << 8 | pdev->devfn; instance->init_id = MEGASAS_DEFAULT_INIT_ID; @@ -3917,7 +4034,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->last_time = 0; instance->disableOnlineCtrlReset = 1; - INIT_WORK(&instance->work_init, process_fw_state_change_wq); + if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) + INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); + else + INIT_WORK(&instance->work_init, process_fw_state_change_wq); /* * Initialize MFI Firmware @@ -4000,6 +4120,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_free_consistent(pdev, sizeof(u32), instance->producer, instance->producer_h); megasas_release_mfi(instance); + } else { + megasas_release_fusion(instance); } if (instance->consumer) pci_free_consistent(pdev, sizeof(u32), instance->consumer, @@ -4072,7 +4194,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, if (instance->aen_cmd) megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd); - + if (instance->map_update_cmd) + megasas_issue_blocked_abort_cmd(instance, + instance->map_update_cmd); dcmd = &cmd->frame->dcmd; memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); @@ -4177,9 +4301,6 @@ megasas_resume(struct pci_dev *pdev) * Initialize MFI Firmware */ - *instance->producer = 0; - *instance->consumer = 0; - atomic_set(&instance->fw_outstanding, 0); /* @@ -4188,11 +4309,29 @@ megasas_resume(struct pci_dev *pdev) if (megasas_transition_to_ready(instance)) goto fail_ready_state; - if (megasas_issue_init_mfi(instance)) - goto fail_init_mfi; + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_FUSION: + { + megasas_reset_reply_desc(instance); + if (megasas_ioc_init_fusion(instance)) { + megasas_free_cmds(instance); + megasas_free_cmds_fusion(instance); + goto fail_init_mfi; + } + if (!megasas_get_map_info(instance)) + megasas_sync_map_info(instance); + } + break; + default: + *instance->producer = 0; + *instance->consumer = 0; + if (megasas_issue_init_mfi(instance)) + goto fail_init_mfi; + break; + } - tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, - (unsigned long)instance); + tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, + (unsigned long)instance); /* Now re-enable MSI-X */ if (instance->msi_flag) @@ -4261,10 +4400,12 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) int i; struct Scsi_Host *host; struct megasas_instance *instance; + struct fusion_context *fusion; instance = pci_get_drvdata(pdev); instance->unload = 1; host = instance->host; + fusion = instance->ctrl_context; if (poll_mode_io) del_timer_sync(&instance->io_completion_timer); @@ -4306,16 +4447,32 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) if (instance->msi_flag) pci_disable_msix(instance->pdev); - megasas_release_mfi(instance); - - pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), - instance->evt_detail, instance->evt_detail_h); - - pci_free_consistent(pdev, sizeof(u32), instance->producer, - instance->producer_h); - - pci_free_consistent(pdev, sizeof(u32), instance->consumer, - instance->consumer_h); + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_FUSION: + megasas_release_fusion(instance); + for (i = 0; i < 2 ; i++) + if (fusion->ld_map[i]) + dma_free_coherent(&instance->pdev->dev, + fusion->map_sz, + fusion->ld_map[i], + fusion-> + ld_map_phys[i]); + kfree(instance->ctrl_context); + break; + default: + megasas_release_mfi(instance); + pci_free_consistent(pdev, + sizeof(struct megasas_evt_detail), + instance->evt_detail, + instance->evt_detail_h); + pci_free_consistent(pdev, sizeof(u32), + instance->producer, + instance->producer_h); + pci_free_consistent(pdev, sizeof(u32), + instance->consumer, + instance->consumer_h); + break; + } scsi_host_put(host); @@ -5079,6 +5236,7 @@ megasas_aen_polling(struct work_struct *work) break; case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: case MR_EVT_FOREIGN_CFG_IMPORTED: + case MR_EVT_LD_STATE_CHANGE: doscan = 1; break; default: |