diff options
| -rw-r--r-- | drivers/scsi/megaraid/Makefile | 3 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 38 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 362 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fp.c | 516 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 2248 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.h | 695 |
6 files changed, 3751 insertions, 111 deletions
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile index 6613a2ceea03..5826ed509e3e 100644 --- a/drivers/scsi/megaraid/Makefile +++ b/drivers/scsi/megaraid/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o | 1 | obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o |
| 2 | obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o | 2 | obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o |
| 3 | obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o | 3 | obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o |
| 4 | megaraid_sas-objs := megaraid_sas_base.o | 4 | megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \ |
| 5 | megaraid_sas_fp.o | ||
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index a0b8ee1a5d2d..1b5e375732c0 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h | |||
| @@ -33,9 +33,9 @@ | |||
| 33 | /* | 33 | /* |
| 34 | * MegaRAID SAS Driver meta data | 34 | * MegaRAID SAS Driver meta data |
| 35 | */ | 35 | */ |
| 36 | #define MEGASAS_VERSION "00.00.04.31-rc1" | 36 | #define MEGASAS_VERSION "00.00.05.29-rc1" |
| 37 | #define MEGASAS_RELDATE "May 3, 2010" | 37 | #define MEGASAS_RELDATE "Dec. 7, 2010" |
| 38 | #define MEGASAS_EXT_VERSION "Mon. May 3, 11:41:51 PST 2010" | 38 | #define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010" |
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| 41 | * Device IDs | 41 | * Device IDs |
| @@ -47,6 +47,7 @@ | |||
| 47 | #define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079 | 47 | #define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079 |
| 48 | #define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073 | 48 | #define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073 |
| 49 | #define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071 | 49 | #define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071 |
| 50 | #define PCI_DEVICE_ID_LSI_FUSION 0x005b | ||
| 50 | 51 | ||
| 51 | /* | 52 | /* |
| 52 | * ===================================== | 53 | * ===================================== |
| @@ -436,7 +437,6 @@ struct megasas_ctrl_prop { | |||
| 436 | * Add properties that can be controlled by | 437 | * Add properties that can be controlled by |
| 437 | * a bit in the following structure. | 438 | * a bit in the following structure. |
| 438 | */ | 439 | */ |
| 439 | |||
| 440 | struct { | 440 | struct { |
| 441 | u32 copyBackDisabled : 1; | 441 | u32 copyBackDisabled : 1; |
| 442 | u32 SMARTerEnabled : 1; | 442 | u32 SMARTerEnabled : 1; |
| @@ -716,6 +716,7 @@ struct megasas_ctrl_info { | |||
| 716 | #define MEGASAS_DEFAULT_INIT_ID -1 | 716 | #define MEGASAS_DEFAULT_INIT_ID -1 |
| 717 | #define MEGASAS_MAX_LUN 8 | 717 | #define MEGASAS_MAX_LUN 8 |
| 718 | #define MEGASAS_MAX_LD 64 | 718 | #define MEGASAS_MAX_LD 64 |
| 719 | #define MEGASAS_DEFAULT_CMD_PER_LUN 128 | ||
| 719 | #define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \ | 720 | #define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \ |
| 720 | MEGASAS_MAX_DEV_PER_CHANNEL) | 721 | MEGASAS_MAX_DEV_PER_CHANNEL) |
| 721 | #define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \ | 722 | #define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \ |
| @@ -784,7 +785,10 @@ struct megasas_ctrl_info { | |||
| 784 | */ | 785 | */ |
| 785 | 786 | ||
| 786 | struct megasas_register_set { | 787 | struct megasas_register_set { |
| 787 | u32 reserved_0[4]; /*0000h*/ | 788 | u32 doorbell; /*0000h*/ |
| 789 | u32 fusion_seq_offset; /*0004h*/ | ||
| 790 | u32 fusion_host_diag; /*0008h*/ | ||
| 791 | u32 reserved_01; /*000Ch*/ | ||
| 788 | 792 | ||
| 789 | u32 inbound_msg_0; /*0010h*/ | 793 | u32 inbound_msg_0; /*0010h*/ |
| 790 | u32 inbound_msg_1; /*0014h*/ | 794 | u32 inbound_msg_1; /*0014h*/ |
| @@ -804,15 +808,18 @@ struct megasas_register_set { | |||
| 804 | u32 inbound_queue_port; /*0040h*/ | 808 | u32 inbound_queue_port; /*0040h*/ |
| 805 | u32 outbound_queue_port; /*0044h*/ | 809 | u32 outbound_queue_port; /*0044h*/ |
| 806 | 810 | ||
| 807 | u32 reserved_2[22]; /*0048h*/ | 811 | u32 reserved_2[9]; /*0048h*/ |
| 812 | u32 reply_post_host_index; /*006Ch*/ | ||
| 813 | u32 reserved_2_2[12]; /*0070h*/ | ||
| 808 | 814 | ||
| 809 | u32 outbound_doorbell_clear; /*00A0h*/ | 815 | u32 outbound_doorbell_clear; /*00A0h*/ |
| 810 | 816 | ||
| 811 | u32 reserved_3[3]; /*00A4h*/ | 817 | u32 reserved_3[3]; /*00A4h*/ |
| 812 | 818 | ||
| 813 | u32 outbound_scratch_pad ; /*00B0h*/ | 819 | u32 outbound_scratch_pad ; /*00B0h*/ |
| 820 | u32 outbound_scratch_pad_2; /*00B4h*/ | ||
| 814 | 821 | ||
| 815 | u32 reserved_4[3]; /*00B4h*/ | 822 | u32 reserved_4[2]; /*00B8h*/ |
| 816 | 823 | ||
| 817 | u32 inbound_low_queue_port ; /*00C0h*/ | 824 | u32 inbound_low_queue_port ; /*00C0h*/ |
| 818 | 825 | ||
| @@ -1287,6 +1294,9 @@ struct megasas_instance { | |||
| 1287 | 1294 | ||
| 1288 | u16 max_num_sge; | 1295 | u16 max_num_sge; |
| 1289 | u16 max_fw_cmds; | 1296 | u16 max_fw_cmds; |
| 1297 | /* For Fusion its num IOCTL cmds, for others MFI based its | ||
| 1298 | max_fw_cmds */ | ||
| 1299 | u16 max_mfi_cmds; | ||
| 1290 | u32 max_sectors_per_req; | 1300 | u32 max_sectors_per_req; |
| 1291 | struct megasas_aen_event *ev; | 1301 | struct megasas_aen_event *ev; |
| 1292 | 1302 | ||
| @@ -1336,9 +1346,15 @@ struct megasas_instance { | |||
| 1336 | struct timer_list io_completion_timer; | 1346 | struct timer_list io_completion_timer; |
| 1337 | struct list_head internal_reset_pending_q; | 1347 | struct list_head internal_reset_pending_q; |
| 1338 | 1348 | ||
| 1349 | /* Ptr to hba specfic information */ | ||
| 1350 | void *ctrl_context; | ||
| 1339 | u8 msi_flag; | 1351 | u8 msi_flag; |
| 1340 | struct msix_entry msixentry; | 1352 | struct msix_entry msixentry; |
| 1353 | u64 map_id; | ||
| 1354 | struct megasas_cmd *map_update_cmd; | ||
| 1341 | unsigned long bar; | 1355 | unsigned long bar; |
| 1356 | long reset_flags; | ||
| 1357 | struct mutex reset_mutex; | ||
| 1342 | }; | 1358 | }; |
| 1343 | 1359 | ||
| 1344 | enum { | 1360 | enum { |
| @@ -1397,7 +1413,13 @@ struct megasas_cmd { | |||
| 1397 | struct list_head list; | 1413 | struct list_head list; |
| 1398 | struct scsi_cmnd *scmd; | 1414 | struct scsi_cmnd *scmd; |
| 1399 | struct megasas_instance *instance; | 1415 | struct megasas_instance *instance; |
| 1400 | u32 frame_count; | 1416 | union { |
| 1417 | struct { | ||
| 1418 | u16 smid; | ||
| 1419 | u16 resvd; | ||
| 1420 | } context; | ||
| 1421 | u32 frame_count; | ||
| 1422 | }; | ||
| 1401 | }; | 1423 | }; |
| 1402 | 1424 | ||
| 1403 | #define MAX_MGMT_ADAPTERS 1024 | 1425 | #define MAX_MGMT_ADAPTERS 1024 |
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5938267e472b..5d6d07bd1cd0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <scsi/scsi_cmnd.h> | 53 | #include <scsi/scsi_cmnd.h> |
| 54 | #include <scsi/scsi_device.h> | 54 | #include <scsi/scsi_device.h> |
| 55 | #include <scsi/scsi_host.h> | 55 | #include <scsi/scsi_host.h> |
| 56 | #include "megaraid_sas_fusion.h" | ||
| 56 | #include "megaraid_sas.h" | 57 | #include "megaraid_sas.h" |
| 57 | 58 | ||
| 58 | /* | 59 | /* |
| @@ -81,7 +82,7 @@ MODULE_VERSION(MEGASAS_VERSION); | |||
| 81 | MODULE_AUTHOR("megaraidlinux@lsi.com"); | 82 | MODULE_AUTHOR("megaraidlinux@lsi.com"); |
| 82 | MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); | 83 | MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); |
| 83 | 84 | ||
| 84 | static int megasas_transition_to_ready(struct megasas_instance *instance); | 85 | int megasas_transition_to_ready(struct megasas_instance *instance); |
| 85 | static int megasas_get_pd_list(struct megasas_instance *instance); | 86 | static int megasas_get_pd_list(struct megasas_instance *instance); |
| 86 | static int megasas_issue_init_mfi(struct megasas_instance *instance); | 87 | static int megasas_issue_init_mfi(struct megasas_instance *instance); |
| 87 | static int megasas_register_aen(struct megasas_instance *instance, | 88 | static int megasas_register_aen(struct megasas_instance *instance, |
| @@ -109,6 +110,8 @@ static struct pci_device_id megasas_pci_table[] = { | |||
| 109 | /* xscale IOP, vega */ | 110 | /* xscale IOP, vega */ |
| 110 | {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, | 111 | {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, |
| 111 | /* xscale IOP */ | 112 | /* xscale IOP */ |
| 113 | {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)}, | ||
| 114 | /* Fusion */ | ||
| 112 | {} | 115 | {} |
| 113 | }; | 116 | }; |
| 114 | 117 | ||
| @@ -122,15 +125,16 @@ static DEFINE_MUTEX(megasas_async_queue_mutex); | |||
| 122 | static int megasas_poll_wait_aen; | 125 | static int megasas_poll_wait_aen; |
| 123 | static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait); | 126 | static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait); |
| 124 | static u32 support_poll_for_event; | 127 | static u32 support_poll_for_event; |
| 125 | static u32 megasas_dbg_lvl; | 128 | u32 megasas_dbg_lvl; |
| 126 | static u32 support_device_change; | 129 | static u32 support_device_change; |
| 127 | 130 | ||
| 128 | /* define lock for aen poll */ | 131 | /* define lock for aen poll */ |
| 129 | spinlock_t poll_aen_lock; | 132 | spinlock_t poll_aen_lock; |
| 130 | 133 | ||
| 131 | static void | 134 | void |
| 132 | megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | 135 | megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, |
| 133 | u8 alt_status); | 136 | u8 alt_status); |
| 137 | |||
| 134 | static irqreturn_t megasas_isr(int irq, void *devp); | 138 | static irqreturn_t megasas_isr(int irq, void *devp); |
| 135 | static u32 | 139 | static u32 |
| 136 | megasas_init_adapter_mfi(struct megasas_instance *instance); | 140 | megasas_init_adapter_mfi(struct megasas_instance *instance); |
| @@ -138,6 +142,23 @@ u32 | |||
| 138 | megasas_build_and_issue_cmd(struct megasas_instance *instance, | 142 | megasas_build_and_issue_cmd(struct megasas_instance *instance, |
| 139 | struct scsi_cmnd *scmd); | 143 | struct scsi_cmnd *scmd); |
| 140 | static void megasas_complete_cmd_dpc(unsigned long instance_addr); | 144 | static void megasas_complete_cmd_dpc(unsigned long instance_addr); |
| 145 | void | ||
| 146 | megasas_release_fusion(struct megasas_instance *instance); | ||
| 147 | int | ||
| 148 | megasas_ioc_init_fusion(struct megasas_instance *instance); | ||
| 149 | void | ||
| 150 | megasas_free_cmds_fusion(struct megasas_instance *instance); | ||
| 151 | u8 | ||
| 152 | megasas_get_map_info(struct megasas_instance *instance); | ||
| 153 | int | ||
| 154 | megasas_sync_map_info(struct megasas_instance *instance); | ||
| 155 | int | ||
| 156 | wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd); | ||
| 157 | void megasas_reset_reply_desc(struct megasas_instance *instance); | ||
| 158 | u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, | ||
| 159 | struct LD_LOAD_BALANCE_INFO *lbInfo); | ||
| 160 | int megasas_reset_fusion(struct Scsi_Host *shost); | ||
| 161 | void megasas_fusion_ocr_wq(struct work_struct *work); | ||
| 141 | 162 | ||
| 142 | void | 163 | void |
| 143 | megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) | 164 | 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) | |||
| 152 | * | 173 | * |
| 153 | * Returns a free command from the pool | 174 | * Returns a free command from the pool |
| 154 | */ | 175 | */ |
| 155 | static struct megasas_cmd *megasas_get_cmd(struct megasas_instance | 176 | struct megasas_cmd *megasas_get_cmd(struct megasas_instance |
| 156 | *instance) | 177 | *instance) |
| 157 | { | 178 | { |
| 158 | unsigned long flags; | 179 | unsigned long flags; |
| @@ -177,7 +198,7 @@ static struct megasas_cmd *megasas_get_cmd(struct megasas_instance | |||
| 177 | * @instance: Adapter soft state | 198 | * @instance: Adapter soft state |
| 178 | * @cmd: Command packet to be returned to free command pool | 199 | * @cmd: Command packet to be returned to free command pool |
| 179 | */ | 200 | */ |
| 180 | static inline void | 201 | inline void |
| 181 | megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) | 202 | megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) |
| 182 | { | 203 | { |
| 183 | unsigned long flags; | 204 | unsigned long flags; |
| @@ -185,6 +206,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) | |||
| 185 | spin_lock_irqsave(&instance->cmd_pool_lock, flags); | 206 | spin_lock_irqsave(&instance->cmd_pool_lock, flags); |
| 186 | 207 | ||
| 187 | cmd->scmd = NULL; | 208 | cmd->scmd = NULL; |
| 209 | cmd->frame_count = 0; | ||
| 188 | list_add_tail(&cmd->list, &instance->cmd_pool); | 210 | list_add_tail(&cmd->list, &instance->cmd_pool); |
| 189 | 211 | ||
| 190 | spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); | 212 | spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); |
| @@ -796,6 +818,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { | |||
| 796 | * specific to gen2 (deviceid : 0x78, 0x79) controllers | 818 | * specific to gen2 (deviceid : 0x78, 0x79) controllers |
| 797 | */ | 819 | */ |
| 798 | 820 | ||
| 821 | /* | ||
| 822 | * Template added for TB (Fusion) | ||
| 823 | */ | ||
| 824 | extern struct megasas_instance_template megasas_instance_template_fusion; | ||
| 825 | |||
| 799 | /** | 826 | /** |
| 800 | * megasas_issue_polled - Issues a polling command | 827 | * megasas_issue_polled - Issues a polling command |
| 801 | * @instance: Adapter soft state | 828 | * @instance: Adapter soft state |
| @@ -803,11 +830,9 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { | |||
| 803 | * | 830 | * |
| 804 | * For polling, MFI requires the cmd_status to be set to 0xFF before posting. | 831 | * For polling, MFI requires the cmd_status to be set to 0xFF before posting. |
| 805 | */ | 832 | */ |
| 806 | static int | 833 | int |
| 807 | megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) | 834 | megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) |
| 808 | { | 835 | { |
| 809 | int i; | ||
| 810 | u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000; | ||
| 811 | 836 | ||
| 812 | struct megasas_header *frame_hdr = &cmd->frame->hdr; | 837 | struct megasas_header *frame_hdr = &cmd->frame->hdr; |
| 813 | 838 | ||
| @@ -817,21 +842,12 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) | |||
| 817 | /* | 842 | /* |
| 818 | * Issue the frame using inbound queue port | 843 | * Issue the frame using inbound queue port |
| 819 | */ | 844 | */ |
| 820 | instance->instancet->fire_cmd(instance, | 845 | instance->instancet->issue_dcmd(instance, cmd); |
| 821 | cmd->frame_phys_addr, 0, instance->reg_set); | ||
| 822 | 846 | ||
| 823 | /* | 847 | /* |
| 824 | * Wait for cmd_status to change | 848 | * Wait for cmd_status to change |
| 825 | */ | 849 | */ |
| 826 | for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) { | 850 | return wait_and_poll(instance, cmd); |
| 827 | rmb(); | ||
| 828 | msleep(1); | ||
| 829 | } | ||
| 830 | |||
| 831 | if (frame_hdr->cmd_status == 0xff) | ||
| 832 | return -ETIME; | ||
| 833 | |||
| 834 | return 0; | ||
| 835 | } | 851 | } |
| 836 | 852 | ||
| 837 | /** | 853 | /** |
| @@ -849,8 +865,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, | |||
| 849 | { | 865 | { |
| 850 | cmd->cmd_status = ENODATA; | 866 | cmd->cmd_status = ENODATA; |
| 851 | 867 | ||
| 852 | instance->instancet->fire_cmd(instance, | 868 | instance->instancet->issue_dcmd(instance, cmd); |
| 853 | cmd->frame_phys_addr, 0, instance->reg_set); | ||
| 854 | 869 | ||
| 855 | wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); | 870 | wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); |
| 856 | 871 | ||
| @@ -894,8 +909,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, | |||
| 894 | cmd->sync_cmd = 1; | 909 | cmd->sync_cmd = 1; |
| 895 | cmd->cmd_status = 0xFF; | 910 | cmd->cmd_status = 0xFF; |
| 896 | 911 | ||
| 897 | instance->instancet->fire_cmd(instance, | 912 | instance->instancet->issue_dcmd(instance, cmd); |
| 898 | cmd->frame_phys_addr, 0, instance->reg_set); | ||
| 899 | 913 | ||
| 900 | /* | 914 | /* |
| 901 | * Wait for this cmd to complete | 915 | * Wait for this cmd to complete |
| @@ -1291,7 +1305,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, | |||
| 1291 | * Called by megasas_queue_command to find out if the command to be queued | 1305 | * Called by megasas_queue_command to find out if the command to be queued |
| 1292 | * is a logical drive command | 1306 | * is a logical drive command |
| 1293 | */ | 1307 | */ |
| 1294 | static inline int megasas_is_ldio(struct scsi_cmnd *cmd) | 1308 | inline int megasas_is_ldio(struct scsi_cmnd *cmd) |
| 1295 | { | 1309 | { |
| 1296 | if (!MEGASAS_IS_LOGICAL(cmd)) | 1310 | if (!MEGASAS_IS_LOGICAL(cmd)) |
| 1297 | return 0; | 1311 | return 0; |
| @@ -1551,15 +1565,44 @@ static int megasas_slave_alloc(struct scsi_device *sdev) | |||
| 1551 | return 0; | 1565 | return 0; |
| 1552 | } | 1566 | } |
| 1553 | 1567 | ||
| 1554 | static void megaraid_sas_kill_hba(struct megasas_instance *instance) | 1568 | void megaraid_sas_kill_hba(struct megasas_instance *instance) |
| 1555 | { | 1569 | { |
| 1556 | if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | 1570 | if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || |
| 1557 | (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | 1571 | (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || |
| 1558 | writel(MFI_STOP_ADP, | 1572 | (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) { |
| 1559 | &instance->reg_set->reserved_0[0]); | 1573 | writel(MFI_STOP_ADP, &instance->reg_set->doorbell); |
| 1560 | } else { | 1574 | } else { |
| 1561 | writel(MFI_STOP_ADP, | 1575 | writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); |
| 1562 | &instance->reg_set->inbound_doorbell); | 1576 | } |
| 1577 | } | ||
| 1578 | |||
| 1579 | /** | ||
| 1580 | * megasas_check_and_restore_queue_depth - Check if queue depth needs to be | ||
| 1581 | * restored to max value | ||
| 1582 | * @instance: Adapter soft state | ||
| 1583 | * | ||
| 1584 | */ | ||
| 1585 | void | ||
| 1586 | megasas_check_and_restore_queue_depth(struct megasas_instance *instance) | ||
| 1587 | { | ||
| 1588 | unsigned long flags; | ||
| 1589 | if (instance->flag & MEGASAS_FW_BUSY | ||
| 1590 | && time_after(jiffies, instance->last_time + 5 * HZ) | ||
| 1591 | && atomic_read(&instance->fw_outstanding) < 17) { | ||
| 1592 | |||
| 1593 | spin_lock_irqsave(instance->host->host_lock, flags); | ||
| 1594 | instance->flag &= ~MEGASAS_FW_BUSY; | ||
| 1595 | if ((instance->pdev->device == | ||
| 1596 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | ||
| 1597 | (instance->pdev->device == | ||
| 1598 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | ||
| 1599 | instance->host->can_queue = | ||
| 1600 | instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; | ||
| 1601 | } else | ||
| 1602 | instance->host->can_queue = | ||
| 1603 | instance->max_fw_cmds - MEGASAS_INT_CMDS; | ||
| 1604 | |||
| 1605 | spin_unlock_irqrestore(instance->host->host_lock, flags); | ||
| 1563 | } | 1606 | } |
| 1564 | } | 1607 | } |
| 1565 | 1608 | ||
| @@ -1613,24 +1656,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
| 1613 | /* | 1656 | /* |
| 1614 | * Check if we can restore can_queue | 1657 | * Check if we can restore can_queue |
| 1615 | */ | 1658 | */ |
| 1616 | if (instance->flag & MEGASAS_FW_BUSY | 1659 | megasas_check_and_restore_queue_depth(instance); |
| 1617 | && time_after(jiffies, instance->last_time + 5 * HZ) | ||
| 1618 | && atomic_read(&instance->fw_outstanding) < 17) { | ||
| 1619 | |||
| 1620 | spin_lock_irqsave(instance->host->host_lock, flags); | ||
| 1621 | instance->flag &= ~MEGASAS_FW_BUSY; | ||
| 1622 | if ((instance->pdev->device == | ||
| 1623 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | ||
| 1624 | (instance->pdev->device == | ||
| 1625 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | ||
| 1626 | instance->host->can_queue = | ||
| 1627 | instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; | ||
| 1628 | } else | ||
| 1629 | instance->host->can_queue = | ||
| 1630 | instance->max_fw_cmds - MEGASAS_INT_CMDS; | ||
| 1631 | |||
| 1632 | spin_unlock_irqrestore(instance->host->host_lock, flags); | ||
| 1633 | } | ||
| 1634 | } | 1660 | } |
| 1635 | 1661 | ||
| 1636 | static void | 1662 | static void |
| @@ -1808,7 +1834,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) | |||
| 1808 | (instance->pdev->device == | 1834 | (instance->pdev->device == |
| 1809 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | 1835 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { |
| 1810 | writel(MFI_STOP_ADP, | 1836 | writel(MFI_STOP_ADP, |
| 1811 | &instance->reg_set->reserved_0[0]); | 1837 | &instance->reg_set->doorbell); |
| 1812 | } else { | 1838 | } else { |
| 1813 | writel(MFI_STOP_ADP, | 1839 | writel(MFI_STOP_ADP, |
| 1814 | &instance->reg_set->inbound_doorbell); | 1840 | &instance->reg_set->inbound_doorbell); |
| @@ -1912,11 +1938,16 @@ static int megasas_reset_device(struct scsi_cmnd *scmd) | |||
| 1912 | static int megasas_reset_bus_host(struct scsi_cmnd *scmd) | 1938 | static int megasas_reset_bus_host(struct scsi_cmnd *scmd) |
| 1913 | { | 1939 | { |
| 1914 | int ret; | 1940 | int ret; |
| 1941 | struct megasas_instance *instance; | ||
| 1942 | instance = (struct megasas_instance *)scmd->device->host->hostdata; | ||
| 1915 | 1943 | ||
| 1916 | /* | 1944 | /* |
| 1917 | * First wait for all commands to complete | 1945 | * First wait for all commands to complete |
| 1918 | */ | 1946 | */ |
| 1919 | ret = megasas_generic_reset(scmd); | 1947 | if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) |
| 1948 | ret = megasas_reset_fusion(scmd->device->host); | ||
| 1949 | else | ||
| 1950 | ret = megasas_generic_reset(scmd); | ||
| 1920 | 1951 | ||
| 1921 | return ret; | 1952 | return ret; |
| 1922 | } | 1953 | } |
| @@ -2086,13 +2117,14 @@ megasas_complete_abort(struct megasas_instance *instance, | |||
| 2086 | * an alternate status (as in the case of aborted | 2117 | * an alternate status (as in the case of aborted |
| 2087 | * commands) | 2118 | * commands) |
| 2088 | */ | 2119 | */ |
| 2089 | static void | 2120 | void |
| 2090 | megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | 2121 | megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, |
| 2091 | u8 alt_status) | 2122 | u8 alt_status) |
| 2092 | { | 2123 | { |
| 2093 | int exception = 0; | 2124 | int exception = 0; |
| 2094 | struct megasas_header *hdr = &cmd->frame->hdr; | 2125 | struct megasas_header *hdr = &cmd->frame->hdr; |
| 2095 | unsigned long flags; | 2126 | unsigned long flags; |
| 2127 | struct fusion_context *fusion = instance->ctrl_context; | ||
| 2096 | 2128 | ||
| 2097 | /* flag for the retry reset */ | 2129 | /* flag for the retry reset */ |
| 2098 | cmd->retry_for_fw_reset = 0; | 2130 | cmd->retry_for_fw_reset = 0; |
| @@ -2185,6 +2217,37 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | |||
| 2185 | case MFI_CMD_SMP: | 2217 | case MFI_CMD_SMP: |
| 2186 | case MFI_CMD_STP: | 2218 | case MFI_CMD_STP: |
| 2187 | case MFI_CMD_DCMD: | 2219 | case MFI_CMD_DCMD: |
| 2220 | /* Check for LD map update */ | ||
| 2221 | if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) && | ||
| 2222 | (cmd->frame->dcmd.mbox.b[1] == 1)) { | ||
| 2223 | spin_lock_irqsave(instance->host->host_lock, flags); | ||
| 2224 | if (cmd->frame->hdr.cmd_status != 0) { | ||
| 2225 | if (cmd->frame->hdr.cmd_status != | ||
| 2226 | MFI_STAT_NOT_FOUND) | ||
| 2227 | printk(KERN_WARNING "megasas: map sync" | ||
| 2228 | "failed, status = 0x%x.\n", | ||
| 2229 | cmd->frame->hdr.cmd_status); | ||
| 2230 | else { | ||
| 2231 | megasas_return_cmd(instance, cmd); | ||
| 2232 | spin_unlock_irqrestore( | ||
| 2233 | instance->host->host_lock, | ||
| 2234 | flags); | ||
| 2235 | break; | ||
| 2236 | } | ||
| 2237 | } else | ||
| 2238 | instance->map_id++; | ||
| 2239 | megasas_return_cmd(instance, cmd); | ||
| 2240 | if (MR_ValidateMapInfo( | ||
| 2241 | fusion->ld_map[(instance->map_id & 1)], | ||
| 2242 | fusion->load_balance_info)) | ||
| 2243 | fusion->fast_path_io = 1; | ||
| 2244 | else | ||
| 2245 | fusion->fast_path_io = 0; | ||
| 2246 | megasas_sync_map_info(instance); | ||
| 2247 | spin_unlock_irqrestore(instance->host->host_lock, | ||
| 2248 | flags); | ||
| 2249 | break; | ||
| 2250 | } | ||
| 2188 | if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || | 2251 | if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || |
| 2189 | cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) { | 2252 | cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) { |
| 2190 | spin_lock_irqsave(&poll_aen_lock, flags); | 2253 | spin_lock_irqsave(&poll_aen_lock, flags); |
| @@ -2523,7 +2586,7 @@ static irqreturn_t megasas_isr(int irq, void *devp) | |||
| 2523 | * states, driver must take steps to bring it to ready state. Otherwise, it | 2586 | * states, driver must take steps to bring it to ready state. Otherwise, it |
| 2524 | * has to wait for the ready state. | 2587 | * has to wait for the ready state. |
| 2525 | */ | 2588 | */ |
| 2526 | static int | 2589 | int |
| 2527 | megasas_transition_to_ready(struct megasas_instance* instance) | 2590 | megasas_transition_to_ready(struct megasas_instance* instance) |
| 2528 | { | 2591 | { |
| 2529 | int i; | 2592 | int i; |
| @@ -2557,11 +2620,12 @@ megasas_transition_to_ready(struct megasas_instance* instance) | |||
| 2557 | if ((instance->pdev->device == | 2620 | if ((instance->pdev->device == |
| 2558 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | 2621 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || |
| 2559 | (instance->pdev->device == | 2622 | (instance->pdev->device == |
| 2560 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | 2623 | PCI_DEVICE_ID_LSI_SAS0071SKINNY) || |
| 2561 | 2624 | (instance->pdev->device == | |
| 2625 | PCI_DEVICE_ID_LSI_FUSION)) { | ||
| 2562 | writel( | 2626 | writel( |
| 2563 | MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, | 2627 | MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, |
| 2564 | &instance->reg_set->reserved_0[0]); | 2628 | &instance->reg_set->doorbell); |
| 2565 | } else { | 2629 | } else { |
| 2566 | writel( | 2630 | writel( |
| 2567 | MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, | 2631 | MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, |
| @@ -2574,11 +2638,13 @@ megasas_transition_to_ready(struct megasas_instance* instance) | |||
| 2574 | 2638 | ||
| 2575 | case MFI_STATE_BOOT_MESSAGE_PENDING: | 2639 | case MFI_STATE_BOOT_MESSAGE_PENDING: |
| 2576 | if ((instance->pdev->device == | 2640 | if ((instance->pdev->device == |
| 2577 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | 2641 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || |
| 2578 | (instance->pdev->device == | 2642 | (instance->pdev->device == |
| 2579 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | 2643 | PCI_DEVICE_ID_LSI_SAS0071SKINNY) || |
| 2644 | (instance->pdev->device == | ||
| 2645 | PCI_DEVICE_ID_LSI_FUSION)) { | ||
| 2580 | writel(MFI_INIT_HOTPLUG, | 2646 | writel(MFI_INIT_HOTPLUG, |
| 2581 | &instance->reg_set->reserved_0[0]); | 2647 | &instance->reg_set->doorbell); |
| 2582 | } else | 2648 | } else |
| 2583 | writel(MFI_INIT_HOTPLUG, | 2649 | writel(MFI_INIT_HOTPLUG, |
| 2584 | &instance->reg_set->inbound_doorbell); | 2650 | &instance->reg_set->inbound_doorbell); |
| @@ -2595,9 +2661,23 @@ megasas_transition_to_ready(struct megasas_instance* instance) | |||
| 2595 | if ((instance->pdev->device == | 2661 | if ((instance->pdev->device == |
| 2596 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | 2662 | PCI_DEVICE_ID_LSI_SAS0073SKINNY) || |
| 2597 | (instance->pdev->device == | 2663 | (instance->pdev->device == |
| 2598 | PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | 2664 | PCI_DEVICE_ID_LSI_SAS0071SKINNY) || |
| 2665 | (instance->pdev->device | ||
| 2666 | == PCI_DEVICE_ID_LSI_FUSION)) { | ||
| 2599 | writel(MFI_RESET_FLAGS, | 2667 | writel(MFI_RESET_FLAGS, |
| 2600 | &instance->reg_set->reserved_0[0]); | 2668 | &instance->reg_set->doorbell); |
| 2669 | if (instance->pdev->device == | ||
| 2670 | PCI_DEVICE_ID_LSI_FUSION) { | ||
| 2671 | for (i = 0; i < (10 * 1000); i += 20) { | ||
| 2672 | if (readl( | ||
| 2673 | &instance-> | ||
| 2674 | reg_set-> | ||
| 2675 | doorbell) & 1) | ||
| 2676 | msleep(20); | ||
| 2677 | else | ||
| 2678 | break; | ||
| 2679 | } | ||
| 2680 | } | ||
| 2601 | } else | 2681 | } else |
| 2602 | writel(MFI_RESET_FLAGS, | 2682 | writel(MFI_RESET_FLAGS, |
| 2603 | &instance->reg_set->inbound_doorbell); | 2683 | &instance->reg_set->inbound_doorbell); |
| @@ -2681,7 +2761,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) | |||
| 2681 | static void megasas_teardown_frame_pool(struct megasas_instance *instance) | 2761 | static void megasas_teardown_frame_pool(struct megasas_instance *instance) |
| 2682 | { | 2762 | { |
| 2683 | int i; | 2763 | int i; |
| 2684 | u32 max_cmd = instance->max_fw_cmds; | 2764 | u32 max_cmd = instance->max_mfi_cmds; |
| 2685 | struct megasas_cmd *cmd; | 2765 | struct megasas_cmd *cmd; |
| 2686 | 2766 | ||
| 2687 | if (!instance->frame_dma_pool) | 2767 | if (!instance->frame_dma_pool) |
| @@ -2732,7 +2812,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) | |||
| 2732 | u32 frame_count; | 2812 | u32 frame_count; |
| 2733 | struct megasas_cmd *cmd; | 2813 | struct megasas_cmd *cmd; |
| 2734 | 2814 | ||
| 2735 | max_cmd = instance->max_fw_cmds; | 2815 | max_cmd = instance->max_mfi_cmds; |
| 2736 | 2816 | ||
| 2737 | /* | 2817 | /* |
| 2738 | * Size of our frame is 64 bytes for MFI frame, followed by max SG | 2818 | * 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) | |||
| 2819 | * megasas_free_cmds - Free all the cmds in the free cmd pool | 2899 | * megasas_free_cmds - Free all the cmds in the free cmd pool |
| 2820 | * @instance: Adapter soft state | 2900 | * @instance: Adapter soft state |
| 2821 | */ | 2901 | */ |
| 2822 | static void megasas_free_cmds(struct megasas_instance *instance) | 2902 | void megasas_free_cmds(struct megasas_instance *instance) |
| 2823 | { | 2903 | { |
| 2824 | int i; | 2904 | int i; |
| 2825 | /* First free the MFI frame pool */ | 2905 | /* First free the MFI frame pool */ |
| 2826 | megasas_teardown_frame_pool(instance); | 2906 | megasas_teardown_frame_pool(instance); |
| 2827 | 2907 | ||
| 2828 | /* Free all the commands in the cmd_list */ | 2908 | /* Free all the commands in the cmd_list */ |
| 2829 | for (i = 0; i < instance->max_fw_cmds; i++) | 2909 | for (i = 0; i < instance->max_mfi_cmds; i++) |
| 2910 | |||
| 2830 | kfree(instance->cmd_list[i]); | 2911 | kfree(instance->cmd_list[i]); |
| 2831 | 2912 | ||
| 2832 | /* Free the cmd_list buffer itself */ | 2913 | /* Free the cmd_list buffer itself */ |
| @@ -2854,14 +2935,14 @@ static void megasas_free_cmds(struct megasas_instance *instance) | |||
| 2854 | * This array is used only to look up the megasas_cmd given the context. The | 2935 | * This array is used only to look up the megasas_cmd given the context. The |
| 2855 | * free commands themselves are maintained in a linked list called cmd_pool. | 2936 | * free commands themselves are maintained in a linked list called cmd_pool. |
| 2856 | */ | 2937 | */ |
| 2857 | static int megasas_alloc_cmds(struct megasas_instance *instance) | 2938 | int megasas_alloc_cmds(struct megasas_instance *instance) |
| 2858 | { | 2939 | { |
| 2859 | int i; | 2940 | int i; |
| 2860 | int j; | 2941 | int j; |
| 2861 | u32 max_cmd; | 2942 | u32 max_cmd; |
| 2862 | struct megasas_cmd *cmd; | 2943 | struct megasas_cmd *cmd; |
| 2863 | 2944 | ||
| 2864 | max_cmd = instance->max_fw_cmds; | 2945 | max_cmd = instance->max_mfi_cmds; |
| 2865 | 2946 | ||
| 2866 | /* | 2947 | /* |
| 2867 | * instance->cmd_list is an array of struct megasas_cmd pointers. | 2948 | * instance->cmd_list is an array of struct megasas_cmd pointers. |
| @@ -2875,6 +2956,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance) | |||
| 2875 | return -ENOMEM; | 2956 | return -ENOMEM; |
| 2876 | } | 2957 | } |
| 2877 | 2958 | ||
| 2959 | memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd); | ||
| 2878 | 2960 | ||
| 2879 | for (i = 0; i < max_cmd; i++) { | 2961 | for (i = 0; i < max_cmd; i++) { |
| 2880 | instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), | 2962 | instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), |
| @@ -3288,6 +3370,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) | |||
| 3288 | * does not exceed max cmds that the FW can support | 3370 | * does not exceed max cmds that the FW can support |
| 3289 | */ | 3371 | */ |
| 3290 | instance->max_fw_cmds = instance->max_fw_cmds-1; | 3372 | instance->max_fw_cmds = instance->max_fw_cmds-1; |
| 3373 | instance->max_mfi_cmds = instance->max_fw_cmds; | ||
| 3291 | instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> | 3374 | instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> |
| 3292 | 0x10; | 3375 | 0x10; |
| 3293 | /* | 3376 | /* |
| @@ -3381,6 +3464,9 @@ static int megasas_init_fw(struct megasas_instance *instance) | |||
| 3381 | reg_set = instance->reg_set; | 3464 | reg_set = instance->reg_set; |
| 3382 | 3465 | ||
| 3383 | switch (instance->pdev->device) { | 3466 | switch (instance->pdev->device) { |
| 3467 | case PCI_DEVICE_ID_LSI_FUSION: | ||
| 3468 | instance->instancet = &megasas_instance_template_fusion; | ||
| 3469 | break; | ||
| 3384 | case PCI_DEVICE_ID_LSI_SAS1078R: | 3470 | case PCI_DEVICE_ID_LSI_SAS1078R: |
| 3385 | case PCI_DEVICE_ID_LSI_SAS1078DE: | 3471 | case PCI_DEVICE_ID_LSI_SAS1078DE: |
| 3386 | instance->instancet = &megasas_instance_template_ppc; | 3472 | instance->instancet = &megasas_instance_template_ppc; |
| @@ -3482,9 +3568,10 @@ fail_ready_state: | |||
| 3482 | */ | 3568 | */ |
| 3483 | static void megasas_release_mfi(struct megasas_instance *instance) | 3569 | static void megasas_release_mfi(struct megasas_instance *instance) |
| 3484 | { | 3570 | { |
| 3485 | u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1); | 3571 | u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1); |
| 3486 | 3572 | ||
| 3487 | pci_free_consistent(instance->pdev, reply_q_sz, | 3573 | if (instance->reply_queue) |
| 3574 | pci_free_consistent(instance->pdev, reply_q_sz, | ||
| 3488 | instance->reply_queue, instance->reply_queue_h); | 3575 | instance->reply_queue, instance->reply_queue_h); |
| 3489 | 3576 | ||
| 3490 | megasas_free_cmds(instance); | 3577 | megasas_free_cmds(instance); |
| @@ -3678,8 +3765,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, | |||
| 3678 | /* | 3765 | /* |
| 3679 | * Issue the aen registration frame | 3766 | * Issue the aen registration frame |
| 3680 | */ | 3767 | */ |
| 3681 | instance->instancet->fire_cmd(instance, | 3768 | instance->instancet->issue_dcmd(instance, cmd); |
| 3682 | cmd->frame_phys_addr, 0, instance->reg_set); | ||
| 3683 | 3769 | ||
| 3684 | return 0; | 3770 | return 0; |
| 3685 | } | 3771 | } |
| @@ -3756,12 +3842,18 @@ static int megasas_io_attach(struct megasas_instance *instance) | |||
| 3756 | } | 3842 | } |
| 3757 | 3843 | ||
| 3758 | host->max_sectors = instance->max_sectors_per_req; | 3844 | host->max_sectors = instance->max_sectors_per_req; |
| 3759 | host->cmd_per_lun = 128; | 3845 | host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN; |
| 3760 | host->max_channel = MEGASAS_MAX_CHANNELS - 1; | 3846 | host->max_channel = MEGASAS_MAX_CHANNELS - 1; |
| 3761 | host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL; | 3847 | host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL; |
| 3762 | host->max_lun = MEGASAS_MAX_LUN; | 3848 | host->max_lun = MEGASAS_MAX_LUN; |
| 3763 | host->max_cmd_len = 16; | 3849 | host->max_cmd_len = 16; |
| 3764 | 3850 | ||
| 3851 | /* Fusion only supports host reset */ | ||
| 3852 | if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) { | ||
| 3853 | host->hostt->eh_device_reset_handler = NULL; | ||
| 3854 | host->hostt->eh_bus_reset_handler = NULL; | ||
| 3855 | } | ||
| 3856 | |||
| 3765 | /* | 3857 | /* |
| 3766 | * Notify the mid-layer about the new controller | 3858 | * Notify the mid-layer about the new controller |
| 3767 | */ | 3859 | */ |
| @@ -3846,20 +3938,45 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 3846 | instance = (struct megasas_instance *)host->hostdata; | 3938 | instance = (struct megasas_instance *)host->hostdata; |
| 3847 | memset(instance, 0, sizeof(*instance)); | 3939 | memset(instance, 0, sizeof(*instance)); |
| 3848 | atomic_set( &instance->fw_reset_no_pci_access, 0 ); | 3940 | atomic_set( &instance->fw_reset_no_pci_access, 0 ); |
| 3941 | instance->pdev = pdev; | ||
| 3849 | 3942 | ||
| 3850 | instance->producer = pci_alloc_consistent(pdev, sizeof(u32), | 3943 | switch (instance->pdev->device) { |
| 3851 | &instance->producer_h); | 3944 | case PCI_DEVICE_ID_LSI_FUSION: |
| 3852 | instance->consumer = pci_alloc_consistent(pdev, sizeof(u32), | 3945 | { |
| 3853 | &instance->consumer_h); | 3946 | struct fusion_context *fusion; |
| 3947 | |||
| 3948 | instance->ctrl_context = | ||
| 3949 | kzalloc(sizeof(struct fusion_context), GFP_KERNEL); | ||
| 3950 | if (!instance->ctrl_context) { | ||
| 3951 | printk(KERN_DEBUG "megasas: Failed to allocate " | ||
| 3952 | "memory for Fusion context info\n"); | ||
| 3953 | goto fail_alloc_dma_buf; | ||
| 3954 | } | ||
| 3955 | fusion = instance->ctrl_context; | ||
| 3956 | INIT_LIST_HEAD(&fusion->cmd_pool); | ||
| 3957 | spin_lock_init(&fusion->cmd_pool_lock); | ||
| 3958 | } | ||
| 3959 | break; | ||
| 3960 | default: /* For all other supported controllers */ | ||
| 3961 | |||
| 3962 | instance->producer = | ||
| 3963 | pci_alloc_consistent(pdev, sizeof(u32), | ||
| 3964 | &instance->producer_h); | ||
| 3965 | instance->consumer = | ||
| 3966 | pci_alloc_consistent(pdev, sizeof(u32), | ||
| 3967 | &instance->consumer_h); | ||
| 3968 | |||
| 3969 | if (!instance->producer || !instance->consumer) { | ||
| 3970 | printk(KERN_DEBUG "megasas: Failed to allocate" | ||
| 3971 | "memory for producer, consumer\n"); | ||
| 3972 | goto fail_alloc_dma_buf; | ||
| 3973 | } | ||
| 3854 | 3974 | ||
| 3855 | if (!instance->producer || !instance->consumer) { | 3975 | *instance->producer = 0; |
| 3856 | printk(KERN_DEBUG "megasas: Failed to allocate memory for " | 3976 | *instance->consumer = 0; |
| 3857 | "producer, consumer\n"); | 3977 | break; |
| 3858 | goto fail_alloc_dma_buf; | ||
| 3859 | } | 3978 | } |
| 3860 | 3979 | ||
| 3861 | *instance->producer = 0; | ||
| 3862 | *instance->consumer = 0; | ||
| 3863 | megasas_poll_wait_aen = 0; | 3980 | megasas_poll_wait_aen = 0; |
| 3864 | instance->flag_ieee = 0; | 3981 | instance->flag_ieee = 0; |
| 3865 | instance->ev = NULL; | 3982 | instance->ev = NULL; |
| @@ -3895,11 +4012,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 3895 | spin_lock_init(&poll_aen_lock); | 4012 | spin_lock_init(&poll_aen_lock); |
| 3896 | 4013 | ||
| 3897 | mutex_init(&instance->aen_mutex); | 4014 | mutex_init(&instance->aen_mutex); |
| 4015 | mutex_init(&instance->reset_mutex); | ||
| 3898 | 4016 | ||
| 3899 | /* | 4017 | /* |
| 3900 | * Initialize PCI related and misc parameters | 4018 | * Initialize PCI related and misc parameters |
| 3901 | */ | 4019 | */ |
| 3902 | instance->pdev = pdev; | ||
| 3903 | instance->host = host; | 4020 | instance->host = host; |
| 3904 | instance->unique_id = pdev->bus->number << 8 | pdev->devfn; | 4021 | instance->unique_id = pdev->bus->number << 8 | pdev->devfn; |
| 3905 | instance->init_id = MEGASAS_DEFAULT_INIT_ID; | 4022 | instance->init_id = MEGASAS_DEFAULT_INIT_ID; |
| @@ -3917,7 +4034,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 3917 | instance->last_time = 0; | 4034 | instance->last_time = 0; |
| 3918 | instance->disableOnlineCtrlReset = 1; | 4035 | instance->disableOnlineCtrlReset = 1; |
| 3919 | 4036 | ||
| 3920 | INIT_WORK(&instance->work_init, process_fw_state_change_wq); | 4037 | if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) |
| 4038 | INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); | ||
| 4039 | else | ||
| 4040 | INIT_WORK(&instance->work_init, process_fw_state_change_wq); | ||
| 3921 | 4041 | ||
| 3922 | /* | 4042 | /* |
| 3923 | * Initialize MFI Firmware | 4043 | * Initialize MFI Firmware |
| @@ -4000,6 +4120,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 4000 | pci_free_consistent(pdev, sizeof(u32), instance->producer, | 4120 | pci_free_consistent(pdev, sizeof(u32), instance->producer, |
| 4001 | instance->producer_h); | 4121 | instance->producer_h); |
| 4002 | megasas_release_mfi(instance); | 4122 | megasas_release_mfi(instance); |
| 4123 | } else { | ||
| 4124 | megasas_release_fusion(instance); | ||
| 4003 | } | 4125 | } |
| 4004 | if (instance->consumer) | 4126 | if (instance->consumer) |
| 4005 | pci_free_consistent(pdev, sizeof(u32), instance->consumer, | 4127 | pci_free_consistent(pdev, sizeof(u32), instance->consumer, |
| @@ -4072,7 +4194,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, | |||
| 4072 | 4194 | ||
| 4073 | if (instance->aen_cmd) | 4195 | if (instance->aen_cmd) |
| 4074 | megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd); | 4196 | megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd); |
| 4075 | 4197 | if (instance->map_update_cmd) | |
| 4198 | megasas_issue_blocked_abort_cmd(instance, | ||
| 4199 | instance->map_update_cmd); | ||
| 4076 | dcmd = &cmd->frame->dcmd; | 4200 | dcmd = &cmd->frame->dcmd; |
| 4077 | 4201 | ||
| 4078 | memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); | 4202 | memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); |
| @@ -4177,9 +4301,6 @@ megasas_resume(struct pci_dev *pdev) | |||
| 4177 | * Initialize MFI Firmware | 4301 | * Initialize MFI Firmware |
| 4178 | */ | 4302 | */ |
| 4179 | 4303 | ||
| 4180 | *instance->producer = 0; | ||
| 4181 | *instance->consumer = 0; | ||
| 4182 | |||
| 4183 | atomic_set(&instance->fw_outstanding, 0); | 4304 | atomic_set(&instance->fw_outstanding, 0); |
| 4184 | 4305 | ||
| 4185 | /* | 4306 | /* |
| @@ -4188,11 +4309,29 @@ megasas_resume(struct pci_dev *pdev) | |||
| 4188 | if (megasas_transition_to_ready(instance)) | 4309 | if (megasas_transition_to_ready(instance)) |
| 4189 | goto fail_ready_state; | 4310 | goto fail_ready_state; |
| 4190 | 4311 | ||
| 4191 | if (megasas_issue_init_mfi(instance)) | 4312 | switch (instance->pdev->device) { |
| 4192 | goto fail_init_mfi; | 4313 | case PCI_DEVICE_ID_LSI_FUSION: |
| 4314 | { | ||
| 4315 | megasas_reset_reply_desc(instance); | ||
| 4316 | if (megasas_ioc_init_fusion(instance)) { | ||
| 4317 | megasas_free_cmds(instance); | ||
| 4318 | megasas_free_cmds_fusion(instance); | ||
| 4319 | goto fail_init_mfi; | ||
| 4320 | } | ||
| 4321 | if (!megasas_get_map_info(instance)) | ||
| 4322 | megasas_sync_map_info(instance); | ||
| 4323 | } | ||
| 4324 | break; | ||
| 4325 | default: | ||
| 4326 | *instance->producer = 0; | ||
| 4327 | *instance->consumer = 0; | ||
| 4328 | if (megasas_issue_init_mfi(instance)) | ||
| 4329 | goto fail_init_mfi; | ||
| 4330 | break; | ||
| 4331 | } | ||
| 4193 | 4332 | ||
| 4194 | tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, | 4333 | tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, |
| 4195 | (unsigned long)instance); | 4334 | (unsigned long)instance); |
| 4196 | 4335 | ||
| 4197 | /* Now re-enable MSI-X */ | 4336 | /* Now re-enable MSI-X */ |
| 4198 | if (instance->msi_flag) | 4337 | if (instance->msi_flag) |
| @@ -4261,10 +4400,12 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) | |||
| 4261 | int i; | 4400 | int i; |
| 4262 | struct Scsi_Host *host; | 4401 | struct Scsi_Host *host; |
| 4263 | struct megasas_instance *instance; | 4402 | struct megasas_instance *instance; |
| 4403 | struct fusion_context *fusion; | ||
| 4264 | 4404 | ||
| 4265 | instance = pci_get_drvdata(pdev); | 4405 | instance = pci_get_drvdata(pdev); |
| 4266 | instance->unload = 1; | 4406 | instance->unload = 1; |
| 4267 | host = instance->host; | 4407 | host = instance->host; |
| 4408 | fusion = instance->ctrl_context; | ||
| 4268 | 4409 | ||
| 4269 | if (poll_mode_io) | 4410 | if (poll_mode_io) |
| 4270 | del_timer_sync(&instance->io_completion_timer); | 4411 | del_timer_sync(&instance->io_completion_timer); |
| @@ -4306,16 +4447,32 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) | |||
| 4306 | if (instance->msi_flag) | 4447 | if (instance->msi_flag) |
| 4307 | pci_disable_msix(instance->pdev); | 4448 | pci_disable_msix(instance->pdev); |
| 4308 | 4449 | ||
| 4309 | megasas_release_mfi(instance); | 4450 | switch (instance->pdev->device) { |
| 4310 | 4451 | case PCI_DEVICE_ID_LSI_FUSION: | |
| 4311 | pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), | 4452 | megasas_release_fusion(instance); |
| 4312 | instance->evt_detail, instance->evt_detail_h); | 4453 | for (i = 0; i < 2 ; i++) |
| 4313 | 4454 | if (fusion->ld_map[i]) | |
| 4314 | pci_free_consistent(pdev, sizeof(u32), instance->producer, | 4455 | dma_free_coherent(&instance->pdev->dev, |
| 4315 | instance->producer_h); | 4456 | fusion->map_sz, |
| 4316 | 4457 | fusion->ld_map[i], | |
| 4317 | pci_free_consistent(pdev, sizeof(u32), instance->consumer, | 4458 | fusion-> |
| 4318 | instance->consumer_h); | 4459 | ld_map_phys[i]); |
| 4460 | kfree(instance->ctrl_context); | ||
| 4461 | break; | ||
| 4462 | default: | ||
| 4463 | megasas_release_mfi(instance); | ||
| 4464 | pci_free_consistent(pdev, | ||
| 4465 | sizeof(struct megasas_evt_detail), | ||
| 4466 | instance->evt_detail, | ||
| 4467 | instance->evt_detail_h); | ||
| 4468 | pci_free_consistent(pdev, sizeof(u32), | ||
| 4469 | instance->producer, | ||
| 4470 | instance->producer_h); | ||
| 4471 | pci_free_consistent(pdev, sizeof(u32), | ||
| 4472 | instance->consumer, | ||
| 4473 | instance->consumer_h); | ||
| 4474 | break; | ||
| 4475 | } | ||
| 4319 | 4476 | ||
| 4320 | scsi_host_put(host); | 4477 | scsi_host_put(host); |
| 4321 | 4478 | ||
| @@ -5079,6 +5236,7 @@ megasas_aen_polling(struct work_struct *work) | |||
| 5079 | break; | 5236 | break; |
| 5080 | case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: | 5237 | case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: |
| 5081 | case MR_EVT_FOREIGN_CFG_IMPORTED: | 5238 | case MR_EVT_FOREIGN_CFG_IMPORTED: |
| 5239 | case MR_EVT_LD_STATE_CHANGE: | ||
| 5082 | doscan = 1; | 5240 | doscan = 1; |
| 5083 | break; | 5241 | break; |
| 5084 | default: | 5242 | default: |
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c new file mode 100644 index 000000000000..53fa96ae2b3e --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c | |||
| @@ -0,0 +1,516 @@ | |||
| 1 | /* | ||
| 2 | * Linux MegaRAID driver for SAS based RAID controllers | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009-2011 LSI Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * | ||
| 20 | * FILE: megaraid_sas_fp.c | ||
| 21 | * | ||
| 22 | * Authors: LSI Corporation | ||
| 23 | * Sumant Patro | ||
| 24 | * Varad Talamacki | ||
| 25 | * Manoj Jose | ||
| 26 | * | ||
| 27 | * Send feedback to: <megaraidlinux@lsi.com> | ||
| 28 | * | ||
| 29 | * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 | ||
| 30 | * ATTN: Linuxraid | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/kernel.h> | ||
| 34 | #include <linux/types.h> | ||
| 35 | #include <linux/pci.h> | ||
| 36 | #include <linux/list.h> | ||
| 37 | #include <linux/moduleparam.h> | ||
| 38 | #include <linux/module.h> | ||
| 39 | #include <linux/spinlock.h> | ||
| 40 | #include <linux/interrupt.h> | ||
| 41 | #include <linux/delay.h> | ||
| 42 | #include <linux/smp_lock.h> | ||
| 43 | #include <linux/uio.h> | ||
| 44 | #include <linux/uaccess.h> | ||
| 45 | #include <linux/fs.h> | ||
| 46 | #include <linux/compat.h> | ||
| 47 | #include <linux/blkdev.h> | ||
| 48 | #include <linux/poll.h> | ||
| 49 | |||
| 50 | #include <scsi/scsi.h> | ||
| 51 | #include <scsi/scsi_cmnd.h> | ||
| 52 | #include <scsi/scsi_device.h> | ||
| 53 | #include <scsi/scsi_host.h> | ||
| 54 | |||
| 55 | #include "megaraid_sas_fusion.h" | ||
| 56 | #include <asm/div64.h> | ||
| 57 | |||
| 58 | #define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) | ||
| 59 | #define MR_LD_STATE_OPTIMAL 3 | ||
| 60 | #define FALSE 0 | ||
| 61 | #define TRUE 1 | ||
| 62 | |||
| 63 | /* Prototypes */ | ||
| 64 | void | ||
| 65 | mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map, | ||
| 66 | struct LD_LOAD_BALANCE_INFO *lbInfo); | ||
| 67 | |||
| 68 | u32 mega_mod64(u64 dividend, u32 divisor) | ||
| 69 | { | ||
| 70 | u64 d; | ||
| 71 | u32 remainder; | ||
| 72 | |||
| 73 | if (!divisor) | ||
| 74 | printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n"); | ||
| 75 | d = dividend; | ||
| 76 | remainder = do_div(d, divisor); | ||
| 77 | return remainder; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * @param dividend : Dividend | ||
| 82 | * @param divisor : Divisor | ||
| 83 | * | ||
| 84 | * @return quotient | ||
| 85 | **/ | ||
| 86 | u64 mega_div64_32(uint64_t dividend, uint32_t divisor) | ||
| 87 | { | ||
| 88 | u32 remainder; | ||
| 89 | u64 d; | ||
| 90 | |||
| 91 | if (!divisor) | ||
| 92 | printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n"); | ||
| 93 | |||
| 94 | d = dividend; | ||
| 95 | remainder = do_div(d, divisor); | ||
| 96 | |||
| 97 | return d; | ||
| 98 | } | ||
| 99 | |||
| 100 | struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map) | ||
| 101 | { | ||
| 102 | return &map->raidMap.ldSpanMap[ld].ldRaid; | ||
| 103 | } | ||
| 104 | |||
| 105 | static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld, | ||
| 106 | struct MR_FW_RAID_MAP_ALL | ||
| 107 | *map) | ||
| 108 | { | ||
| 109 | return &map->raidMap.ldSpanMap[ld].spanBlock[0]; | ||
| 110 | } | ||
| 111 | |||
| 112 | static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map) | ||
| 113 | { | ||
| 114 | return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; | ||
| 115 | } | ||
| 116 | |||
| 117 | static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map) | ||
| 118 | { | ||
| 119 | return map->raidMap.arMapInfo[ar].pd[arm]; | ||
| 120 | } | ||
| 121 | |||
| 122 | static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map) | ||
| 123 | { | ||
| 124 | return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef; | ||
| 125 | } | ||
| 126 | |||
| 127 | static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map) | ||
| 128 | { | ||
| 129 | return map->raidMap.devHndlInfo[pd].curDevHdl; | ||
| 130 | } | ||
| 131 | |||
| 132 | u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map) | ||
| 133 | { | ||
| 134 | return map->raidMap.ldSpanMap[ld].ldRaid.targetId; | ||
| 135 | } | ||
| 136 | |||
| 137 | u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map) | ||
| 138 | { | ||
| 139 | return map->raidMap.ldTgtIdToLd[ldTgtId]; | ||
| 140 | } | ||
| 141 | |||
| 142 | static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, | ||
| 143 | struct MR_FW_RAID_MAP_ALL *map) | ||
| 144 | { | ||
| 145 | return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * This function will validate Map info data provided by FW | ||
| 150 | */ | ||
| 151 | u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, | ||
| 152 | struct LD_LOAD_BALANCE_INFO *lbInfo) | ||
| 153 | { | ||
| 154 | struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap; | ||
| 155 | |||
| 156 | if (pFwRaidMap->totalSize != | ||
| 157 | (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) + | ||
| 158 | (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) { | ||
| 159 | printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n", | ||
| 160 | (unsigned int)((sizeof(struct MR_FW_RAID_MAP) - | ||
| 161 | sizeof(struct MR_LD_SPAN_MAP)) + | ||
| 162 | (sizeof(struct MR_LD_SPAN_MAP) * | ||
| 163 | pFwRaidMap->ldCount))); | ||
| 164 | printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize " | ||
| 165 | ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP), | ||
| 166 | pFwRaidMap->totalSize); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | mr_update_load_balance_params(map, lbInfo); | ||
| 171 | |||
| 172 | return 1; | ||
| 173 | } | ||
| 174 | |||
| 175 | u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, | ||
| 176 | struct MR_FW_RAID_MAP_ALL *map, int *div_error) | ||
| 177 | { | ||
| 178 | struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); | ||
| 179 | struct MR_QUAD_ELEMENT *quad; | ||
| 180 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); | ||
| 181 | u32 span, j; | ||
| 182 | |||
| 183 | for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) { | ||
| 184 | |||
| 185 | for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) { | ||
| 186 | quad = &pSpanBlock->block_span_info.quad[j]; | ||
| 187 | |||
| 188 | if (quad->diff == 0) { | ||
| 189 | *div_error = 1; | ||
| 190 | return span; | ||
| 191 | } | ||
| 192 | if (quad->logStart <= row && row <= quad->logEnd && | ||
| 193 | (mega_mod64(row-quad->logStart, quad->diff)) == 0) { | ||
| 194 | if (span_blk != NULL) { | ||
| 195 | u64 blk, debugBlk; | ||
| 196 | blk = | ||
| 197 | mega_div64_32( | ||
| 198 | (row-quad->logStart), | ||
| 199 | quad->diff); | ||
| 200 | debugBlk = blk; | ||
| 201 | |||
| 202 | blk = (blk + quad->offsetInSpan) << | ||
| 203 | raid->stripeShift; | ||
| 204 | *span_blk = blk; | ||
| 205 | } | ||
| 206 | return span; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | return span; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* | ||
| 214 | ****************************************************************************** | ||
| 215 | * | ||
| 216 | * This routine calculates the arm, span and block for the specified stripe and | ||
| 217 | * reference in stripe. | ||
| 218 | * | ||
| 219 | * Inputs : | ||
| 220 | * | ||
| 221 | * ld - Logical drive number | ||
| 222 | * stripRow - Stripe number | ||
| 223 | * stripRef - Reference in stripe | ||
| 224 | * | ||
| 225 | * Outputs : | ||
| 226 | * | ||
| 227 | * span - Span number | ||
| 228 | * block - Absolute Block number in the physical disk | ||
| 229 | */ | ||
| 230 | u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock, | ||
| 231 | u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context, | ||
| 232 | struct MR_FW_RAID_MAP_ALL *map) | ||
| 233 | { | ||
| 234 | struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); | ||
| 235 | u32 pd, arRef; | ||
| 236 | u8 physArm, span; | ||
| 237 | u64 row; | ||
| 238 | u8 retval = TRUE; | ||
| 239 | int error_code = 0; | ||
| 240 | |||
| 241 | row = mega_div64_32(stripRow, raid->rowDataSize); | ||
| 242 | |||
| 243 | if (raid->level == 6) { | ||
| 244 | /* logical arm within row */ | ||
| 245 | u32 logArm = mega_mod64(stripRow, raid->rowDataSize); | ||
| 246 | u32 rowMod, armQ, arm; | ||
| 247 | |||
| 248 | if (raid->rowSize == 0) | ||
| 249 | return FALSE; | ||
| 250 | /* get logical row mod */ | ||
| 251 | rowMod = mega_mod64(row, raid->rowSize); | ||
| 252 | armQ = raid->rowSize-1-rowMod; /* index of Q drive */ | ||
| 253 | arm = armQ+1+logArm; /* data always logically follows Q */ | ||
| 254 | if (arm >= raid->rowSize) /* handle wrap condition */ | ||
| 255 | arm -= raid->rowSize; | ||
| 256 | physArm = (u8)arm; | ||
| 257 | } else { | ||
| 258 | if (raid->modFactor == 0) | ||
| 259 | return FALSE; | ||
| 260 | physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, | ||
| 261 | raid->modFactor), | ||
| 262 | map); | ||
| 263 | } | ||
| 264 | |||
| 265 | if (raid->spanDepth == 1) { | ||
| 266 | span = 0; | ||
| 267 | *pdBlock = row << raid->stripeShift; | ||
| 268 | } else { | ||
| 269 | span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code); | ||
| 270 | if (error_code == 1) | ||
| 271 | return FALSE; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* Get the array on which this span is present */ | ||
| 275 | arRef = MR_LdSpanArrayGet(ld, span, map); | ||
| 276 | pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ | ||
| 277 | |||
| 278 | if (pd != MR_PD_INVALID) | ||
| 279 | /* Get dev handle from Pd. */ | ||
| 280 | *pDevHandle = MR_PdDevHandleGet(pd, map); | ||
| 281 | else { | ||
| 282 | *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */ | ||
| 283 | if (raid->level >= 5) | ||
| 284 | pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; | ||
| 285 | else if (raid->level == 1) { | ||
| 286 | /* Get alternate Pd. */ | ||
| 287 | pd = MR_ArPdGet(arRef, physArm + 1, map); | ||
| 288 | if (pd != MR_PD_INVALID) | ||
| 289 | /* Get dev handle from Pd */ | ||
| 290 | *pDevHandle = MR_PdDevHandleGet(pd, map); | ||
| 291 | } | ||
| 292 | retval = FALSE; | ||
| 293 | } | ||
| 294 | |||
| 295 | *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; | ||
| 296 | pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | | ||
| 297 | physArm; | ||
| 298 | return retval; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | ****************************************************************************** | ||
| 303 | * | ||
| 304 | * MR_BuildRaidContext function | ||
| 305 | * | ||
| 306 | * This function will initiate command processing. The start/end row and strip | ||
| 307 | * information is calculated then the lock is acquired. | ||
| 308 | * This function will return 0 if region lock was acquired OR return num strips | ||
| 309 | */ | ||
| 310 | u8 | ||
| 311 | MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info, | ||
| 312 | struct RAID_CONTEXT *pRAID_Context, | ||
| 313 | struct MR_FW_RAID_MAP_ALL *map) | ||
| 314 | { | ||
| 315 | struct MR_LD_RAID *raid; | ||
| 316 | u32 ld, stripSize, stripe_mask; | ||
| 317 | u64 endLba, endStrip, endRow, start_row, start_strip; | ||
| 318 | u64 regStart; | ||
| 319 | u32 regSize; | ||
| 320 | u8 num_strips, numRows; | ||
| 321 | u16 ref_in_start_stripe, ref_in_end_stripe; | ||
| 322 | u64 ldStartBlock; | ||
| 323 | u32 numBlocks, ldTgtId; | ||
| 324 | u8 isRead; | ||
| 325 | u8 retval = 0; | ||
| 326 | |||
| 327 | ldStartBlock = io_info->ldStartBlock; | ||
| 328 | numBlocks = io_info->numBlocks; | ||
| 329 | ldTgtId = io_info->ldTgtId; | ||
| 330 | isRead = io_info->isRead; | ||
| 331 | |||
| 332 | ld = MR_TargetIdToLdGet(ldTgtId, map); | ||
| 333 | raid = MR_LdRaidGet(ld, map); | ||
| 334 | |||
| 335 | stripSize = 1 << raid->stripeShift; | ||
| 336 | stripe_mask = stripSize-1; | ||
| 337 | /* | ||
| 338 | * calculate starting row and stripe, and number of strips and rows | ||
| 339 | */ | ||
| 340 | start_strip = ldStartBlock >> raid->stripeShift; | ||
| 341 | ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask); | ||
| 342 | endLba = ldStartBlock + numBlocks - 1; | ||
| 343 | ref_in_end_stripe = (u16)(endLba & stripe_mask); | ||
| 344 | endStrip = endLba >> raid->stripeShift; | ||
| 345 | num_strips = (u8)(endStrip - start_strip + 1); /* End strip */ | ||
| 346 | if (raid->rowDataSize == 0) | ||
| 347 | return FALSE; | ||
| 348 | start_row = mega_div64_32(start_strip, raid->rowDataSize); | ||
| 349 | endRow = mega_div64_32(endStrip, raid->rowDataSize); | ||
| 350 | numRows = (u8)(endRow - start_row + 1); | ||
| 351 | |||
| 352 | /* | ||
| 353 | * calculate region info. | ||
| 354 | */ | ||
| 355 | |||
| 356 | /* assume region is at the start of the first row */ | ||
| 357 | regStart = start_row << raid->stripeShift; | ||
| 358 | /* assume this IO needs the full row - we'll adjust if not true */ | ||
| 359 | regSize = stripSize; | ||
| 360 | |||
| 361 | /* If IO spans more than 1 strip, fp is not possible | ||
| 362 | FP is not possible for writes on non-0 raid levels | ||
| 363 | FP is not possible if LD is not capable */ | ||
| 364 | if (num_strips > 1 || (!isRead && raid->level != 0) || | ||
| 365 | !raid->capability.fpCapable) { | ||
| 366 | io_info->fpOkForIo = FALSE; | ||
| 367 | } else { | ||
| 368 | io_info->fpOkForIo = TRUE; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (numRows == 1) { | ||
| 372 | /* single-strip IOs can always lock only the data needed */ | ||
| 373 | if (num_strips == 1) { | ||
| 374 | regStart += ref_in_start_stripe; | ||
| 375 | regSize = numBlocks; | ||
| 376 | } | ||
| 377 | /* multi-strip IOs always need to full stripe locked */ | ||
| 378 | } else { | ||
| 379 | if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { | ||
| 380 | /* If the start strip is the last in the start row */ | ||
| 381 | regStart += ref_in_start_stripe; | ||
| 382 | regSize = stripSize - ref_in_start_stripe; | ||
| 383 | /* initialize count to sectors from startref to end | ||
| 384 | of strip */ | ||
| 385 | } | ||
| 386 | |||
| 387 | if (numRows > 2) | ||
| 388 | /* Add complete rows in the middle of the transfer */ | ||
| 389 | regSize += (numRows-2) << raid->stripeShift; | ||
| 390 | |||
| 391 | /* if IO ends within first strip of last row */ | ||
| 392 | if (endStrip == endRow*raid->rowDataSize) | ||
| 393 | regSize += ref_in_end_stripe+1; | ||
| 394 | else | ||
| 395 | regSize += stripSize; | ||
| 396 | } | ||
| 397 | |||
| 398 | pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; | ||
| 399 | pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ : | ||
| 400 | raid->regTypeReqOnWrite; | ||
| 401 | pRAID_Context->VirtualDiskTgtId = raid->targetId; | ||
| 402 | pRAID_Context->regLockRowLBA = regStart; | ||
| 403 | pRAID_Context->regLockLength = regSize; | ||
| 404 | pRAID_Context->configSeqNum = raid->seqNum; | ||
| 405 | |||
| 406 | /*Get Phy Params only if FP capable, or else leave it to MR firmware | ||
| 407 | to do the calculation.*/ | ||
| 408 | if (io_info->fpOkForIo) { | ||
| 409 | retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe, | ||
| 410 | &io_info->pdBlock, | ||
| 411 | &io_info->devHandle, pRAID_Context, | ||
| 412 | map); | ||
| 413 | /* If IO on an invalid Pd, then FP i snot possible */ | ||
| 414 | if (io_info->devHandle == MR_PD_INVALID) | ||
| 415 | io_info->fpOkForIo = FALSE; | ||
| 416 | return retval; | ||
| 417 | } else if (isRead) { | ||
| 418 | uint stripIdx; | ||
| 419 | for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { | ||
| 420 | if (!MR_GetPhyParams(ld, start_strip + stripIdx, | ||
| 421 | ref_in_start_stripe, | ||
| 422 | &io_info->pdBlock, | ||
| 423 | &io_info->devHandle, | ||
| 424 | pRAID_Context, map)) | ||
| 425 | return TRUE; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | return TRUE; | ||
| 429 | } | ||
| 430 | |||
| 431 | void | ||
| 432 | mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map, | ||
| 433 | struct LD_LOAD_BALANCE_INFO *lbInfo) | ||
| 434 | { | ||
| 435 | int ldCount; | ||
| 436 | u16 ld; | ||
| 437 | struct MR_LD_RAID *raid; | ||
| 438 | |||
| 439 | for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) { | ||
| 440 | ld = MR_TargetIdToLdGet(ldCount, map); | ||
| 441 | if (ld >= MAX_LOGICAL_DRIVES) { | ||
| 442 | lbInfo[ldCount].loadBalanceFlag = 0; | ||
| 443 | continue; | ||
| 444 | } | ||
| 445 | |||
| 446 | raid = MR_LdRaidGet(ld, map); | ||
| 447 | |||
| 448 | /* Two drive Optimal RAID 1 */ | ||
| 449 | if ((raid->level == 1) && (raid->rowSize == 2) && | ||
| 450 | (raid->spanDepth == 1) && raid->ldState == | ||
| 451 | MR_LD_STATE_OPTIMAL) { | ||
| 452 | u32 pd, arRef; | ||
| 453 | |||
| 454 | lbInfo[ldCount].loadBalanceFlag = 1; | ||
| 455 | |||
| 456 | /* Get the array on which this span is present */ | ||
| 457 | arRef = MR_LdSpanArrayGet(ld, 0, map); | ||
| 458 | |||
| 459 | /* Get the Pd */ | ||
| 460 | pd = MR_ArPdGet(arRef, 0, map); | ||
| 461 | /* Get dev handle from Pd */ | ||
| 462 | lbInfo[ldCount].raid1DevHandle[0] = | ||
| 463 | MR_PdDevHandleGet(pd, map); | ||
| 464 | /* Get the Pd */ | ||
| 465 | pd = MR_ArPdGet(arRef, 1, map); | ||
| 466 | |||
| 467 | /* Get the dev handle from Pd */ | ||
| 468 | lbInfo[ldCount].raid1DevHandle[1] = | ||
| 469 | MR_PdDevHandleGet(pd, map); | ||
| 470 | } else | ||
| 471 | lbInfo[ldCount].loadBalanceFlag = 0; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block, | ||
| 476 | u32 count) | ||
| 477 | { | ||
| 478 | u16 pend0, pend1; | ||
| 479 | u64 diff0, diff1; | ||
| 480 | u8 bestArm; | ||
| 481 | |||
| 482 | /* get the pending cmds for the data and mirror arms */ | ||
| 483 | pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]); | ||
| 484 | pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]); | ||
| 485 | |||
| 486 | /* Determine the disk whose head is nearer to the req. block */ | ||
| 487 | diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]); | ||
| 488 | diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]); | ||
| 489 | bestArm = (diff0 <= diff1 ? 0 : 1); | ||
| 490 | |||
| 491 | if ((bestArm == arm && pend0 > pend1 + 16) || | ||
| 492 | (bestArm != arm && pend1 > pend0 + 16)) | ||
| 493 | bestArm ^= 1; | ||
| 494 | |||
| 495 | /* Update the last accessed block on the correct pd */ | ||
| 496 | lbInfo->last_accessed_block[bestArm] = block + count - 1; | ||
| 497 | |||
| 498 | return bestArm; | ||
| 499 | } | ||
| 500 | |||
| 501 | u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo, | ||
| 502 | struct IO_REQUEST_INFO *io_info) | ||
| 503 | { | ||
| 504 | u8 arm, old_arm; | ||
| 505 | u16 devHandle; | ||
| 506 | |||
| 507 | old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1; | ||
| 508 | |||
| 509 | /* get best new arm */ | ||
| 510 | arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, | ||
| 511 | io_info->numBlocks); | ||
| 512 | devHandle = lbInfo->raid1DevHandle[arm]; | ||
| 513 | atomic_inc(&lbInfo->scsi_pending_cmds[arm]); | ||
| 514 | |||
| 515 | return devHandle; | ||
| 516 | } | ||
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c new file mode 100644 index 000000000000..c1e09d5a6196 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c | |||
| @@ -0,0 +1,2248 @@ | |||
| 1 | /* | ||
| 2 | * Linux MegaRAID driver for SAS based RAID controllers | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009-2011 LSI Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * | ||
| 20 | * FILE: megaraid_sas_fusion.c | ||
| 21 | * | ||
| 22 | * Authors: LSI Corporation | ||
| 23 | * Sumant Patro | ||
| 24 | * Adam Radford <linuxraid@lsi.com> | ||
| 25 | * | ||
| 26 | * Send feedback to: <megaraidlinux@lsi.com> | ||
| 27 | * | ||
| 28 | * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 | ||
| 29 | * ATTN: Linuxraid | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/pci.h> | ||
| 35 | #include <linux/list.h> | ||
| 36 | #include <linux/moduleparam.h> | ||
| 37 | #include <linux/module.h> | ||
| 38 | #include <linux/spinlock.h> | ||
| 39 | #include <linux/interrupt.h> | ||
| 40 | #include <linux/delay.h> | ||
| 41 | #include <linux/smp_lock.h> | ||
| 42 | #include <linux/uio.h> | ||
| 43 | #include <linux/uaccess.h> | ||
| 44 | #include <linux/fs.h> | ||
| 45 | #include <linux/compat.h> | ||
| 46 | #include <linux/blkdev.h> | ||
| 47 | #include <linux/mutex.h> | ||
| 48 | #include <linux/poll.h> | ||
| 49 | |||
| 50 | #include <scsi/scsi.h> | ||
| 51 | #include <scsi/scsi_cmnd.h> | ||
| 52 | #include <scsi/scsi_device.h> | ||
| 53 | #include <scsi/scsi_host.h> | ||
| 54 | |||
| 55 | #include "megaraid_sas_fusion.h" | ||
| 56 | #include "megaraid_sas.h" | ||
| 57 | |||
| 58 | extern void megasas_free_cmds(struct megasas_instance *instance); | ||
| 59 | extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance | ||
| 60 | *instance); | ||
| 61 | extern void | ||
| 62 | megasas_complete_cmd(struct megasas_instance *instance, | ||
| 63 | struct megasas_cmd *cmd, u8 alt_status); | ||
| 64 | int megasas_is_ldio(struct scsi_cmnd *cmd); | ||
| 65 | int | ||
| 66 | wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd); | ||
| 67 | |||
| 68 | void | ||
| 69 | megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd); | ||
| 70 | int megasas_alloc_cmds(struct megasas_instance *instance); | ||
| 71 | int | ||
| 72 | megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs); | ||
| 73 | int | ||
| 74 | megasas_issue_polled(struct megasas_instance *instance, | ||
| 75 | struct megasas_cmd *cmd); | ||
| 76 | |||
| 77 | u8 | ||
| 78 | MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info, | ||
| 79 | struct RAID_CONTEXT *pRAID_Context, | ||
| 80 | struct MR_FW_RAID_MAP_ALL *map); | ||
| 81 | u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map); | ||
| 82 | struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map); | ||
| 83 | |||
| 84 | u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map); | ||
| 85 | u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, | ||
| 86 | struct LD_LOAD_BALANCE_INFO *lbInfo); | ||
| 87 | u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo, | ||
| 88 | struct IO_REQUEST_INFO *in_info); | ||
| 89 | int megasas_transition_to_ready(struct megasas_instance *instance); | ||
| 90 | void megaraid_sas_kill_hba(struct megasas_instance *instance); | ||
| 91 | |||
| 92 | extern u32 megasas_dbg_lvl; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * megasas_enable_intr_fusion - Enables interrupts | ||
| 96 | * @regs: MFI register set | ||
| 97 | */ | ||
| 98 | void | ||
| 99 | megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs) | ||
| 100 | { | ||
| 101 | writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); | ||
| 102 | |||
| 103 | /* Dummy readl to force pci flush */ | ||
| 104 | readl(®s->outbound_intr_mask); | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * megasas_disable_intr_fusion - Disables interrupt | ||
| 109 | * @regs: MFI register set | ||
| 110 | */ | ||
| 111 | void | ||
| 112 | megasas_disable_intr_fusion(struct megasas_register_set __iomem *regs) | ||
| 113 | { | ||
| 114 | u32 mask = 0xFFFFFFFF; | ||
| 115 | u32 status; | ||
| 116 | |||
| 117 | writel(mask, ®s->outbound_intr_mask); | ||
| 118 | /* Dummy readl to force pci flush */ | ||
| 119 | status = readl(®s->outbound_intr_mask); | ||
| 120 | } | ||
| 121 | |||
| 122 | int | ||
| 123 | megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs) | ||
| 124 | { | ||
| 125 | u32 status; | ||
| 126 | /* | ||
| 127 | * Check if it is our interrupt | ||
| 128 | */ | ||
| 129 | status = readl(®s->outbound_intr_status); | ||
| 130 | |||
| 131 | if (status & 1) { | ||
| 132 | writel(status, ®s->outbound_intr_status); | ||
| 133 | readl(®s->outbound_intr_status); | ||
| 134 | return 1; | ||
| 135 | } | ||
| 136 | if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) | ||
| 137 | return 0; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * dummy read to flush PCI | ||
| 141 | */ | ||
| 142 | readl(®s->outbound_intr_status); | ||
| 143 | |||
| 144 | return 1; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * megasas_get_cmd_fusion - Get a command from the free pool | ||
| 149 | * @instance: Adapter soft state | ||
| 150 | * | ||
| 151 | * Returns a free command from the pool | ||
| 152 | */ | ||
| 153 | struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance | ||
| 154 | *instance) | ||
| 155 | { | ||
| 156 | unsigned long flags; | ||
| 157 | struct fusion_context *fusion = | ||
| 158 | (struct fusion_context *)instance->ctrl_context; | ||
| 159 | struct megasas_cmd_fusion *cmd = NULL; | ||
| 160 | |||
| 161 | spin_lock_irqsave(&fusion->cmd_pool_lock, flags); | ||
| 162 | |||
| 163 | if (!list_empty(&fusion->cmd_pool)) { | ||
| 164 | cmd = list_entry((&fusion->cmd_pool)->next, | ||
| 165 | struct megasas_cmd_fusion, list); | ||
| 166 | list_del_init(&cmd->list); | ||
| 167 | } else { | ||
| 168 | printk(KERN_ERR "megasas: Command pool (fusion) empty!\n"); | ||
| 169 | } | ||
| 170 | |||
| 171 | spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags); | ||
| 172 | return cmd; | ||
| 173 | } | ||
| 174 | |||
| 175 | /** | ||
| 176 | * megasas_return_cmd_fusion - Return a cmd to free command pool | ||
| 177 | * @instance: Adapter soft state | ||
| 178 | * @cmd: Command packet to be returned to free command pool | ||
| 179 | */ | ||
| 180 | static inline void | ||
| 181 | megasas_return_cmd_fusion(struct megasas_instance *instance, | ||
| 182 | struct megasas_cmd_fusion *cmd) | ||
| 183 | { | ||
| 184 | unsigned long flags; | ||
| 185 | struct fusion_context *fusion = | ||
| 186 | (struct fusion_context *)instance->ctrl_context; | ||
| 187 | |||
| 188 | spin_lock_irqsave(&fusion->cmd_pool_lock, flags); | ||
| 189 | |||
| 190 | cmd->scmd = NULL; | ||
| 191 | cmd->sync_cmd_idx = (u32)ULONG_MAX; | ||
| 192 | list_add_tail(&cmd->list, &fusion->cmd_pool); | ||
| 193 | |||
| 194 | spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags); | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool | ||
| 199 | * @instance: Adapter soft state | ||
| 200 | */ | ||
| 201 | static void megasas_teardown_frame_pool_fusion( | ||
| 202 | struct megasas_instance *instance) | ||
| 203 | { | ||
| 204 | int i; | ||
| 205 | struct fusion_context *fusion = instance->ctrl_context; | ||
| 206 | |||
| 207 | u16 max_cmd = instance->max_fw_cmds; | ||
| 208 | |||
| 209 | struct megasas_cmd_fusion *cmd; | ||
| 210 | |||
| 211 | if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { | ||
| 212 | printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, " | ||
| 213 | "sense pool : %p\n", fusion->sg_dma_pool, | ||
| 214 | fusion->sense_dma_pool); | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Return all frames to pool | ||
| 220 | */ | ||
| 221 | for (i = 0; i < max_cmd; i++) { | ||
| 222 | |||
| 223 | cmd = fusion->cmd_list[i]; | ||
| 224 | |||
| 225 | if (cmd->sg_frame) | ||
| 226 | pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, | ||
| 227 | cmd->sg_frame_phys_addr); | ||
| 228 | |||
| 229 | if (cmd->sense) | ||
| 230 | pci_pool_free(fusion->sense_dma_pool, cmd->sense, | ||
| 231 | cmd->sense_phys_addr); | ||
| 232 | } | ||
| 233 | |||
| 234 | /* | ||
| 235 | * Now destroy the pool itself | ||
| 236 | */ | ||
| 237 | pci_pool_destroy(fusion->sg_dma_pool); | ||
| 238 | pci_pool_destroy(fusion->sense_dma_pool); | ||
| 239 | |||
| 240 | fusion->sg_dma_pool = NULL; | ||
| 241 | fusion->sense_dma_pool = NULL; | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 245 | * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool | ||
| 246 | * @instance: Adapter soft state | ||
| 247 | */ | ||
| 248 | void | ||
| 249 | megasas_free_cmds_fusion(struct megasas_instance *instance) | ||
| 250 | { | ||
| 251 | int i; | ||
| 252 | struct fusion_context *fusion = instance->ctrl_context; | ||
| 253 | |||
| 254 | u32 max_cmds, req_sz, reply_sz, io_frames_sz; | ||
| 255 | |||
| 256 | |||
| 257 | req_sz = fusion->request_alloc_sz; | ||
| 258 | reply_sz = fusion->reply_alloc_sz; | ||
| 259 | io_frames_sz = fusion->io_frames_alloc_sz; | ||
| 260 | |||
| 261 | max_cmds = instance->max_fw_cmds; | ||
| 262 | |||
| 263 | /* Free descriptors and request Frames memory */ | ||
| 264 | if (fusion->req_frames_desc) | ||
| 265 | dma_free_coherent(&instance->pdev->dev, req_sz, | ||
| 266 | fusion->req_frames_desc, | ||
| 267 | fusion->req_frames_desc_phys); | ||
| 268 | |||
| 269 | if (fusion->reply_frames_desc) { | ||
| 270 | pci_pool_free(fusion->reply_frames_desc_pool, | ||
| 271 | fusion->reply_frames_desc, | ||
| 272 | fusion->reply_frames_desc_phys); | ||
| 273 | pci_pool_destroy(fusion->reply_frames_desc_pool); | ||
| 274 | } | ||
| 275 | |||
| 276 | if (fusion->io_request_frames) { | ||
| 277 | pci_pool_free(fusion->io_request_frames_pool, | ||
| 278 | fusion->io_request_frames, | ||
| 279 | fusion->io_request_frames_phys); | ||
| 280 | pci_pool_destroy(fusion->io_request_frames_pool); | ||
| 281 | } | ||
| 282 | |||
| 283 | /* Free the Fusion frame pool */ | ||
| 284 | megasas_teardown_frame_pool_fusion(instance); | ||
| 285 | |||
| 286 | /* Free all the commands in the cmd_list */ | ||
| 287 | for (i = 0; i < max_cmds; i++) | ||
| 288 | kfree(fusion->cmd_list[i]); | ||
| 289 | |||
| 290 | /* Free the cmd_list buffer itself */ | ||
| 291 | kfree(fusion->cmd_list); | ||
| 292 | fusion->cmd_list = NULL; | ||
| 293 | |||
| 294 | INIT_LIST_HEAD(&fusion->cmd_pool); | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames | ||
| 299 | * @instance: Adapter soft state | ||
| 300 | * | ||
| 301 | */ | ||
| 302 | static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) | ||
| 303 | { | ||
| 304 | int i; | ||
| 305 | u32 max_cmd; | ||
| 306 | struct fusion_context *fusion; | ||
| 307 | struct megasas_cmd_fusion *cmd; | ||
| 308 | u32 total_sz_chain_frame; | ||
| 309 | |||
| 310 | fusion = instance->ctrl_context; | ||
| 311 | max_cmd = instance->max_fw_cmds; | ||
| 312 | |||
| 313 | total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME; | ||
| 314 | |||
| 315 | /* | ||
| 316 | * Use DMA pool facility provided by PCI layer | ||
| 317 | */ | ||
| 318 | |||
| 319 | fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion", | ||
| 320 | instance->pdev, | ||
| 321 | total_sz_chain_frame, 4, | ||
| 322 | 0); | ||
| 323 | if (!fusion->sg_dma_pool) { | ||
| 324 | printk(KERN_DEBUG "megasas: failed to setup request pool " | ||
| 325 | "fusion\n"); | ||
| 326 | return -ENOMEM; | ||
| 327 | } | ||
| 328 | fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion", | ||
| 329 | instance->pdev, | ||
| 330 | SCSI_SENSE_BUFFERSIZE, 64, 0); | ||
| 331 | |||
| 332 | if (!fusion->sense_dma_pool) { | ||
| 333 | printk(KERN_DEBUG "megasas: failed to setup sense pool " | ||
| 334 | "fusion\n"); | ||
| 335 | pci_pool_destroy(fusion->sg_dma_pool); | ||
| 336 | fusion->sg_dma_pool = NULL; | ||
| 337 | return -ENOMEM; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* | ||
| 341 | * Allocate and attach a frame to each of the commands in cmd_list | ||
| 342 | */ | ||
| 343 | for (i = 0; i < max_cmd; i++) { | ||
| 344 | |||
| 345 | cmd = fusion->cmd_list[i]; | ||
| 346 | |||
| 347 | cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, | ||
| 348 | GFP_KERNEL, | ||
| 349 | &cmd->sg_frame_phys_addr); | ||
| 350 | |||
| 351 | cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, | ||
| 352 | GFP_KERNEL, &cmd->sense_phys_addr); | ||
| 353 | /* | ||
| 354 | * megasas_teardown_frame_pool_fusion() takes care of freeing | ||
| 355 | * whatever has been allocated | ||
| 356 | */ | ||
| 357 | if (!cmd->sg_frame || !cmd->sense) { | ||
| 358 | printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n"); | ||
| 359 | megasas_teardown_frame_pool_fusion(instance); | ||
| 360 | return -ENOMEM; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | /** | ||
| 367 | * megasas_alloc_cmds_fusion - Allocates the command packets | ||
| 368 | * @instance: Adapter soft state | ||
| 369 | * | ||
| 370 | * | ||
| 371 | * Each frame has a 32-bit field called context. This context is used to get | ||
| 372 | * back the megasas_cmd_fusion from the frame when a frame gets completed | ||
| 373 | * In this driver, the 32 bit values are the indices into an array cmd_list. | ||
| 374 | * This array is used only to look up the megasas_cmd_fusion given the context. | ||
| 375 | * The free commands themselves are maintained in a linked list called cmd_pool. | ||
| 376 | * | ||
| 377 | * cmds are formed in the io_request and sg_frame members of the | ||
| 378 | * megasas_cmd_fusion. The context field is used to get a request descriptor | ||
| 379 | * and is used as SMID of the cmd. | ||
| 380 | * SMID value range is from 1 to max_fw_cmds. | ||
| 381 | */ | ||
| 382 | int | ||
| 383 | megasas_alloc_cmds_fusion(struct megasas_instance *instance) | ||
| 384 | { | ||
| 385 | int i, j; | ||
| 386 | u32 max_cmd, io_frames_sz; | ||
| 387 | struct fusion_context *fusion; | ||
| 388 | struct megasas_cmd_fusion *cmd; | ||
| 389 | union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; | ||
| 390 | u32 offset; | ||
| 391 | dma_addr_t io_req_base_phys; | ||
| 392 | u8 *io_req_base; | ||
| 393 | |||
| 394 | fusion = instance->ctrl_context; | ||
| 395 | |||
| 396 | max_cmd = instance->max_fw_cmds; | ||
| 397 | |||
| 398 | fusion->req_frames_desc = | ||
| 399 | dma_alloc_coherent(&instance->pdev->dev, | ||
| 400 | fusion->request_alloc_sz, | ||
| 401 | &fusion->req_frames_desc_phys, GFP_KERNEL); | ||
| 402 | |||
| 403 | if (!fusion->req_frames_desc) { | ||
| 404 | printk(KERN_ERR "megasas; Could not allocate memory for " | ||
| 405 | "request_frames\n"); | ||
| 406 | goto fail_req_desc; | ||
| 407 | } | ||
| 408 | |||
| 409 | fusion->reply_frames_desc_pool = | ||
| 410 | pci_pool_create("reply_frames pool", instance->pdev, | ||
| 411 | fusion->reply_alloc_sz, 16, 0); | ||
| 412 | |||
| 413 | if (!fusion->reply_frames_desc_pool) { | ||
| 414 | printk(KERN_ERR "megasas; Could not allocate memory for " | ||
| 415 | "reply_frame pool\n"); | ||
| 416 | goto fail_reply_desc; | ||
| 417 | } | ||
| 418 | |||
| 419 | fusion->reply_frames_desc = | ||
| 420 | pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, | ||
| 421 | &fusion->reply_frames_desc_phys); | ||
| 422 | if (!fusion->reply_frames_desc) { | ||
| 423 | printk(KERN_ERR "megasas; Could not allocate memory for " | ||
| 424 | "reply_frame pool\n"); | ||
| 425 | pci_pool_destroy(fusion->reply_frames_desc_pool); | ||
| 426 | goto fail_reply_desc; | ||
| 427 | } | ||
| 428 | |||
| 429 | reply_desc = fusion->reply_frames_desc; | ||
| 430 | for (i = 0; i < fusion->reply_q_depth; i++, reply_desc++) | ||
| 431 | reply_desc->Words = ULLONG_MAX; | ||
| 432 | |||
| 433 | io_frames_sz = fusion->io_frames_alloc_sz; | ||
| 434 | |||
| 435 | fusion->io_request_frames_pool = | ||
| 436 | pci_pool_create("io_request_frames pool", instance->pdev, | ||
| 437 | fusion->io_frames_alloc_sz, 16, 0); | ||
| 438 | |||
| 439 | if (!fusion->io_request_frames_pool) { | ||
| 440 | printk(KERN_ERR "megasas: Could not allocate memory for " | ||
| 441 | "io_request_frame pool\n"); | ||
| 442 | goto fail_io_frames; | ||
| 443 | } | ||
| 444 | |||
| 445 | fusion->io_request_frames = | ||
| 446 | pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, | ||
| 447 | &fusion->io_request_frames_phys); | ||
| 448 | if (!fusion->io_request_frames) { | ||
| 449 | printk(KERN_ERR "megasas: Could not allocate memory for " | ||
| 450 | "io_request_frames frames\n"); | ||
| 451 | pci_pool_destroy(fusion->io_request_frames_pool); | ||
| 452 | goto fail_io_frames; | ||
| 453 | } | ||
| 454 | |||
| 455 | /* | ||
| 456 | * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. | ||
| 457 | * Allocate the dynamic array first and then allocate individual | ||
| 458 | * commands. | ||
| 459 | */ | ||
| 460 | fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) | ||
| 461 | *max_cmd, GFP_KERNEL); | ||
| 462 | |||
| 463 | if (!fusion->cmd_list) { | ||
| 464 | printk(KERN_DEBUG "megasas: out of memory. Could not alloc " | ||
| 465 | "memory for cmd_list_fusion\n"); | ||
| 466 | goto fail_cmd_list; | ||
| 467 | } | ||
| 468 | |||
| 469 | memset(fusion->cmd_list, 0, sizeof(struct megasas_cmd_fusion *) | ||
| 470 | *max_cmd); | ||
| 471 | |||
| 472 | max_cmd = instance->max_fw_cmds; | ||
| 473 | for (i = 0; i < max_cmd; i++) { | ||
| 474 | fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), | ||
| 475 | GFP_KERNEL); | ||
| 476 | if (!fusion->cmd_list[i]) { | ||
| 477 | printk(KERN_ERR "Could not alloc cmd list fusion\n"); | ||
| 478 | |||
| 479 | for (j = 0; j < i; j++) | ||
| 480 | kfree(fusion->cmd_list[j]); | ||
| 481 | |||
| 482 | kfree(fusion->cmd_list); | ||
| 483 | fusion->cmd_list = NULL; | ||
| 484 | goto fail_cmd_list; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ | ||
| 489 | io_req_base = fusion->io_request_frames + | ||
| 490 | MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; | ||
| 491 | io_req_base_phys = fusion->io_request_frames_phys + | ||
| 492 | MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; | ||
| 493 | |||
| 494 | /* | ||
| 495 | * Add all the commands to command pool (fusion->cmd_pool) | ||
| 496 | */ | ||
| 497 | |||
| 498 | /* SMID 0 is reserved. Set SMID/index from 1 */ | ||
| 499 | for (i = 0; i < max_cmd; i++) { | ||
| 500 | cmd = fusion->cmd_list[i]; | ||
| 501 | offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; | ||
| 502 | memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); | ||
| 503 | cmd->index = i + 1; | ||
| 504 | cmd->scmd = NULL; | ||
| 505 | cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */ | ||
| 506 | cmd->instance = instance; | ||
| 507 | cmd->io_request = | ||
| 508 | (struct MPI2_RAID_SCSI_IO_REQUEST *) | ||
| 509 | (io_req_base + offset); | ||
| 510 | memset(cmd->io_request, 0, | ||
| 511 | sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); | ||
| 512 | cmd->io_request_phys_addr = io_req_base_phys + offset; | ||
| 513 | |||
| 514 | list_add_tail(&cmd->list, &fusion->cmd_pool); | ||
| 515 | } | ||
| 516 | |||
| 517 | /* | ||
| 518 | * Create a frame pool and assign one frame to each cmd | ||
| 519 | */ | ||
| 520 | if (megasas_create_frame_pool_fusion(instance)) { | ||
| 521 | printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); | ||
| 522 | megasas_free_cmds_fusion(instance); | ||
| 523 | goto fail_req_desc; | ||
| 524 | } | ||
| 525 | |||
| 526 | return 0; | ||
| 527 | |||
| 528 | fail_cmd_list: | ||
| 529 | pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames, | ||
| 530 | fusion->io_request_frames_phys); | ||
| 531 | pci_pool_destroy(fusion->io_request_frames_pool); | ||
| 532 | fail_io_frames: | ||
| 533 | dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, | ||
| 534 | fusion->reply_frames_desc, | ||
| 535 | fusion->reply_frames_desc_phys); | ||
| 536 | pci_pool_free(fusion->reply_frames_desc_pool, | ||
| 537 | fusion->reply_frames_desc, | ||
| 538 | fusion->reply_frames_desc_phys); | ||
| 539 | pci_pool_destroy(fusion->reply_frames_desc_pool); | ||
| 540 | |||
| 541 | fail_reply_desc: | ||
| 542 | dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, | ||
| 543 | fusion->req_frames_desc, | ||
| 544 | fusion->req_frames_desc_phys); | ||
| 545 | fail_req_desc: | ||
| 546 | return -ENOMEM; | ||
| 547 | } | ||
| 548 | |||
| 549 | /** | ||
| 550 | * wait_and_poll - Issues a polling command | ||
| 551 | * @instance: Adapter soft state | ||
| 552 | * @cmd: Command packet to be issued | ||
| 553 | * | ||
| 554 | * For polling, MFI requires the cmd_status to be set to 0xFF before posting. | ||
| 555 | */ | ||
| 556 | int | ||
| 557 | wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd) | ||
| 558 | { | ||
| 559 | int i; | ||
| 560 | struct megasas_header *frame_hdr = &cmd->frame->hdr; | ||
| 561 | |||
| 562 | u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000; | ||
| 563 | |||
| 564 | /* | ||
| 565 | * Wait for cmd_status to change | ||
| 566 | */ | ||
| 567 | for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) { | ||
| 568 | rmb(); | ||
| 569 | msleep(20); | ||
| 570 | } | ||
| 571 | |||
| 572 | if (frame_hdr->cmd_status == 0xff) | ||
| 573 | return -ETIME; | ||
| 574 | |||
| 575 | return 0; | ||
| 576 | } | ||
| 577 | |||
| 578 | /** | ||
| 579 | * megasas_ioc_init_fusion - Initializes the FW | ||
| 580 | * @instance: Adapter soft state | ||
| 581 | * | ||
| 582 | * Issues the IOC Init cmd | ||
| 583 | */ | ||
| 584 | int | ||
| 585 | megasas_ioc_init_fusion(struct megasas_instance *instance) | ||
| 586 | { | ||
| 587 | struct megasas_init_frame *init_frame; | ||
| 588 | struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; | ||
| 589 | dma_addr_t ioc_init_handle; | ||
| 590 | u32 context; | ||
| 591 | struct megasas_cmd *cmd; | ||
| 592 | u8 ret; | ||
| 593 | struct fusion_context *fusion; | ||
| 594 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 595 | int i; | ||
| 596 | struct megasas_header *frame_hdr; | ||
| 597 | |||
| 598 | fusion = instance->ctrl_context; | ||
| 599 | |||
| 600 | cmd = megasas_get_cmd(instance); | ||
| 601 | |||
| 602 | if (!cmd) { | ||
| 603 | printk(KERN_ERR "Could not allocate cmd for INIT Frame\n"); | ||
| 604 | ret = 1; | ||
| 605 | goto fail_get_cmd; | ||
| 606 | } | ||
| 607 | |||
| 608 | IOCInitMessage = | ||
| 609 | dma_alloc_coherent(&instance->pdev->dev, | ||
| 610 | sizeof(struct MPI2_IOC_INIT_REQUEST), | ||
| 611 | &ioc_init_handle, GFP_KERNEL); | ||
| 612 | |||
| 613 | if (!IOCInitMessage) { | ||
| 614 | printk(KERN_ERR "Could not allocate memory for " | ||
| 615 | "IOCInitMessage\n"); | ||
| 616 | ret = 1; | ||
| 617 | goto fail_fw_init; | ||
| 618 | } | ||
| 619 | |||
| 620 | memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST)); | ||
| 621 | |||
| 622 | IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT; | ||
| 623 | IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER; | ||
| 624 | IOCInitMessage->MsgVersion = MPI2_VERSION; | ||
| 625 | IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION; | ||
| 626 | IOCInitMessage->SystemRequestFrameSize = | ||
| 627 | MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4; | ||
| 628 | |||
| 629 | IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth; | ||
| 630 | IOCInitMessage->ReplyDescriptorPostQueueAddress = | ||
| 631 | fusion->reply_frames_desc_phys; | ||
| 632 | IOCInitMessage->SystemRequestFrameBaseAddress = | ||
| 633 | fusion->io_request_frames_phys; | ||
| 634 | |||
| 635 | init_frame = (struct megasas_init_frame *)cmd->frame; | ||
| 636 | memset(init_frame, 0, MEGAMFI_FRAME_SIZE); | ||
| 637 | |||
| 638 | frame_hdr = &cmd->frame->hdr; | ||
| 639 | context = init_frame->context; | ||
| 640 | init_frame->context = context; | ||
| 641 | |||
| 642 | frame_hdr->cmd_status = 0xFF; | ||
| 643 | frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; | ||
| 644 | |||
| 645 | init_frame->cmd = MFI_CMD_INIT; | ||
| 646 | init_frame->cmd_status = 0xFF; | ||
| 647 | |||
| 648 | init_frame->queue_info_new_phys_addr_lo = ioc_init_handle; | ||
| 649 | init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST); | ||
| 650 | |||
| 651 | req_desc = | ||
| 652 | (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc; | ||
| 653 | |||
| 654 | req_desc->Words = cmd->frame_phys_addr; | ||
| 655 | req_desc->MFAIo.RequestFlags = | ||
| 656 | (MEGASAS_REQ_DESCRIPT_FLAGS_MFA << | ||
| 657 | MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 658 | |||
| 659 | /* | ||
| 660 | * disable the intr before firing the init frame | ||
| 661 | */ | ||
| 662 | instance->instancet->disable_intr(instance->reg_set); | ||
| 663 | |||
| 664 | for (i = 0; i < (10 * 1000); i += 20) { | ||
| 665 | if (readl(&instance->reg_set->doorbell) & 1) | ||
| 666 | msleep(20); | ||
| 667 | else | ||
| 668 | break; | ||
| 669 | } | ||
| 670 | |||
| 671 | instance->instancet->fire_cmd(instance, req_desc->u.low, | ||
| 672 | req_desc->u.high, instance->reg_set); | ||
| 673 | |||
| 674 | wait_and_poll(instance, cmd); | ||
| 675 | |||
| 676 | frame_hdr = &cmd->frame->hdr; | ||
| 677 | if (frame_hdr->cmd_status != 0) { | ||
| 678 | ret = 1; | ||
| 679 | goto fail_fw_init; | ||
| 680 | } | ||
| 681 | printk(KERN_ERR "megasas:IOC Init cmd success\n"); | ||
| 682 | |||
| 683 | ret = 0; | ||
| 684 | |||
| 685 | fail_fw_init: | ||
| 686 | megasas_return_cmd(instance, cmd); | ||
| 687 | if (IOCInitMessage) | ||
| 688 | dma_free_coherent(&instance->pdev->dev, | ||
| 689 | sizeof(struct MPI2_IOC_INIT_REQUEST), | ||
| 690 | IOCInitMessage, ioc_init_handle); | ||
| 691 | fail_get_cmd: | ||
| 692 | return ret; | ||
| 693 | } | ||
| 694 | |||
| 695 | /* | ||
| 696 | * megasas_return_cmd_for_smid - Returns a cmd_fusion for a SMID | ||
| 697 | * @instance: Adapter soft state | ||
| 698 | * | ||
| 699 | */ | ||
| 700 | void | ||
| 701 | megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid) | ||
| 702 | { | ||
| 703 | struct fusion_context *fusion; | ||
| 704 | struct megasas_cmd_fusion *cmd; | ||
| 705 | |||
| 706 | fusion = instance->ctrl_context; | ||
| 707 | cmd = fusion->cmd_list[smid - 1]; | ||
| 708 | megasas_return_cmd_fusion(instance, cmd); | ||
| 709 | } | ||
| 710 | |||
| 711 | /* | ||
| 712 | * megasas_get_ld_map_info - Returns FW's ld_map structure | ||
| 713 | * @instance: Adapter soft state | ||
| 714 | * @pend: Pend the command or not | ||
| 715 | * Issues an internal command (DCMD) to get the FW's controller PD | ||
| 716 | * list structure. This information is mainly used to find out SYSTEM | ||
| 717 | * supported by the FW. | ||
| 718 | */ | ||
| 719 | static int | ||
| 720 | megasas_get_ld_map_info(struct megasas_instance *instance) | ||
| 721 | { | ||
| 722 | int ret = 0; | ||
| 723 | struct megasas_cmd *cmd; | ||
| 724 | struct megasas_dcmd_frame *dcmd; | ||
| 725 | struct MR_FW_RAID_MAP_ALL *ci; | ||
| 726 | dma_addr_t ci_h = 0; | ||
| 727 | u32 size_map_info; | ||
| 728 | struct fusion_context *fusion; | ||
| 729 | |||
| 730 | cmd = megasas_get_cmd(instance); | ||
| 731 | |||
| 732 | if (!cmd) { | ||
| 733 | printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n"); | ||
| 734 | return -ENOMEM; | ||
| 735 | } | ||
| 736 | |||
| 737 | fusion = instance->ctrl_context; | ||
| 738 | |||
| 739 | if (!fusion) { | ||
| 740 | megasas_return_cmd(instance, cmd); | ||
| 741 | return 1; | ||
| 742 | } | ||
| 743 | |||
| 744 | dcmd = &cmd->frame->dcmd; | ||
| 745 | |||
| 746 | size_map_info = sizeof(struct MR_FW_RAID_MAP) + | ||
| 747 | (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); | ||
| 748 | |||
| 749 | ci = fusion->ld_map[(instance->map_id & 1)]; | ||
| 750 | ci_h = fusion->ld_map_phys[(instance->map_id & 1)]; | ||
| 751 | |||
| 752 | if (!ci) { | ||
| 753 | printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n"); | ||
| 754 | megasas_return_cmd(instance, cmd); | ||
| 755 | return -ENOMEM; | ||
| 756 | } | ||
| 757 | |||
| 758 | memset(ci, 0, sizeof(*ci)); | ||
| 759 | memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); | ||
| 760 | |||
| 761 | dcmd->cmd = MFI_CMD_DCMD; | ||
| 762 | dcmd->cmd_status = 0xFF; | ||
| 763 | dcmd->sge_count = 1; | ||
| 764 | dcmd->flags = MFI_FRAME_DIR_READ; | ||
| 765 | dcmd->timeout = 0; | ||
| 766 | dcmd->pad_0 = 0; | ||
| 767 | dcmd->data_xfer_len = size_map_info; | ||
| 768 | dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; | ||
| 769 | dcmd->sgl.sge32[0].phys_addr = ci_h; | ||
| 770 | dcmd->sgl.sge32[0].length = size_map_info; | ||
| 771 | |||
| 772 | if (!megasas_issue_polled(instance, cmd)) | ||
| 773 | ret = 0; | ||
| 774 | else { | ||
| 775 | printk(KERN_ERR "megasas: Get LD Map Info Failed\n"); | ||
| 776 | ret = -1; | ||
| 777 | } | ||
| 778 | |||
| 779 | megasas_return_cmd(instance, cmd); | ||
| 780 | |||
| 781 | return ret; | ||
| 782 | } | ||
| 783 | |||
| 784 | u8 | ||
| 785 | megasas_get_map_info(struct megasas_instance *instance) | ||
| 786 | { | ||
| 787 | struct fusion_context *fusion = instance->ctrl_context; | ||
| 788 | |||
| 789 | fusion->fast_path_io = 0; | ||
| 790 | if (!megasas_get_ld_map_info(instance)) { | ||
| 791 | if (MR_ValidateMapInfo(fusion->ld_map[(instance->map_id & 1)], | ||
| 792 | fusion->load_balance_info)) { | ||
| 793 | fusion->fast_path_io = 1; | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | } | ||
| 797 | return 1; | ||
| 798 | } | ||
| 799 | |||
| 800 | /* | ||
| 801 | * megasas_sync_map_info - Returns FW's ld_map structure | ||
| 802 | * @instance: Adapter soft state | ||
| 803 | * | ||
| 804 | * Issues an internal command (DCMD) to get the FW's controller PD | ||
| 805 | * list structure. This information is mainly used to find out SYSTEM | ||
| 806 | * supported by the FW. | ||
| 807 | */ | ||
| 808 | int | ||
| 809 | megasas_sync_map_info(struct megasas_instance *instance) | ||
| 810 | { | ||
| 811 | int ret = 0, i; | ||
| 812 | struct megasas_cmd *cmd; | ||
| 813 | struct megasas_dcmd_frame *dcmd; | ||
| 814 | u32 size_sync_info, num_lds; | ||
| 815 | struct fusion_context *fusion; | ||
| 816 | struct MR_LD_TARGET_SYNC *ci = NULL; | ||
| 817 | struct MR_FW_RAID_MAP_ALL *map; | ||
| 818 | struct MR_LD_RAID *raid; | ||
| 819 | struct MR_LD_TARGET_SYNC *ld_sync; | ||
| 820 | dma_addr_t ci_h = 0; | ||
| 821 | u32 size_map_info; | ||
| 822 | |||
| 823 | cmd = megasas_get_cmd(instance); | ||
| 824 | |||
| 825 | if (!cmd) { | ||
| 826 | printk(KERN_DEBUG "megasas: Failed to get cmd for sync" | ||
| 827 | "info.\n"); | ||
| 828 | return -ENOMEM; | ||
| 829 | } | ||
| 830 | |||
| 831 | fusion = instance->ctrl_context; | ||
| 832 | |||
| 833 | if (!fusion) { | ||
| 834 | megasas_return_cmd(instance, cmd); | ||
| 835 | return 1; | ||
| 836 | } | ||
| 837 | |||
| 838 | map = fusion->ld_map[instance->map_id & 1]; | ||
| 839 | |||
| 840 | num_lds = map->raidMap.ldCount; | ||
| 841 | |||
| 842 | dcmd = &cmd->frame->dcmd; | ||
| 843 | |||
| 844 | size_sync_info = sizeof(struct MR_LD_TARGET_SYNC) *num_lds; | ||
| 845 | |||
| 846 | memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); | ||
| 847 | |||
| 848 | ci = (struct MR_LD_TARGET_SYNC *) | ||
| 849 | fusion->ld_map[(instance->map_id - 1) & 1]; | ||
| 850 | memset(ci, 0, sizeof(struct MR_FW_RAID_MAP_ALL)); | ||
| 851 | |||
| 852 | ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1]; | ||
| 853 | |||
| 854 | ld_sync = (struct MR_LD_TARGET_SYNC *)ci; | ||
| 855 | |||
| 856 | for (i = 0; i < num_lds; i++, ld_sync++) { | ||
| 857 | raid = MR_LdRaidGet(i, map); | ||
| 858 | ld_sync->targetId = MR_GetLDTgtId(i, map); | ||
| 859 | ld_sync->seqNum = raid->seqNum; | ||
| 860 | } | ||
| 861 | |||
| 862 | size_map_info = sizeof(struct MR_FW_RAID_MAP) + | ||
| 863 | (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); | ||
| 864 | |||
| 865 | dcmd->cmd = MFI_CMD_DCMD; | ||
| 866 | dcmd->cmd_status = 0xFF; | ||
| 867 | dcmd->sge_count = 1; | ||
| 868 | dcmd->flags = MFI_FRAME_DIR_WRITE; | ||
| 869 | dcmd->timeout = 0; | ||
| 870 | dcmd->pad_0 = 0; | ||
| 871 | dcmd->data_xfer_len = size_map_info; | ||
| 872 | dcmd->mbox.b[0] = num_lds; | ||
| 873 | dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG; | ||
| 874 | dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; | ||
| 875 | dcmd->sgl.sge32[0].phys_addr = ci_h; | ||
| 876 | dcmd->sgl.sge32[0].length = size_map_info; | ||
| 877 | |||
| 878 | instance->map_update_cmd = cmd; | ||
| 879 | |||
| 880 | instance->instancet->issue_dcmd(instance, cmd); | ||
| 881 | |||
| 882 | return ret; | ||
| 883 | } | ||
| 884 | |||
| 885 | /** | ||
| 886 | * megasas_init_adapter_fusion - Initializes the FW | ||
| 887 | * @instance: Adapter soft state | ||
| 888 | * | ||
| 889 | * This is the main function for initializing firmware. | ||
| 890 | */ | ||
| 891 | u32 | ||
| 892 | megasas_init_adapter_fusion(struct megasas_instance *instance) | ||
| 893 | { | ||
| 894 | struct megasas_register_set __iomem *reg_set; | ||
| 895 | struct fusion_context *fusion; | ||
| 896 | u32 max_cmd; | ||
| 897 | int i = 0; | ||
| 898 | |||
| 899 | fusion = instance->ctrl_context; | ||
| 900 | |||
| 901 | reg_set = instance->reg_set; | ||
| 902 | |||
| 903 | /* | ||
| 904 | * Get various operational parameters from status register | ||
| 905 | */ | ||
| 906 | instance->max_fw_cmds = | ||
| 907 | instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; | ||
| 908 | instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); | ||
| 909 | |||
| 910 | /* | ||
| 911 | * Reduce the max supported cmds by 1. This is to ensure that the | ||
| 912 | * reply_q_sz (1 more than the max cmd that driver may send) | ||
| 913 | * does not exceed max cmds that the FW can support | ||
| 914 | */ | ||
| 915 | instance->max_fw_cmds = instance->max_fw_cmds-1; | ||
| 916 | /* Only internal cmds (DCMD) need to have MFI frames */ | ||
| 917 | instance->max_mfi_cmds = MEGASAS_INT_CMDS; | ||
| 918 | |||
| 919 | max_cmd = instance->max_fw_cmds; | ||
| 920 | |||
| 921 | fusion->reply_q_depth = ((max_cmd + 1 + 15)/16)*16; | ||
| 922 | |||
| 923 | fusion->request_alloc_sz = | ||
| 924 | sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd; | ||
| 925 | fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) | ||
| 926 | *(fusion->reply_q_depth); | ||
| 927 | fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + | ||
| 928 | (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * | ||
| 929 | (max_cmd + 1)); /* Extra 1 for SMID 0 */ | ||
| 930 | |||
| 931 | fusion->max_sge_in_main_msg = | ||
| 932 | (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - | ||
| 933 | offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; | ||
| 934 | |||
| 935 | fusion->max_sge_in_chain = | ||
| 936 | MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION); | ||
| 937 | |||
| 938 | instance->max_num_sge = fusion->max_sge_in_main_msg + | ||
| 939 | fusion->max_sge_in_chain - 2; | ||
| 940 | |||
| 941 | /* Used for pass thru MFI frame (DCMD) */ | ||
| 942 | fusion->chain_offset_mfi_pthru = | ||
| 943 | offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16; | ||
| 944 | |||
| 945 | fusion->chain_offset_io_request = | ||
| 946 | (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - | ||
| 947 | sizeof(union MPI2_SGE_IO_UNION))/16; | ||
| 948 | |||
| 949 | fusion->last_reply_idx = 0; | ||
| 950 | |||
| 951 | /* | ||
| 952 | * Allocate memory for descriptors | ||
| 953 | * Create a pool of commands | ||
| 954 | */ | ||
| 955 | if (megasas_alloc_cmds(instance)) | ||
| 956 | goto fail_alloc_mfi_cmds; | ||
| 957 | if (megasas_alloc_cmds_fusion(instance)) | ||
| 958 | goto fail_alloc_cmds; | ||
| 959 | |||
| 960 | if (megasas_ioc_init_fusion(instance)) | ||
| 961 | goto fail_ioc_init; | ||
| 962 | |||
| 963 | instance->flag_ieee = 1; | ||
| 964 | |||
| 965 | fusion->map_sz = sizeof(struct MR_FW_RAID_MAP) + | ||
| 966 | (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); | ||
| 967 | |||
| 968 | fusion->fast_path_io = 0; | ||
| 969 | |||
| 970 | for (i = 0; i < 2; i++) { | ||
| 971 | fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev, | ||
| 972 | fusion->map_sz, | ||
| 973 | &fusion->ld_map_phys[i], | ||
| 974 | GFP_KERNEL); | ||
| 975 | if (!fusion->ld_map[i]) { | ||
| 976 | printk(KERN_ERR "megasas: Could not allocate memory " | ||
| 977 | "for map info\n"); | ||
| 978 | goto fail_map_info; | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | if (!megasas_get_map_info(instance)) | ||
| 983 | megasas_sync_map_info(instance); | ||
| 984 | |||
| 985 | return 0; | ||
| 986 | |||
| 987 | fail_alloc_cmds: | ||
| 988 | fail_alloc_mfi_cmds: | ||
| 989 | fail_map_info: | ||
| 990 | if (i == 1) | ||
| 991 | dma_free_coherent(&instance->pdev->dev, fusion->map_sz, | ||
| 992 | fusion->ld_map[0], fusion->ld_map_phys[0]); | ||
| 993 | fail_ioc_init: | ||
| 994 | return 1; | ||
| 995 | } | ||
| 996 | |||
| 997 | /** | ||
| 998 | * megasas_fire_cmd_fusion - Sends command to the FW | ||
| 999 | * @frame_phys_addr : Physical address of cmd | ||
| 1000 | * @frame_count : Number of frames for the command | ||
| 1001 | * @regs : MFI register set | ||
| 1002 | */ | ||
| 1003 | void | ||
| 1004 | megasas_fire_cmd_fusion(struct megasas_instance *instance, | ||
| 1005 | dma_addr_t req_desc_lo, | ||
| 1006 | u32 req_desc_hi, | ||
| 1007 | struct megasas_register_set __iomem *regs) | ||
| 1008 | { | ||
| 1009 | unsigned long flags; | ||
| 1010 | |||
| 1011 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
| 1012 | |||
| 1013 | writel(req_desc_lo, | ||
| 1014 | &(regs)->inbound_low_queue_port); | ||
| 1015 | writel(req_desc_hi, &(regs)->inbound_high_queue_port); | ||
| 1016 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | /** | ||
| 1020 | * map_cmd_status - Maps FW cmd status to OS cmd status | ||
| 1021 | * @cmd : Pointer to cmd | ||
| 1022 | * @status : status of cmd returned by FW | ||
| 1023 | * @ext_status : ext status of cmd returned by FW | ||
| 1024 | */ | ||
| 1025 | |||
| 1026 | void | ||
| 1027 | map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status) | ||
| 1028 | { | ||
| 1029 | |||
| 1030 | switch (status) { | ||
| 1031 | |||
| 1032 | case MFI_STAT_OK: | ||
| 1033 | cmd->scmd->result = DID_OK << 16; | ||
| 1034 | break; | ||
| 1035 | |||
| 1036 | case MFI_STAT_SCSI_IO_FAILED: | ||
| 1037 | case MFI_STAT_LD_INIT_IN_PROGRESS: | ||
| 1038 | cmd->scmd->result = (DID_ERROR << 16) | ext_status; | ||
| 1039 | break; | ||
| 1040 | |||
| 1041 | case MFI_STAT_SCSI_DONE_WITH_ERROR: | ||
| 1042 | |||
| 1043 | cmd->scmd->result = (DID_OK << 16) | ext_status; | ||
| 1044 | if (ext_status == SAM_STAT_CHECK_CONDITION) { | ||
| 1045 | memset(cmd->scmd->sense_buffer, 0, | ||
| 1046 | SCSI_SENSE_BUFFERSIZE); | ||
| 1047 | memcpy(cmd->scmd->sense_buffer, cmd->sense, | ||
| 1048 | SCSI_SENSE_BUFFERSIZE); | ||
| 1049 | cmd->scmd->result |= DRIVER_SENSE << 24; | ||
| 1050 | } | ||
| 1051 | break; | ||
| 1052 | |||
| 1053 | case MFI_STAT_LD_OFFLINE: | ||
| 1054 | case MFI_STAT_DEVICE_NOT_FOUND: | ||
| 1055 | cmd->scmd->result = DID_BAD_TARGET << 16; | ||
| 1056 | break; | ||
| 1057 | |||
| 1058 | default: | ||
| 1059 | printk(KERN_DEBUG "megasas: FW status %#x\n", status); | ||
| 1060 | cmd->scmd->result = DID_ERROR << 16; | ||
| 1061 | break; | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /** | ||
| 1066 | * megasas_make_sgl_fusion - Prepares 32-bit SGL | ||
| 1067 | * @instance: Adapter soft state | ||
| 1068 | * @scp: SCSI command from the mid-layer | ||
| 1069 | * @sgl_ptr: SGL to be filled in | ||
| 1070 | * @cmd: cmd we are working on | ||
| 1071 | * | ||
| 1072 | * If successful, this function returns the number of SG elements. | ||
| 1073 | */ | ||
| 1074 | static int | ||
| 1075 | megasas_make_sgl_fusion(struct megasas_instance *instance, | ||
| 1076 | struct scsi_cmnd *scp, | ||
| 1077 | struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr, | ||
| 1078 | struct megasas_cmd_fusion *cmd) | ||
| 1079 | { | ||
| 1080 | int i, sg_processed; | ||
| 1081 | int sge_count, sge_idx; | ||
| 1082 | struct scatterlist *os_sgl; | ||
| 1083 | struct fusion_context *fusion; | ||
| 1084 | |||
| 1085 | fusion = instance->ctrl_context; | ||
| 1086 | |||
| 1087 | cmd->io_request->ChainOffset = 0; | ||
| 1088 | |||
| 1089 | sge_count = scsi_dma_map(scp); | ||
| 1090 | |||
| 1091 | BUG_ON(sge_count < 0); | ||
| 1092 | |||
| 1093 | if (sge_count > instance->max_num_sge || !sge_count) | ||
| 1094 | return sge_count; | ||
| 1095 | |||
| 1096 | if (sge_count > fusion->max_sge_in_main_msg) { | ||
| 1097 | /* One element to store the chain info */ | ||
| 1098 | sge_idx = fusion->max_sge_in_main_msg - 1; | ||
| 1099 | } else | ||
| 1100 | sge_idx = sge_count; | ||
| 1101 | |||
| 1102 | scsi_for_each_sg(scp, os_sgl, sge_count, i) { | ||
| 1103 | sgl_ptr->Length = sg_dma_len(os_sgl); | ||
| 1104 | sgl_ptr->Address = sg_dma_address(os_sgl); | ||
| 1105 | sgl_ptr->Flags = 0; | ||
| 1106 | sgl_ptr++; | ||
| 1107 | |||
| 1108 | sg_processed = i + 1; | ||
| 1109 | |||
| 1110 | if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) && | ||
| 1111 | (sge_count > fusion->max_sge_in_main_msg)) { | ||
| 1112 | |||
| 1113 | struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; | ||
| 1114 | cmd->io_request->ChainOffset = | ||
| 1115 | fusion->chain_offset_io_request; | ||
| 1116 | sg_chain = sgl_ptr; | ||
| 1117 | /* Prepare chain element */ | ||
| 1118 | sg_chain->NextChainOffset = 0; | ||
| 1119 | sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT | | ||
| 1120 | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); | ||
| 1121 | sg_chain->Length = (sizeof(union MPI2_SGE_IO_UNION) | ||
| 1122 | *(sge_count - sg_processed)); | ||
| 1123 | sg_chain->Address = cmd->sg_frame_phys_addr; | ||
| 1124 | |||
| 1125 | sgl_ptr = | ||
| 1126 | (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; | ||
| 1127 | } | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | return sge_count; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /** | ||
| 1134 | * megasas_set_pd_lba - Sets PD LBA | ||
| 1135 | * @cdb: CDB | ||
| 1136 | * @cdb_len: cdb length | ||
| 1137 | * @start_blk: Start block of IO | ||
| 1138 | * | ||
| 1139 | * Used to set the PD LBA in CDB for FP IOs | ||
| 1140 | */ | ||
| 1141 | void | ||
| 1142 | megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, | ||
| 1143 | struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp, | ||
| 1144 | struct MR_FW_RAID_MAP_ALL *local_map_ptr, u32 ref_tag) | ||
| 1145 | { | ||
| 1146 | struct MR_LD_RAID *raid; | ||
| 1147 | u32 ld; | ||
| 1148 | u64 start_blk = io_info->pdBlock; | ||
| 1149 | u8 *cdb = io_request->CDB.CDB32; | ||
| 1150 | u32 num_blocks = io_info->numBlocks; | ||
| 1151 | u8 opcode, flagvals, groupnum, control; | ||
| 1152 | |||
| 1153 | /* Check if T10 PI (DIF) is enabled for this LD */ | ||
| 1154 | ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr); | ||
| 1155 | raid = MR_LdRaidGet(ld, local_map_ptr); | ||
| 1156 | if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { | ||
| 1157 | memset(cdb, 0, sizeof(io_request->CDB.CDB32)); | ||
| 1158 | cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD; | ||
| 1159 | cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN; | ||
| 1160 | |||
| 1161 | if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) | ||
| 1162 | cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32; | ||
| 1163 | else | ||
| 1164 | cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32; | ||
| 1165 | cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL; | ||
| 1166 | |||
| 1167 | /* LBA */ | ||
| 1168 | cdb[12] = (u8)((start_blk >> 56) & 0xff); | ||
| 1169 | cdb[13] = (u8)((start_blk >> 48) & 0xff); | ||
| 1170 | cdb[14] = (u8)((start_blk >> 40) & 0xff); | ||
| 1171 | cdb[15] = (u8)((start_blk >> 32) & 0xff); | ||
| 1172 | cdb[16] = (u8)((start_blk >> 24) & 0xff); | ||
| 1173 | cdb[17] = (u8)((start_blk >> 16) & 0xff); | ||
| 1174 | cdb[18] = (u8)((start_blk >> 8) & 0xff); | ||
| 1175 | cdb[19] = (u8)(start_blk & 0xff); | ||
| 1176 | |||
| 1177 | /* Logical block reference tag */ | ||
| 1178 | io_request->CDB.EEDP32.PrimaryReferenceTag = | ||
| 1179 | cpu_to_be32(ref_tag); | ||
| 1180 | io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff; | ||
| 1181 | |||
| 1182 | io_request->DataLength = num_blocks * 512; | ||
| 1183 | io_request->IoFlags = 32; /* Specify 32-byte cdb */ | ||
| 1184 | |||
| 1185 | /* Transfer length */ | ||
| 1186 | cdb[28] = (u8)((num_blocks >> 24) & 0xff); | ||
| 1187 | cdb[29] = (u8)((num_blocks >> 16) & 0xff); | ||
| 1188 | cdb[30] = (u8)((num_blocks >> 8) & 0xff); | ||
| 1189 | cdb[31] = (u8)(num_blocks & 0xff); | ||
| 1190 | |||
| 1191 | /* set SCSI IO EEDPFlags */ | ||
| 1192 | if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) { | ||
| 1193 | io_request->EEDPFlags = | ||
| 1194 | MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | | ||
| 1195 | MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | | ||
| 1196 | MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | | ||
| 1197 | MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | | ||
| 1198 | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; | ||
| 1199 | } else { | ||
| 1200 | io_request->EEDPFlags = | ||
| 1201 | MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | | ||
| 1202 | MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; | ||
| 1203 | } | ||
| 1204 | io_request->Control |= (0x4 << 26); | ||
| 1205 | io_request->EEDPBlockSize = MEGASAS_EEDPBLOCKSIZE; | ||
| 1206 | } else { | ||
| 1207 | /* Some drives don't support 16/12 byte CDB's, convert to 10 */ | ||
| 1208 | if (((cdb_len == 12) || (cdb_len == 16)) && | ||
| 1209 | (start_blk <= 0xffffffff)) { | ||
| 1210 | if (cdb_len == 16) { | ||
| 1211 | opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10; | ||
| 1212 | flagvals = cdb[1]; | ||
| 1213 | groupnum = cdb[14]; | ||
| 1214 | control = cdb[15]; | ||
| 1215 | } else { | ||
| 1216 | opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10; | ||
| 1217 | flagvals = cdb[1]; | ||
| 1218 | groupnum = cdb[10]; | ||
| 1219 | control = cdb[11]; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | memset(cdb, 0, sizeof(io_request->CDB.CDB32)); | ||
| 1223 | |||
| 1224 | cdb[0] = opcode; | ||
| 1225 | cdb[1] = flagvals; | ||
| 1226 | cdb[6] = groupnum; | ||
| 1227 | cdb[9] = control; | ||
| 1228 | |||
| 1229 | /* Transfer length */ | ||
| 1230 | cdb[8] = (u8)(num_blocks & 0xff); | ||
| 1231 | cdb[7] = (u8)((num_blocks >> 8) & 0xff); | ||
| 1232 | |||
| 1233 | cdb_len = 10; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | /* Normal case, just load LBA here */ | ||
| 1237 | switch (cdb_len) { | ||
| 1238 | case 6: | ||
| 1239 | { | ||
| 1240 | u8 val = cdb[1] & 0xE0; | ||
| 1241 | cdb[3] = (u8)(start_blk & 0xff); | ||
| 1242 | cdb[2] = (u8)((start_blk >> 8) & 0xff); | ||
| 1243 | cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f); | ||
| 1244 | break; | ||
| 1245 | } | ||
| 1246 | case 10: | ||
| 1247 | cdb[5] = (u8)(start_blk & 0xff); | ||
| 1248 | cdb[4] = (u8)((start_blk >> 8) & 0xff); | ||
| 1249 | cdb[3] = (u8)((start_blk >> 16) & 0xff); | ||
| 1250 | cdb[2] = (u8)((start_blk >> 24) & 0xff); | ||
| 1251 | break; | ||
| 1252 | case 12: | ||
| 1253 | cdb[5] = (u8)(start_blk & 0xff); | ||
| 1254 | cdb[4] = (u8)((start_blk >> 8) & 0xff); | ||
| 1255 | cdb[3] = (u8)((start_blk >> 16) & 0xff); | ||
| 1256 | cdb[2] = (u8)((start_blk >> 24) & 0xff); | ||
| 1257 | break; | ||
| 1258 | case 16: | ||
| 1259 | cdb[9] = (u8)(start_blk & 0xff); | ||
| 1260 | cdb[8] = (u8)((start_blk >> 8) & 0xff); | ||
| 1261 | cdb[7] = (u8)((start_blk >> 16) & 0xff); | ||
| 1262 | cdb[6] = (u8)((start_blk >> 24) & 0xff); | ||
| 1263 | cdb[5] = (u8)((start_blk >> 32) & 0xff); | ||
| 1264 | cdb[4] = (u8)((start_blk >> 40) & 0xff); | ||
| 1265 | cdb[3] = (u8)((start_blk >> 48) & 0xff); | ||
| 1266 | cdb[2] = (u8)((start_blk >> 56) & 0xff); | ||
| 1267 | break; | ||
| 1268 | } | ||
| 1269 | } | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | /** | ||
| 1273 | * megasas_build_ldio_fusion - Prepares IOs to devices | ||
| 1274 | * @instance: Adapter soft state | ||
| 1275 | * @scp: SCSI command | ||
| 1276 | * @cmd: Command to be prepared | ||
| 1277 | * | ||
| 1278 | * Prepares the io_request and chain elements (sg_frame) for IO | ||
| 1279 | * The IO can be for PD (Fast Path) or LD | ||
| 1280 | */ | ||
| 1281 | void | ||
| 1282 | megasas_build_ldio_fusion(struct megasas_instance *instance, | ||
| 1283 | struct scsi_cmnd *scp, | ||
| 1284 | struct megasas_cmd_fusion *cmd) | ||
| 1285 | { | ||
| 1286 | u8 fp_possible; | ||
| 1287 | u32 start_lba_lo, start_lba_hi, device_id; | ||
| 1288 | struct MPI2_RAID_SCSI_IO_REQUEST *io_request; | ||
| 1289 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 1290 | struct IO_REQUEST_INFO io_info; | ||
| 1291 | struct fusion_context *fusion; | ||
| 1292 | struct MR_FW_RAID_MAP_ALL *local_map_ptr; | ||
| 1293 | |||
| 1294 | device_id = MEGASAS_DEV_INDEX(instance, scp); | ||
| 1295 | |||
| 1296 | fusion = instance->ctrl_context; | ||
| 1297 | |||
| 1298 | io_request = cmd->io_request; | ||
| 1299 | io_request->RaidContext.VirtualDiskTgtId = device_id; | ||
| 1300 | io_request->RaidContext.status = 0; | ||
| 1301 | io_request->RaidContext.exStatus = 0; | ||
| 1302 | |||
| 1303 | req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; | ||
| 1304 | |||
| 1305 | start_lba_lo = 0; | ||
| 1306 | start_lba_hi = 0; | ||
| 1307 | fp_possible = 0; | ||
| 1308 | |||
| 1309 | /* | ||
| 1310 | * 6-byte READ(0x08) or WRITE(0x0A) cdb | ||
| 1311 | */ | ||
| 1312 | if (scp->cmd_len == 6) { | ||
| 1313 | io_request->DataLength = (u32) scp->cmnd[4]; | ||
| 1314 | start_lba_lo = ((u32) scp->cmnd[1] << 16) | | ||
| 1315 | ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3]; | ||
| 1316 | |||
| 1317 | start_lba_lo &= 0x1FFFFF; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | /* | ||
| 1321 | * 10-byte READ(0x28) or WRITE(0x2A) cdb | ||
| 1322 | */ | ||
| 1323 | else if (scp->cmd_len == 10) { | ||
| 1324 | io_request->DataLength = (u32) scp->cmnd[8] | | ||
| 1325 | ((u32) scp->cmnd[7] << 8); | ||
| 1326 | start_lba_lo = ((u32) scp->cmnd[2] << 24) | | ||
| 1327 | ((u32) scp->cmnd[3] << 16) | | ||
| 1328 | ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | /* | ||
| 1332 | * 12-byte READ(0xA8) or WRITE(0xAA) cdb | ||
| 1333 | */ | ||
| 1334 | else if (scp->cmd_len == 12) { | ||
| 1335 | io_request->DataLength = ((u32) scp->cmnd[6] << 24) | | ||
| 1336 | ((u32) scp->cmnd[7] << 16) | | ||
| 1337 | ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; | ||
| 1338 | start_lba_lo = ((u32) scp->cmnd[2] << 24) | | ||
| 1339 | ((u32) scp->cmnd[3] << 16) | | ||
| 1340 | ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | /* | ||
| 1344 | * 16-byte READ(0x88) or WRITE(0x8A) cdb | ||
| 1345 | */ | ||
| 1346 | else if (scp->cmd_len == 16) { | ||
| 1347 | io_request->DataLength = ((u32) scp->cmnd[10] << 24) | | ||
| 1348 | ((u32) scp->cmnd[11] << 16) | | ||
| 1349 | ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13]; | ||
| 1350 | start_lba_lo = ((u32) scp->cmnd[6] << 24) | | ||
| 1351 | ((u32) scp->cmnd[7] << 16) | | ||
| 1352 | ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; | ||
| 1353 | |||
| 1354 | start_lba_hi = ((u32) scp->cmnd[2] << 24) | | ||
| 1355 | ((u32) scp->cmnd[3] << 16) | | ||
| 1356 | ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); | ||
| 1360 | io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; | ||
| 1361 | io_info.numBlocks = io_request->DataLength; | ||
| 1362 | io_info.ldTgtId = device_id; | ||
| 1363 | |||
| 1364 | if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) | ||
| 1365 | io_info.isRead = 1; | ||
| 1366 | |||
| 1367 | local_map_ptr = fusion->ld_map[(instance->map_id & 1)]; | ||
| 1368 | |||
| 1369 | if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >= | ||
| 1370 | MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io)) { | ||
| 1371 | io_request->RaidContext.regLockFlags = 0; | ||
| 1372 | fp_possible = 0; | ||
| 1373 | } else { | ||
| 1374 | if (MR_BuildRaidContext(&io_info, &io_request->RaidContext, | ||
| 1375 | local_map_ptr)) | ||
| 1376 | fp_possible = io_info.fpOkForIo; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | if (fp_possible) { | ||
| 1380 | megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, | ||
| 1381 | local_map_ptr, start_lba_lo); | ||
| 1382 | io_request->DataLength = scsi_bufflen(scp); | ||
| 1383 | io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; | ||
| 1384 | cmd->request_desc->SCSIIO.RequestFlags = | ||
| 1385 | (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY | ||
| 1386 | << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 1387 | if ((fusion->load_balance_info[device_id].loadBalanceFlag) && | ||
| 1388 | (io_info.isRead)) { | ||
| 1389 | io_info.devHandle = | ||
| 1390 | get_updated_dev_handle( | ||
| 1391 | &fusion->load_balance_info[device_id], | ||
| 1392 | &io_info); | ||
| 1393 | scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG; | ||
| 1394 | } else | ||
| 1395 | scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; | ||
| 1396 | cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; | ||
| 1397 | io_request->DevHandle = io_info.devHandle; | ||
| 1398 | } else { | ||
| 1399 | io_request->RaidContext.timeoutValue = | ||
| 1400 | local_map_ptr->raidMap.fpPdIoTimeoutSec; | ||
| 1401 | io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; | ||
| 1402 | io_request->DevHandle = device_id; | ||
| 1403 | cmd->request_desc->SCSIIO.RequestFlags = | ||
| 1404 | (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO | ||
| 1405 | << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 1406 | } /* Not FP */ | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | /** | ||
| 1410 | * megasas_build_dcdb_fusion - Prepares IOs to devices | ||
| 1411 | * @instance: Adapter soft state | ||
| 1412 | * @scp: SCSI command | ||
| 1413 | * @cmd: Command to be prepared | ||
| 1414 | * | ||
| 1415 | * Prepares the io_request frame for non-io cmds | ||
| 1416 | */ | ||
| 1417 | static void | ||
| 1418 | megasas_build_dcdb_fusion(struct megasas_instance *instance, | ||
| 1419 | struct scsi_cmnd *scmd, | ||
| 1420 | struct megasas_cmd_fusion *cmd) | ||
| 1421 | { | ||
| 1422 | u32 device_id; | ||
| 1423 | struct MPI2_RAID_SCSI_IO_REQUEST *io_request; | ||
| 1424 | u16 pd_index = 0; | ||
| 1425 | struct MR_FW_RAID_MAP_ALL *local_map_ptr; | ||
| 1426 | struct fusion_context *fusion = instance->ctrl_context; | ||
| 1427 | |||
| 1428 | io_request = cmd->io_request; | ||
| 1429 | device_id = MEGASAS_DEV_INDEX(instance, scmd); | ||
| 1430 | pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL) | ||
| 1431 | +scmd->device->id; | ||
| 1432 | local_map_ptr = fusion->ld_map[(instance->map_id & 1)]; | ||
| 1433 | |||
| 1434 | /* Check if this is a system PD I/O */ | ||
| 1435 | if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) && | ||
| 1436 | (instance->pd_list[pd_index].driveType == TYPE_DISK)) { | ||
| 1437 | io_request->Function = 0; | ||
| 1438 | io_request->DevHandle = | ||
| 1439 | local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; | ||
| 1440 | io_request->RaidContext.timeoutValue = | ||
| 1441 | local_map_ptr->raidMap.fpPdIoTimeoutSec; | ||
| 1442 | io_request->RaidContext.regLockFlags = 0; | ||
| 1443 | io_request->RaidContext.regLockRowLBA = 0; | ||
| 1444 | io_request->RaidContext.regLockLength = 0; | ||
| 1445 | io_request->RaidContext.RAIDFlags = | ||
| 1446 | MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << | ||
| 1447 | MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; | ||
| 1448 | cmd->request_desc->SCSIIO.RequestFlags = | ||
| 1449 | (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << | ||
| 1450 | MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 1451 | } else { | ||
| 1452 | io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; | ||
| 1453 | io_request->DevHandle = device_id; | ||
| 1454 | cmd->request_desc->SCSIIO.RequestFlags = | ||
| 1455 | (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << | ||
| 1456 | MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 1457 | } | ||
| 1458 | io_request->RaidContext.VirtualDiskTgtId = device_id; | ||
| 1459 | io_request->LUN[0] = scmd->device->lun; | ||
| 1460 | io_request->DataLength = scsi_bufflen(scmd); | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | /** | ||
| 1464 | * megasas_build_io_fusion - Prepares IOs to devices | ||
| 1465 | * @instance: Adapter soft state | ||
| 1466 | * @scp: SCSI command | ||
| 1467 | * @cmd: Command to be prepared | ||
| 1468 | * | ||
| 1469 | * Invokes helper functions to prepare request frames | ||
| 1470 | * and sets flags appropriate for IO/Non-IO cmd | ||
| 1471 | */ | ||
| 1472 | int | ||
| 1473 | megasas_build_io_fusion(struct megasas_instance *instance, | ||
| 1474 | struct scsi_cmnd *scp, | ||
| 1475 | struct megasas_cmd_fusion *cmd) | ||
| 1476 | { | ||
| 1477 | u32 device_id, sge_count; | ||
| 1478 | struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; | ||
| 1479 | |||
| 1480 | device_id = MEGASAS_DEV_INDEX(instance, scp); | ||
| 1481 | |||
| 1482 | /* Zero out some fields so they don't get reused */ | ||
| 1483 | io_request->LUN[0] = 0; | ||
| 1484 | io_request->CDB.EEDP32.PrimaryReferenceTag = 0; | ||
| 1485 | io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0; | ||
| 1486 | io_request->EEDPFlags = 0; | ||
| 1487 | io_request->Control = 0; | ||
| 1488 | io_request->EEDPBlockSize = 0; | ||
| 1489 | io_request->IoFlags = 0; | ||
| 1490 | io_request->RaidContext.RAIDFlags = 0; | ||
| 1491 | |||
| 1492 | memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); | ||
| 1493 | /* | ||
| 1494 | * Just the CDB length,rest of the Flags are zero | ||
| 1495 | * This will be modified for FP in build_ldio_fusion | ||
| 1496 | */ | ||
| 1497 | io_request->IoFlags = scp->cmd_len; | ||
| 1498 | |||
| 1499 | if (megasas_is_ldio(scp)) | ||
| 1500 | megasas_build_ldio_fusion(instance, scp, cmd); | ||
| 1501 | else | ||
| 1502 | megasas_build_dcdb_fusion(instance, scp, cmd); | ||
| 1503 | |||
| 1504 | /* | ||
| 1505 | * Construct SGL | ||
| 1506 | */ | ||
| 1507 | |||
| 1508 | sge_count = | ||
| 1509 | megasas_make_sgl_fusion(instance, scp, | ||
| 1510 | (struct MPI25_IEEE_SGE_CHAIN64 *) | ||
| 1511 | &io_request->SGL, cmd); | ||
| 1512 | |||
| 1513 | if (sge_count > instance->max_num_sge) { | ||
| 1514 | printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds " | ||
| 1515 | "max (0x%x) allowed\n", sge_count, | ||
| 1516 | instance->max_num_sge); | ||
| 1517 | return 1; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | io_request->RaidContext.numSGE = sge_count; | ||
| 1521 | |||
| 1522 | io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; | ||
| 1523 | |||
| 1524 | if (scp->sc_data_direction == PCI_DMA_TODEVICE) | ||
| 1525 | io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE; | ||
| 1526 | else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) | ||
| 1527 | io_request->Control |= MPI2_SCSIIO_CONTROL_READ; | ||
| 1528 | |||
| 1529 | io_request->SGLOffset0 = | ||
| 1530 | offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4; | ||
| 1531 | |||
| 1532 | io_request->SenseBufferLowAddress = cmd->sense_phys_addr; | ||
| 1533 | io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; | ||
| 1534 | |||
| 1535 | cmd->scmd = scp; | ||
| 1536 | scp->SCp.ptr = (char *)cmd; | ||
| 1537 | |||
| 1538 | return 0; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | union MEGASAS_REQUEST_DESCRIPTOR_UNION * | ||
| 1542 | megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) | ||
| 1543 | { | ||
| 1544 | u8 *p; | ||
| 1545 | struct fusion_context *fusion; | ||
| 1546 | |||
| 1547 | if (index >= instance->max_fw_cmds) { | ||
| 1548 | printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for " | ||
| 1549 | "descriptor\n", index); | ||
| 1550 | return NULL; | ||
| 1551 | } | ||
| 1552 | fusion = instance->ctrl_context; | ||
| 1553 | p = fusion->req_frames_desc | ||
| 1554 | +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index; | ||
| 1555 | |||
| 1556 | return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p; | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | /** | ||
| 1560 | * megasas_build_and_issue_cmd_fusion -Main routine for building and | ||
| 1561 | * issuing non IOCTL cmd | ||
| 1562 | * @instance: Adapter soft state | ||
| 1563 | * @scmd: pointer to scsi cmd from OS | ||
| 1564 | */ | ||
| 1565 | static u32 | ||
| 1566 | megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, | ||
| 1567 | struct scsi_cmnd *scmd) | ||
| 1568 | { | ||
| 1569 | struct megasas_cmd_fusion *cmd; | ||
| 1570 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 1571 | u32 index; | ||
| 1572 | struct fusion_context *fusion; | ||
| 1573 | |||
| 1574 | fusion = instance->ctrl_context; | ||
| 1575 | |||
| 1576 | cmd = megasas_get_cmd_fusion(instance); | ||
| 1577 | if (!cmd) | ||
| 1578 | return SCSI_MLQUEUE_HOST_BUSY; | ||
| 1579 | |||
| 1580 | index = cmd->index; | ||
| 1581 | |||
| 1582 | req_desc = megasas_get_request_descriptor(instance, index-1); | ||
| 1583 | if (!req_desc) | ||
| 1584 | return 1; | ||
| 1585 | |||
| 1586 | req_desc->Words = 0; | ||
| 1587 | cmd->request_desc = req_desc; | ||
| 1588 | cmd->request_desc->Words = 0; | ||
| 1589 | |||
| 1590 | if (megasas_build_io_fusion(instance, scmd, cmd)) { | ||
| 1591 | megasas_return_cmd_fusion(instance, cmd); | ||
| 1592 | printk(KERN_ERR "megasas: Error building command.\n"); | ||
| 1593 | cmd->request_desc = NULL; | ||
| 1594 | return 1; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | req_desc = cmd->request_desc; | ||
| 1598 | req_desc->SCSIIO.SMID = index; | ||
| 1599 | |||
| 1600 | if (cmd->io_request->ChainOffset != 0 && | ||
| 1601 | cmd->io_request->ChainOffset != 0xF) | ||
| 1602 | printk(KERN_ERR "megasas: The chain offset value is not " | ||
| 1603 | "correct : %x\n", cmd->io_request->ChainOffset); | ||
| 1604 | |||
| 1605 | /* | ||
| 1606 | * Issue the command to the FW | ||
| 1607 | */ | ||
| 1608 | atomic_inc(&instance->fw_outstanding); | ||
| 1609 | |||
| 1610 | instance->instancet->fire_cmd(instance, | ||
| 1611 | req_desc->u.low, req_desc->u.high, | ||
| 1612 | instance->reg_set); | ||
| 1613 | |||
| 1614 | return 0; | ||
| 1615 | } | ||
| 1616 | |||
| 1617 | /** | ||
| 1618 | * complete_cmd_fusion - Completes command | ||
| 1619 | * @instance: Adapter soft state | ||
| 1620 | * Completes all commands that is in reply descriptor queue | ||
| 1621 | */ | ||
| 1622 | int | ||
| 1623 | complete_cmd_fusion(struct megasas_instance *instance) | ||
| 1624 | { | ||
| 1625 | union MPI2_REPLY_DESCRIPTORS_UNION *desc; | ||
| 1626 | struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; | ||
| 1627 | struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; | ||
| 1628 | struct fusion_context *fusion; | ||
| 1629 | struct megasas_cmd *cmd_mfi; | ||
| 1630 | struct megasas_cmd_fusion *cmd_fusion; | ||
| 1631 | u16 smid, num_completed; | ||
| 1632 | u8 reply_descript_type, arm; | ||
| 1633 | u32 status, extStatus, device_id; | ||
| 1634 | union desc_value d_val; | ||
| 1635 | struct LD_LOAD_BALANCE_INFO *lbinfo; | ||
| 1636 | |||
| 1637 | fusion = instance->ctrl_context; | ||
| 1638 | |||
| 1639 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) | ||
| 1640 | return IRQ_HANDLED; | ||
| 1641 | |||
| 1642 | desc = fusion->reply_frames_desc; | ||
| 1643 | desc += fusion->last_reply_idx; | ||
| 1644 | |||
| 1645 | reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; | ||
| 1646 | |||
| 1647 | d_val.word = desc->Words; | ||
| 1648 | |||
| 1649 | reply_descript_type = reply_desc->ReplyFlags & | ||
| 1650 | MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; | ||
| 1651 | |||
| 1652 | if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) | ||
| 1653 | return IRQ_NONE; | ||
| 1654 | |||
| 1655 | d_val.word = desc->Words; | ||
| 1656 | |||
| 1657 | num_completed = 0; | ||
| 1658 | |||
| 1659 | while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) { | ||
| 1660 | smid = reply_desc->SMID; | ||
| 1661 | |||
| 1662 | cmd_fusion = fusion->cmd_list[smid - 1]; | ||
| 1663 | |||
| 1664 | scsi_io_req = | ||
| 1665 | (struct MPI2_RAID_SCSI_IO_REQUEST *) | ||
| 1666 | cmd_fusion->io_request; | ||
| 1667 | |||
| 1668 | if (cmd_fusion->scmd) | ||
| 1669 | cmd_fusion->scmd->SCp.ptr = NULL; | ||
| 1670 | |||
| 1671 | status = scsi_io_req->RaidContext.status; | ||
| 1672 | extStatus = scsi_io_req->RaidContext.exStatus; | ||
| 1673 | |||
| 1674 | switch (scsi_io_req->Function) { | ||
| 1675 | case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ | ||
| 1676 | /* Update load balancing info */ | ||
| 1677 | device_id = MEGASAS_DEV_INDEX(instance, | ||
| 1678 | cmd_fusion->scmd); | ||
| 1679 | lbinfo = &fusion->load_balance_info[device_id]; | ||
| 1680 | if (cmd_fusion->scmd->SCp.Status & | ||
| 1681 | MEGASAS_LOAD_BALANCE_FLAG) { | ||
| 1682 | arm = lbinfo->raid1DevHandle[0] == | ||
| 1683 | cmd_fusion->io_request->DevHandle ? 0 : | ||
| 1684 | 1; | ||
| 1685 | atomic_dec(&lbinfo->scsi_pending_cmds[arm]); | ||
| 1686 | cmd_fusion->scmd->SCp.Status &= | ||
| 1687 | ~MEGASAS_LOAD_BALANCE_FLAG; | ||
| 1688 | } | ||
| 1689 | if (reply_descript_type == | ||
| 1690 | MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { | ||
| 1691 | if (megasas_dbg_lvl == 5) | ||
| 1692 | printk(KERN_ERR "\nmegasas: FAST Path " | ||
| 1693 | "IO Success\n"); | ||
| 1694 | } | ||
| 1695 | /* Fall thru and complete IO */ | ||
| 1696 | case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ | ||
| 1697 | /* Map the FW Cmd Status */ | ||
| 1698 | map_cmd_status(cmd_fusion, status, extStatus); | ||
| 1699 | scsi_dma_unmap(cmd_fusion->scmd); | ||
| 1700 | cmd_fusion->scmd->scsi_done(cmd_fusion->scmd); | ||
| 1701 | scsi_io_req->RaidContext.status = 0; | ||
| 1702 | scsi_io_req->RaidContext.exStatus = 0; | ||
| 1703 | megasas_return_cmd_fusion(instance, cmd_fusion); | ||
| 1704 | atomic_dec(&instance->fw_outstanding); | ||
| 1705 | |||
| 1706 | break; | ||
| 1707 | case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */ | ||
| 1708 | cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; | ||
| 1709 | megasas_complete_cmd(instance, cmd_mfi, DID_OK); | ||
| 1710 | cmd_fusion->flags = 0; | ||
| 1711 | megasas_return_cmd_fusion(instance, cmd_fusion); | ||
| 1712 | |||
| 1713 | break; | ||
| 1714 | } | ||
| 1715 | |||
| 1716 | fusion->last_reply_idx++; | ||
| 1717 | if (fusion->last_reply_idx >= fusion->reply_q_depth) | ||
| 1718 | fusion->last_reply_idx = 0; | ||
| 1719 | |||
| 1720 | desc->Words = ULLONG_MAX; | ||
| 1721 | num_completed++; | ||
| 1722 | |||
| 1723 | /* Get the next reply descriptor */ | ||
| 1724 | if (!fusion->last_reply_idx) | ||
| 1725 | desc = fusion->reply_frames_desc; | ||
| 1726 | else | ||
| 1727 | desc++; | ||
| 1728 | |||
| 1729 | reply_desc = | ||
| 1730 | (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; | ||
| 1731 | |||
| 1732 | d_val.word = desc->Words; | ||
| 1733 | |||
| 1734 | reply_descript_type = reply_desc->ReplyFlags & | ||
| 1735 | MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; | ||
| 1736 | |||
| 1737 | if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) | ||
| 1738 | break; | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | if (!num_completed) | ||
| 1742 | return IRQ_NONE; | ||
| 1743 | |||
| 1744 | wmb(); | ||
| 1745 | writel(fusion->last_reply_idx, | ||
| 1746 | &instance->reg_set->reply_post_host_index); | ||
| 1747 | |||
| 1748 | return IRQ_HANDLED; | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | /** | ||
| 1752 | * megasas_complete_cmd_dpc_fusion - Completes command | ||
| 1753 | * @instance: Adapter soft state | ||
| 1754 | * | ||
| 1755 | * Tasklet to complete cmds | ||
| 1756 | */ | ||
| 1757 | void | ||
| 1758 | megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) | ||
| 1759 | { | ||
| 1760 | struct megasas_instance *instance = | ||
| 1761 | (struct megasas_instance *)instance_addr; | ||
| 1762 | unsigned long flags; | ||
| 1763 | |||
| 1764 | /* If we have already declared adapter dead, donot complete cmds */ | ||
| 1765 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
| 1766 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { | ||
| 1767 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
| 1768 | return; | ||
| 1769 | } | ||
| 1770 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
| 1771 | |||
| 1772 | spin_lock_irqsave(&instance->completion_lock, flags); | ||
| 1773 | complete_cmd_fusion(instance); | ||
| 1774 | spin_unlock_irqrestore(&instance->completion_lock, flags); | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | /** | ||
| 1778 | * megasas_isr_fusion - isr entry point | ||
| 1779 | */ | ||
| 1780 | irqreturn_t megasas_isr_fusion(int irq, void *devp) | ||
| 1781 | { | ||
| 1782 | struct megasas_instance *instance = (struct megasas_instance *)devp; | ||
| 1783 | u32 mfiStatus, fw_state; | ||
| 1784 | |||
| 1785 | if (!instance->msi_flag) { | ||
| 1786 | mfiStatus = instance->instancet->clear_intr(instance->reg_set); | ||
| 1787 | if (!mfiStatus) | ||
| 1788 | return IRQ_NONE; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | /* If we are resetting, bail */ | ||
| 1792 | if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) | ||
| 1793 | return IRQ_HANDLED; | ||
| 1794 | |||
| 1795 | if (!complete_cmd_fusion(instance)) { | ||
| 1796 | /* If we didn't complete any commands, check for FW fault */ | ||
| 1797 | fw_state = instance->instancet->read_fw_status_reg( | ||
| 1798 | instance->reg_set) & MFI_STATE_MASK; | ||
| 1799 | if (fw_state == MFI_STATE_FAULT) | ||
| 1800 | schedule_work(&instance->work_init); | ||
| 1801 | } | ||
| 1802 | |||
| 1803 | return IRQ_HANDLED; | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | /** | ||
| 1807 | * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru | ||
| 1808 | * @instance: Adapter soft state | ||
| 1809 | * mfi_cmd: megasas_cmd pointer | ||
| 1810 | * | ||
| 1811 | */ | ||
| 1812 | u8 | ||
| 1813 | build_mpt_mfi_pass_thru(struct megasas_instance *instance, | ||
| 1814 | struct megasas_cmd *mfi_cmd) | ||
| 1815 | { | ||
| 1816 | struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; | ||
| 1817 | struct MPI2_RAID_SCSI_IO_REQUEST *io_req; | ||
| 1818 | struct megasas_cmd_fusion *cmd; | ||
| 1819 | struct fusion_context *fusion; | ||
| 1820 | struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr; | ||
| 1821 | |||
| 1822 | cmd = megasas_get_cmd_fusion(instance); | ||
| 1823 | if (!cmd) | ||
| 1824 | return 1; | ||
| 1825 | |||
| 1826 | /* Save the smid. To be used for returning the cmd */ | ||
| 1827 | mfi_cmd->context.smid = cmd->index; | ||
| 1828 | |||
| 1829 | cmd->sync_cmd_idx = mfi_cmd->index; | ||
| 1830 | |||
| 1831 | /* | ||
| 1832 | * For cmds where the flag is set, store the flag and check | ||
| 1833 | * on completion. For cmds with this flag, don't call | ||
| 1834 | * megasas_complete_cmd | ||
| 1835 | */ | ||
| 1836 | |||
| 1837 | if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE) | ||
| 1838 | cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; | ||
| 1839 | |||
| 1840 | fusion = instance->ctrl_context; | ||
| 1841 | io_req = cmd->io_request; | ||
| 1842 | mpi25_ieee_chain = | ||
| 1843 | (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; | ||
| 1844 | |||
| 1845 | io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST; | ||
| 1846 | io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, | ||
| 1847 | SGL) / 4; | ||
| 1848 | io_req->ChainOffset = fusion->chain_offset_mfi_pthru; | ||
| 1849 | |||
| 1850 | mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr; | ||
| 1851 | |||
| 1852 | mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | | ||
| 1853 | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; | ||
| 1854 | |||
| 1855 | mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME; | ||
| 1856 | |||
| 1857 | return 0; | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | /** | ||
| 1861 | * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd | ||
| 1862 | * @instance: Adapter soft state | ||
| 1863 | * @cmd: mfi cmd to build | ||
| 1864 | * | ||
| 1865 | */ | ||
| 1866 | union MEGASAS_REQUEST_DESCRIPTOR_UNION * | ||
| 1867 | build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) | ||
| 1868 | { | ||
| 1869 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 1870 | u16 index; | ||
| 1871 | |||
| 1872 | if (build_mpt_mfi_pass_thru(instance, cmd)) { | ||
| 1873 | printk(KERN_ERR "Couldn't build MFI pass thru cmd\n"); | ||
| 1874 | return NULL; | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | index = cmd->context.smid; | ||
| 1878 | |||
| 1879 | req_desc = megasas_get_request_descriptor(instance, index - 1); | ||
| 1880 | |||
| 1881 | if (!req_desc) | ||
| 1882 | return NULL; | ||
| 1883 | |||
| 1884 | req_desc->Words = 0; | ||
| 1885 | req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << | ||
| 1886 | MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); | ||
| 1887 | |||
| 1888 | req_desc->SCSIIO.SMID = index; | ||
| 1889 | |||
| 1890 | return req_desc; | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | /** | ||
| 1894 | * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd | ||
| 1895 | * @instance: Adapter soft state | ||
| 1896 | * @cmd: mfi cmd pointer | ||
| 1897 | * | ||
| 1898 | */ | ||
| 1899 | void | ||
| 1900 | megasas_issue_dcmd_fusion(struct megasas_instance *instance, | ||
| 1901 | struct megasas_cmd *cmd) | ||
| 1902 | { | ||
| 1903 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 1904 | union desc_value d_val; | ||
| 1905 | |||
| 1906 | req_desc = build_mpt_cmd(instance, cmd); | ||
| 1907 | if (!req_desc) { | ||
| 1908 | printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n"); | ||
| 1909 | return; | ||
| 1910 | } | ||
| 1911 | d_val.word = req_desc->Words; | ||
| 1912 | |||
| 1913 | instance->instancet->fire_cmd(instance, req_desc->u.low, | ||
| 1914 | req_desc->u.high, instance->reg_set); | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | /** | ||
| 1918 | * megasas_release_fusion - Reverses the FW initialization | ||
| 1919 | * @intance: Adapter soft state | ||
| 1920 | */ | ||
| 1921 | void | ||
| 1922 | megasas_release_fusion(struct megasas_instance *instance) | ||
| 1923 | { | ||
| 1924 | megasas_free_cmds(instance); | ||
| 1925 | megasas_free_cmds_fusion(instance); | ||
| 1926 | |||
| 1927 | iounmap(instance->reg_set); | ||
| 1928 | |||
| 1929 | pci_release_selected_regions(instance->pdev, instance->bar); | ||
| 1930 | } | ||
| 1931 | |||
| 1932 | /** | ||
| 1933 | * megasas_read_fw_status_reg_fusion - returns the current FW status value | ||
| 1934 | * @regs: MFI register set | ||
| 1935 | */ | ||
| 1936 | static u32 | ||
| 1937 | megasas_read_fw_status_reg_fusion(struct megasas_register_set __iomem *regs) | ||
| 1938 | { | ||
| 1939 | return readl(&(regs)->outbound_scratch_pad); | ||
| 1940 | } | ||
| 1941 | |||
| 1942 | /** | ||
| 1943 | * megasas_adp_reset_fusion - For controller reset | ||
| 1944 | * @regs: MFI register set | ||
| 1945 | */ | ||
| 1946 | static int | ||
| 1947 | megasas_adp_reset_fusion(struct megasas_instance *instance, | ||
| 1948 | struct megasas_register_set __iomem *regs) | ||
| 1949 | { | ||
| 1950 | return 0; | ||
| 1951 | } | ||
| 1952 | |||
| 1953 | /** | ||
| 1954 | * megasas_check_reset_fusion - For controller reset check | ||
| 1955 | * @regs: MFI register set | ||
| 1956 | */ | ||
| 1957 | static int | ||
| 1958 | megasas_check_reset_fusion(struct megasas_instance *instance, | ||
| 1959 | struct megasas_register_set __iomem *regs) | ||
| 1960 | { | ||
| 1961 | return 0; | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | /* This function waits for outstanding commands on fusion to complete */ | ||
| 1965 | int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance) | ||
| 1966 | { | ||
| 1967 | int i, outstanding, retval = 0; | ||
| 1968 | u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME; | ||
| 1969 | |||
| 1970 | for (i = 0; i < wait_time; i++) { | ||
| 1971 | /* Check if firmware is in fault state */ | ||
| 1972 | fw_state = instance->instancet->read_fw_status_reg( | ||
| 1973 | instance->reg_set) & MFI_STATE_MASK; | ||
| 1974 | if (fw_state == MFI_STATE_FAULT) { | ||
| 1975 | printk(KERN_WARNING "megasas: Found FW in FAULT state," | ||
| 1976 | " will reset adapter.\n"); | ||
| 1977 | retval = 1; | ||
| 1978 | goto out; | ||
| 1979 | } | ||
| 1980 | |||
| 1981 | outstanding = atomic_read(&instance->fw_outstanding); | ||
| 1982 | if (!outstanding) | ||
| 1983 | goto out; | ||
| 1984 | |||
| 1985 | if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { | ||
| 1986 | printk(KERN_NOTICE "megasas: [%2d]waiting for %d " | ||
| 1987 | "commands to complete\n", i, outstanding); | ||
| 1988 | megasas_complete_cmd_dpc_fusion( | ||
| 1989 | (unsigned long)instance); | ||
| 1990 | } | ||
| 1991 | msleep(1000); | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | if (atomic_read(&instance->fw_outstanding)) { | ||
| 1995 | printk("megaraid_sas: pending commands remain after waiting, " | ||
| 1996 | "will reset adapter.\n"); | ||
| 1997 | retval = 1; | ||
| 1998 | } | ||
| 1999 | out: | ||
| 2000 | return retval; | ||
| 2001 | } | ||
| 2002 | |||
| 2003 | void megasas_reset_reply_desc(struct megasas_instance *instance) | ||
| 2004 | { | ||
| 2005 | int i; | ||
| 2006 | struct fusion_context *fusion; | ||
| 2007 | union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; | ||
| 2008 | |||
| 2009 | fusion = instance->ctrl_context; | ||
| 2010 | fusion->last_reply_idx = 0; | ||
| 2011 | reply_desc = fusion->reply_frames_desc; | ||
| 2012 | for (i = 0 ; i < fusion->reply_q_depth; i++, reply_desc++) | ||
| 2013 | reply_desc->Words = ULLONG_MAX; | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | /* Core fusion reset function */ | ||
| 2017 | int megasas_reset_fusion(struct Scsi_Host *shost) | ||
| 2018 | { | ||
| 2019 | int retval = SUCCESS, i, j, retry = 0; | ||
| 2020 | struct megasas_instance *instance; | ||
| 2021 | struct megasas_cmd_fusion *cmd_fusion; | ||
| 2022 | struct fusion_context *fusion; | ||
| 2023 | struct megasas_cmd *cmd_mfi; | ||
| 2024 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; | ||
| 2025 | u32 host_diag, abs_state; | ||
| 2026 | |||
| 2027 | instance = (struct megasas_instance *)shost->hostdata; | ||
| 2028 | fusion = instance->ctrl_context; | ||
| 2029 | |||
| 2030 | mutex_lock(&instance->reset_mutex); | ||
| 2031 | set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); | ||
| 2032 | instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; | ||
| 2033 | instance->instancet->disable_intr(instance->reg_set); | ||
| 2034 | msleep(1000); | ||
| 2035 | |||
| 2036 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { | ||
| 2037 | printk(KERN_WARNING "megaraid_sas: Hardware critical error, " | ||
| 2038 | "returning FAILED.\n"); | ||
| 2039 | retval = FAILED; | ||
| 2040 | goto out; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | /* First try waiting for commands to complete */ | ||
| 2044 | if (megasas_wait_for_outstanding_fusion(instance)) { | ||
| 2045 | printk(KERN_WARNING "megaraid_sas: resetting fusion " | ||
| 2046 | "adapter.\n"); | ||
| 2047 | /* Now return commands back to the OS */ | ||
| 2048 | for (i = 0 ; i < instance->max_fw_cmds; i++) { | ||
| 2049 | cmd_fusion = fusion->cmd_list[i]; | ||
| 2050 | if (cmd_fusion->scmd) { | ||
| 2051 | scsi_dma_unmap(cmd_fusion->scmd); | ||
| 2052 | cmd_fusion->scmd->result = (DID_RESET << 16); | ||
| 2053 | cmd_fusion->scmd->scsi_done(cmd_fusion->scmd); | ||
| 2054 | megasas_return_cmd_fusion(instance, cmd_fusion); | ||
| 2055 | atomic_dec(&instance->fw_outstanding); | ||
| 2056 | } | ||
| 2057 | } | ||
| 2058 | |||
| 2059 | if (instance->disableOnlineCtrlReset == 1) { | ||
| 2060 | /* Reset not supported, kill adapter */ | ||
| 2061 | printk(KERN_WARNING "megaraid_sas: Reset not supported" | ||
| 2062 | ", killing adapter.\n"); | ||
| 2063 | megaraid_sas_kill_hba(instance); | ||
| 2064 | instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; | ||
| 2065 | retval = FAILED; | ||
| 2066 | goto out; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | /* Now try to reset the chip */ | ||
| 2070 | for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { | ||
| 2071 | writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, | ||
| 2072 | &instance->reg_set->fusion_seq_offset); | ||
| 2073 | writel(MPI2_WRSEQ_1ST_KEY_VALUE, | ||
| 2074 | &instance->reg_set->fusion_seq_offset); | ||
| 2075 | writel(MPI2_WRSEQ_2ND_KEY_VALUE, | ||
| 2076 | &instance->reg_set->fusion_seq_offset); | ||
| 2077 | writel(MPI2_WRSEQ_3RD_KEY_VALUE, | ||
| 2078 | &instance->reg_set->fusion_seq_offset); | ||
| 2079 | writel(MPI2_WRSEQ_4TH_KEY_VALUE, | ||
| 2080 | &instance->reg_set->fusion_seq_offset); | ||
| 2081 | writel(MPI2_WRSEQ_5TH_KEY_VALUE, | ||
| 2082 | &instance->reg_set->fusion_seq_offset); | ||
| 2083 | writel(MPI2_WRSEQ_6TH_KEY_VALUE, | ||
| 2084 | &instance->reg_set->fusion_seq_offset); | ||
| 2085 | |||
| 2086 | /* Check that the diag write enable (DRWE) bit is on */ | ||
| 2087 | host_diag = readl(&instance->reg_set->fusion_host_diag); | ||
| 2088 | while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { | ||
| 2089 | msleep(100); | ||
| 2090 | host_diag = | ||
| 2091 | readl(&instance->reg_set->fusion_host_diag); | ||
| 2092 | if (retry++ == 100) { | ||
| 2093 | printk(KERN_WARNING "megaraid_sas: " | ||
| 2094 | "Host diag unlock failed!\n"); | ||
| 2095 | break; | ||
| 2096 | } | ||
| 2097 | } | ||
| 2098 | if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) | ||
| 2099 | continue; | ||
| 2100 | |||
| 2101 | /* Send chip reset command */ | ||
| 2102 | writel(host_diag | HOST_DIAG_RESET_ADAPTER, | ||
| 2103 | &instance->reg_set->fusion_host_diag); | ||
| 2104 | msleep(3000); | ||
| 2105 | |||
| 2106 | /* Make sure reset adapter bit is cleared */ | ||
| 2107 | host_diag = readl(&instance->reg_set->fusion_host_diag); | ||
| 2108 | retry = 0; | ||
| 2109 | while (host_diag & HOST_DIAG_RESET_ADAPTER) { | ||
| 2110 | msleep(100); | ||
| 2111 | host_diag = | ||
| 2112 | readl(&instance->reg_set->fusion_host_diag); | ||
| 2113 | if (retry++ == 1000) { | ||
| 2114 | printk(KERN_WARNING "megaraid_sas: " | ||
| 2115 | "Diag reset adapter never " | ||
| 2116 | "cleared!\n"); | ||
| 2117 | break; | ||
| 2118 | } | ||
| 2119 | } | ||
| 2120 | if (host_diag & HOST_DIAG_RESET_ADAPTER) | ||
| 2121 | continue; | ||
| 2122 | |||
| 2123 | abs_state = | ||
| 2124 | instance->instancet->read_fw_status_reg( | ||
| 2125 | instance->reg_set); | ||
| 2126 | retry = 0; | ||
| 2127 | |||
| 2128 | while ((abs_state <= MFI_STATE_FW_INIT) && | ||
| 2129 | (retry++ < 1000)) { | ||
| 2130 | msleep(100); | ||
| 2131 | abs_state = | ||
| 2132 | instance->instancet->read_fw_status_reg( | ||
| 2133 | instance->reg_set); | ||
| 2134 | } | ||
| 2135 | if (abs_state <= MFI_STATE_FW_INIT) { | ||
| 2136 | printk(KERN_WARNING "megaraid_sas: firmware " | ||
| 2137 | "state < MFI_STATE_FW_INIT, state = " | ||
| 2138 | "0x%x\n", abs_state); | ||
| 2139 | continue; | ||
| 2140 | } | ||
| 2141 | |||
| 2142 | /* Wait for FW to become ready */ | ||
| 2143 | if (megasas_transition_to_ready(instance)) { | ||
| 2144 | printk(KERN_WARNING "megaraid_sas: Failed to " | ||
| 2145 | "transition controller to ready.\n"); | ||
| 2146 | continue; | ||
| 2147 | } | ||
| 2148 | |||
| 2149 | megasas_reset_reply_desc(instance); | ||
| 2150 | if (megasas_ioc_init_fusion(instance)) { | ||
| 2151 | printk(KERN_WARNING "megaraid_sas: " | ||
| 2152 | "megasas_ioc_init_fusion() failed!\n"); | ||
| 2153 | continue; | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | instance->instancet->enable_intr(instance->reg_set); | ||
| 2157 | instance->adprecovery = MEGASAS_HBA_OPERATIONAL; | ||
| 2158 | |||
| 2159 | /* Re-fire management commands */ | ||
| 2160 | for (j = 0 ; j < instance->max_fw_cmds; j++) { | ||
| 2161 | cmd_fusion = fusion->cmd_list[j]; | ||
| 2162 | if (cmd_fusion->sync_cmd_idx != | ||
| 2163 | (u32)ULONG_MAX) { | ||
| 2164 | cmd_mfi = | ||
| 2165 | instance-> | ||
| 2166 | cmd_list[cmd_fusion->sync_cmd_idx]; | ||
| 2167 | if (cmd_mfi->frame->dcmd.opcode == | ||
| 2168 | MR_DCMD_LD_MAP_GET_INFO) { | ||
| 2169 | megasas_return_cmd(instance, | ||
| 2170 | cmd_mfi); | ||
| 2171 | megasas_return_cmd_fusion( | ||
| 2172 | instance, cmd_fusion); | ||
| 2173 | } else { | ||
| 2174 | req_desc = | ||
| 2175 | megasas_get_request_descriptor( | ||
| 2176 | instance, | ||
| 2177 | cmd_mfi->context.smid | ||
| 2178 | -1); | ||
| 2179 | if (!req_desc) | ||
| 2180 | printk(KERN_WARNING | ||
| 2181 | "req_desc NULL" | ||
| 2182 | "\n"); | ||
| 2183 | else { | ||
| 2184 | instance->instancet-> | ||
| 2185 | fire_cmd(instance, | ||
| 2186 | req_desc-> | ||
| 2187 | u.low, | ||
| 2188 | req_desc-> | ||
| 2189 | u.high, | ||
| 2190 | instance-> | ||
| 2191 | reg_set); | ||
| 2192 | } | ||
| 2193 | } | ||
| 2194 | } | ||
| 2195 | } | ||
| 2196 | |||
| 2197 | /* Reset load balance info */ | ||
| 2198 | memset(fusion->load_balance_info, 0, | ||
| 2199 | sizeof(struct LD_LOAD_BALANCE_INFO) | ||
| 2200 | *MAX_LOGICAL_DRIVES); | ||
| 2201 | |||
| 2202 | if (!megasas_get_map_info(instance)) | ||
| 2203 | megasas_sync_map_info(instance); | ||
| 2204 | |||
| 2205 | /* Adapter reset completed successfully */ | ||
| 2206 | printk(KERN_WARNING "megaraid_sas: Reset " | ||
| 2207 | "successful.\n"); | ||
| 2208 | retval = SUCCESS; | ||
| 2209 | goto out; | ||
| 2210 | } | ||
| 2211 | /* Reset failed, kill the adapter */ | ||
| 2212 | printk(KERN_WARNING "megaraid_sas: Reset failed, killing " | ||
| 2213 | "adapter.\n"); | ||
| 2214 | megaraid_sas_kill_hba(instance); | ||
| 2215 | retval = FAILED; | ||
| 2216 | } else { | ||
| 2217 | instance->instancet->enable_intr(instance->reg_set); | ||
| 2218 | instance->adprecovery = MEGASAS_HBA_OPERATIONAL; | ||
| 2219 | } | ||
| 2220 | out: | ||
| 2221 | clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); | ||
| 2222 | mutex_unlock(&instance->reset_mutex); | ||
| 2223 | return retval; | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | /* Fusion OCR work queue */ | ||
| 2227 | void megasas_fusion_ocr_wq(struct work_struct *work) | ||
| 2228 | { | ||
| 2229 | struct megasas_instance *instance = | ||
| 2230 | container_of(work, struct megasas_instance, work_init); | ||
| 2231 | |||
| 2232 | megasas_reset_fusion(instance->host); | ||
| 2233 | } | ||
| 2234 | |||
| 2235 | struct megasas_instance_template megasas_instance_template_fusion = { | ||
| 2236 | .fire_cmd = megasas_fire_cmd_fusion, | ||
| 2237 | .enable_intr = megasas_enable_intr_fusion, | ||
| 2238 | .disable_intr = megasas_disable_intr_fusion, | ||
| 2239 | .clear_intr = megasas_clear_intr_fusion, | ||
| 2240 | .read_fw_status_reg = megasas_read_fw_status_reg_fusion, | ||
| 2241 | .adp_reset = megasas_adp_reset_fusion, | ||
| 2242 | .check_reset = megasas_check_reset_fusion, | ||
| 2243 | .service_isr = megasas_isr_fusion, | ||
| 2244 | .tasklet = megasas_complete_cmd_dpc_fusion, | ||
| 2245 | .init_adapter = megasas_init_adapter_fusion, | ||
| 2246 | .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion, | ||
| 2247 | .issue_dcmd = megasas_issue_dcmd_fusion, | ||
| 2248 | }; | ||
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h new file mode 100644 index 000000000000..82b577a72c8b --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h | |||
| @@ -0,0 +1,695 @@ | |||
| 1 | /* | ||
| 2 | * Linux MegaRAID driver for SAS based RAID controllers | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009-2011 LSI Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * | ||
| 20 | * FILE: megaraid_sas_fusion.h | ||
| 21 | * | ||
| 22 | * Authors: LSI Corporation | ||
| 23 | * Manoj Jose | ||
| 24 | * Sumant Patro | ||
| 25 | * | ||
| 26 | * Send feedback to: <megaraidlinux@lsi.com> | ||
| 27 | * | ||
| 28 | * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 | ||
| 29 | * ATTN: Linuxraid | ||
| 30 | */ | ||
| 31 | |||
| 32 | #ifndef _MEGARAID_SAS_FUSION_H_ | ||
| 33 | #define _MEGARAID_SAS_FUSION_H_ | ||
| 34 | |||
| 35 | /* Fusion defines */ | ||
| 36 | #define MEGASAS_MAX_SZ_CHAIN_FRAME 1024 | ||
| 37 | #define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009) | ||
| 38 | #define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256 | ||
| 39 | #define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 | ||
| 40 | #define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1 | ||
| 41 | #define MEGASAS_LOAD_BALANCE_FLAG 0x1 | ||
| 42 | #define MEGASAS_DCMD_MBOX_PEND_FLAG 0x1 | ||
| 43 | #define HOST_DIAG_WRITE_ENABLE 0x80 | ||
| 44 | #define HOST_DIAG_RESET_ADAPTER 0x4 | ||
| 45 | #define MEGASAS_FUSION_MAX_RESET_TRIES 3 | ||
| 46 | |||
| 47 | /* T10 PI defines */ | ||
| 48 | #define MR_PROT_INFO_TYPE_CONTROLLER 0x8 | ||
| 49 | #define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f | ||
| 50 | #define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9 | ||
| 51 | #define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB | ||
| 52 | #define MEGASAS_SCSI_ADDL_CDB_LEN 0x18 | ||
| 53 | #define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20 | ||
| 54 | #define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60 | ||
| 55 | #define MEGASAS_EEDPBLOCKSIZE 512 | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Raid context flags | ||
| 59 | */ | ||
| 60 | |||
| 61 | #define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4 | ||
| 62 | #define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30 | ||
| 63 | enum MR_RAID_FLAGS_IO_SUB_TYPE { | ||
| 64 | MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0, | ||
| 65 | MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1, | ||
| 66 | }; | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Request descriptor types | ||
| 70 | */ | ||
| 71 | #define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7 | ||
| 72 | #define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1 | ||
| 73 | |||
| 74 | #define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1 | ||
| 75 | |||
| 76 | #define MEGASAS_FP_CMD_LEN 16 | ||
| 77 | #define MEGASAS_FUSION_IN_RESET 0 | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Raid Context structure which describes MegaRAID specific IO Paramenters | ||
| 81 | * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames | ||
| 82 | */ | ||
| 83 | |||
| 84 | struct RAID_CONTEXT { | ||
| 85 | u16 resvd0; | ||
| 86 | u16 timeoutValue; | ||
| 87 | u8 regLockFlags; | ||
| 88 | u8 resvd1; | ||
| 89 | u16 VirtualDiskTgtId; | ||
| 90 | u64 regLockRowLBA; | ||
| 91 | u32 regLockLength; | ||
| 92 | u16 nextLMId; | ||
| 93 | u8 exStatus; | ||
| 94 | u8 status; | ||
| 95 | u8 RAIDFlags; | ||
| 96 | u8 numSGE; | ||
| 97 | u16 configSeqNum; | ||
| 98 | u8 spanArm; | ||
| 99 | u8 resvd2[3]; | ||
| 100 | }; | ||
| 101 | |||
| 102 | #define RAID_CTX_SPANARM_ARM_SHIFT (0) | ||
| 103 | #define RAID_CTX_SPANARM_ARM_MASK (0x1f) | ||
| 104 | |||
| 105 | #define RAID_CTX_SPANARM_SPAN_SHIFT (5) | ||
| 106 | #define RAID_CTX_SPANARM_SPAN_MASK (0xE0) | ||
| 107 | |||
| 108 | /* | ||
| 109 | * define region lock types | ||
| 110 | */ | ||
| 111 | enum REGION_TYPE { | ||
| 112 | REGION_TYPE_UNUSED = 0, | ||
| 113 | REGION_TYPE_SHARED_READ = 1, | ||
| 114 | REGION_TYPE_SHARED_WRITE = 2, | ||
| 115 | REGION_TYPE_EXCLUSIVE = 3, | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* MPI2 defines */ | ||
| 119 | #define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ | ||
| 120 | #define MPI2_WHOINIT_HOST_DRIVER (0x04) | ||
| 121 | #define MPI2_VERSION_MAJOR (0x02) | ||
| 122 | #define MPI2_VERSION_MINOR (0x00) | ||
| 123 | #define MPI2_VERSION_MAJOR_MASK (0xFF00) | ||
| 124 | #define MPI2_VERSION_MAJOR_SHIFT (8) | ||
| 125 | #define MPI2_VERSION_MINOR_MASK (0x00FF) | ||
| 126 | #define MPI2_VERSION_MINOR_SHIFT (0) | ||
| 127 | #define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ | ||
| 128 | MPI2_VERSION_MINOR) | ||
| 129 | #define MPI2_HEADER_VERSION_UNIT (0x10) | ||
| 130 | #define MPI2_HEADER_VERSION_DEV (0x00) | ||
| 131 | #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) | ||
| 132 | #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) | ||
| 133 | #define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) | ||
| 134 | #define MPI2_HEADER_VERSION_DEV_SHIFT (0) | ||
| 135 | #define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \ | ||
| 136 | MPI2_HEADER_VERSION_DEV) | ||
| 137 | #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) | ||
| 138 | #define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) | ||
| 139 | #define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) | ||
| 140 | #define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) | ||
| 141 | #define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) | ||
| 142 | #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) | ||
| 143 | #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) | ||
| 144 | #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ | ||
| 145 | #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) | ||
| 146 | #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) | ||
| 147 | #define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) | ||
| 148 | #define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) | ||
| 149 | #define MPI2_SCSIIO_CONTROL_READ (0x02000000) | ||
| 150 | #define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) | ||
| 151 | #define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) | ||
| 152 | #define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) | ||
| 153 | #define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) | ||
| 154 | #define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) | ||
| 155 | #define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) | ||
| 156 | #define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) | ||
| 157 | #define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) | ||
| 158 | #define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) | ||
| 159 | #define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) | ||
| 160 | #define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) | ||
| 161 | #define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) | ||
| 162 | |||
| 163 | struct MPI25_IEEE_SGE_CHAIN64 { | ||
| 164 | u64 Address; | ||
| 165 | u32 Length; | ||
| 166 | u16 Reserved1; | ||
| 167 | u8 NextChainOffset; | ||
| 168 | u8 Flags; | ||
| 169 | }; | ||
| 170 | |||
| 171 | struct MPI2_SGE_SIMPLE_UNION { | ||
| 172 | u32 FlagsLength; | ||
| 173 | union { | ||
| 174 | u32 Address32; | ||
| 175 | u64 Address64; | ||
| 176 | } u; | ||
| 177 | }; | ||
| 178 | |||
| 179 | struct MPI2_SCSI_IO_CDB_EEDP32 { | ||
| 180 | u8 CDB[20]; /* 0x00 */ | ||
| 181 | u32 PrimaryReferenceTag; /* 0x14 */ | ||
| 182 | u16 PrimaryApplicationTag; /* 0x18 */ | ||
| 183 | u16 PrimaryApplicationTagMask; /* 0x1A */ | ||
| 184 | u32 TransferLength; /* 0x1C */ | ||
| 185 | }; | ||
| 186 | |||
| 187 | struct MPI2_SGE_CHAIN_UNION { | ||
| 188 | u16 Length; | ||
| 189 | u8 NextChainOffset; | ||
| 190 | u8 Flags; | ||
| 191 | union { | ||
| 192 | u32 Address32; | ||
| 193 | u64 Address64; | ||
| 194 | } u; | ||
| 195 | }; | ||
| 196 | |||
| 197 | struct MPI2_IEEE_SGE_SIMPLE32 { | ||
| 198 | u32 Address; | ||
| 199 | u32 FlagsLength; | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct MPI2_IEEE_SGE_CHAIN32 { | ||
| 203 | u32 Address; | ||
| 204 | u32 FlagsLength; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct MPI2_IEEE_SGE_SIMPLE64 { | ||
| 208 | u64 Address; | ||
| 209 | u32 Length; | ||
| 210 | u16 Reserved1; | ||
| 211 | u8 Reserved2; | ||
| 212 | u8 Flags; | ||
| 213 | }; | ||
| 214 | |||
| 215 | struct MPI2_IEEE_SGE_CHAIN64 { | ||
| 216 | u64 Address; | ||
| 217 | u32 Length; | ||
| 218 | u16 Reserved1; | ||
| 219 | u8 Reserved2; | ||
| 220 | u8 Flags; | ||
| 221 | }; | ||
| 222 | |||
| 223 | union MPI2_IEEE_SGE_SIMPLE_UNION { | ||
| 224 | struct MPI2_IEEE_SGE_SIMPLE32 Simple32; | ||
| 225 | struct MPI2_IEEE_SGE_SIMPLE64 Simple64; | ||
| 226 | }; | ||
| 227 | |||
| 228 | union MPI2_IEEE_SGE_CHAIN_UNION { | ||
| 229 | struct MPI2_IEEE_SGE_CHAIN32 Chain32; | ||
| 230 | struct MPI2_IEEE_SGE_CHAIN64 Chain64; | ||
| 231 | }; | ||
| 232 | |||
| 233 | union MPI2_SGE_IO_UNION { | ||
| 234 | struct MPI2_SGE_SIMPLE_UNION MpiSimple; | ||
| 235 | struct MPI2_SGE_CHAIN_UNION MpiChain; | ||
| 236 | union MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; | ||
| 237 | union MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; | ||
| 238 | }; | ||
| 239 | |||
| 240 | union MPI2_SCSI_IO_CDB_UNION { | ||
| 241 | u8 CDB32[32]; | ||
| 242 | struct MPI2_SCSI_IO_CDB_EEDP32 EEDP32; | ||
| 243 | struct MPI2_SGE_SIMPLE_UNION SGE; | ||
| 244 | }; | ||
| 245 | |||
| 246 | /* | ||
| 247 | * RAID SCSI IO Request Message | ||
| 248 | * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST | ||
| 249 | */ | ||
| 250 | struct MPI2_RAID_SCSI_IO_REQUEST { | ||
| 251 | u16 DevHandle; /* 0x00 */ | ||
| 252 | u8 ChainOffset; /* 0x02 */ | ||
| 253 | u8 Function; /* 0x03 */ | ||
| 254 | u16 Reserved1; /* 0x04 */ | ||
| 255 | u8 Reserved2; /* 0x06 */ | ||
| 256 | u8 MsgFlags; /* 0x07 */ | ||
| 257 | u8 VP_ID; /* 0x08 */ | ||
| 258 | u8 VF_ID; /* 0x09 */ | ||
| 259 | u16 Reserved3; /* 0x0A */ | ||
| 260 | u32 SenseBufferLowAddress; /* 0x0C */ | ||
| 261 | u16 SGLFlags; /* 0x10 */ | ||
| 262 | u8 SenseBufferLength; /* 0x12 */ | ||
| 263 | u8 Reserved4; /* 0x13 */ | ||
| 264 | u8 SGLOffset0; /* 0x14 */ | ||
| 265 | u8 SGLOffset1; /* 0x15 */ | ||
| 266 | u8 SGLOffset2; /* 0x16 */ | ||
| 267 | u8 SGLOffset3; /* 0x17 */ | ||
| 268 | u32 SkipCount; /* 0x18 */ | ||
| 269 | u32 DataLength; /* 0x1C */ | ||
| 270 | u32 BidirectionalDataLength; /* 0x20 */ | ||
| 271 | u16 IoFlags; /* 0x24 */ | ||
| 272 | u16 EEDPFlags; /* 0x26 */ | ||
| 273 | u32 EEDPBlockSize; /* 0x28 */ | ||
| 274 | u32 SecondaryReferenceTag; /* 0x2C */ | ||
| 275 | u16 SecondaryApplicationTag; /* 0x30 */ | ||
| 276 | u16 ApplicationTagTranslationMask; /* 0x32 */ | ||
| 277 | u8 LUN[8]; /* 0x34 */ | ||
| 278 | u32 Control; /* 0x3C */ | ||
| 279 | union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ | ||
| 280 | struct RAID_CONTEXT RaidContext; /* 0x60 */ | ||
| 281 | union MPI2_SGE_IO_UNION SGL; /* 0x80 */ | ||
| 282 | }; | ||
| 283 | |||
| 284 | /* | ||
| 285 | * MPT RAID MFA IO Descriptor. | ||
| 286 | */ | ||
| 287 | struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR { | ||
| 288 | u32 RequestFlags:8; | ||
| 289 | u32 MessageAddress1:24; /* bits 31:8*/ | ||
| 290 | u32 MessageAddress2; /* bits 61:32 */ | ||
| 291 | }; | ||
| 292 | |||
| 293 | /* Default Request Descriptor */ | ||
| 294 | struct MPI2_DEFAULT_REQUEST_DESCRIPTOR { | ||
| 295 | u8 RequestFlags; /* 0x00 */ | ||
| 296 | u8 MSIxIndex; /* 0x01 */ | ||
| 297 | u16 SMID; /* 0x02 */ | ||
| 298 | u16 LMID; /* 0x04 */ | ||
| 299 | u16 DescriptorTypeDependent; /* 0x06 */ | ||
| 300 | }; | ||
| 301 | |||
| 302 | /* High Priority Request Descriptor */ | ||
| 303 | struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR { | ||
| 304 | u8 RequestFlags; /* 0x00 */ | ||
| 305 | u8 MSIxIndex; /* 0x01 */ | ||
| 306 | u16 SMID; /* 0x02 */ | ||
| 307 | u16 LMID; /* 0x04 */ | ||
| 308 | u16 Reserved1; /* 0x06 */ | ||
| 309 | }; | ||
| 310 | |||
| 311 | /* SCSI IO Request Descriptor */ | ||
| 312 | struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR { | ||
| 313 | u8 RequestFlags; /* 0x00 */ | ||
| 314 | u8 MSIxIndex; /* 0x01 */ | ||
| 315 | u16 SMID; /* 0x02 */ | ||
| 316 | u16 LMID; /* 0x04 */ | ||
| 317 | u16 DevHandle; /* 0x06 */ | ||
| 318 | }; | ||
| 319 | |||
| 320 | /* SCSI Target Request Descriptor */ | ||
| 321 | struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR { | ||
| 322 | u8 RequestFlags; /* 0x00 */ | ||
| 323 | u8 MSIxIndex; /* 0x01 */ | ||
| 324 | u16 SMID; /* 0x02 */ | ||
| 325 | u16 LMID; /* 0x04 */ | ||
| 326 | u16 IoIndex; /* 0x06 */ | ||
| 327 | }; | ||
| 328 | |||
| 329 | /* RAID Accelerator Request Descriptor */ | ||
| 330 | struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { | ||
| 331 | u8 RequestFlags; /* 0x00 */ | ||
| 332 | u8 MSIxIndex; /* 0x01 */ | ||
| 333 | u16 SMID; /* 0x02 */ | ||
| 334 | u16 LMID; /* 0x04 */ | ||
| 335 | u16 Reserved; /* 0x06 */ | ||
| 336 | }; | ||
| 337 | |||
| 338 | /* union of Request Descriptors */ | ||
| 339 | union MEGASAS_REQUEST_DESCRIPTOR_UNION { | ||
| 340 | struct MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; | ||
| 341 | struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; | ||
| 342 | struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; | ||
| 343 | struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; | ||
| 344 | struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; | ||
| 345 | struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo; | ||
| 346 | union { | ||
| 347 | struct { | ||
| 348 | u32 low; | ||
| 349 | u32 high; | ||
| 350 | } u; | ||
| 351 | u64 Words; | ||
| 352 | }; | ||
| 353 | }; | ||
| 354 | |||
| 355 | /* Default Reply Descriptor */ | ||
| 356 | struct MPI2_DEFAULT_REPLY_DESCRIPTOR { | ||
| 357 | u8 ReplyFlags; /* 0x00 */ | ||
| 358 | u8 MSIxIndex; /* 0x01 */ | ||
| 359 | u16 DescriptorTypeDependent1; /* 0x02 */ | ||
| 360 | u32 DescriptorTypeDependent2; /* 0x04 */ | ||
| 361 | }; | ||
| 362 | |||
| 363 | /* Address Reply Descriptor */ | ||
| 364 | struct MPI2_ADDRESS_REPLY_DESCRIPTOR { | ||
| 365 | u8 ReplyFlags; /* 0x00 */ | ||
| 366 | u8 MSIxIndex; /* 0x01 */ | ||
| 367 | u16 SMID; /* 0x02 */ | ||
| 368 | u32 ReplyFrameAddress; /* 0x04 */ | ||
| 369 | }; | ||
| 370 | |||
| 371 | /* SCSI IO Success Reply Descriptor */ | ||
| 372 | struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR { | ||
| 373 | u8 ReplyFlags; /* 0x00 */ | ||
| 374 | u8 MSIxIndex; /* 0x01 */ | ||
| 375 | u16 SMID; /* 0x02 */ | ||
| 376 | u16 TaskTag; /* 0x04 */ | ||
| 377 | u16 Reserved1; /* 0x06 */ | ||
| 378 | }; | ||
| 379 | |||
| 380 | /* TargetAssist Success Reply Descriptor */ | ||
| 381 | struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR { | ||
| 382 | u8 ReplyFlags; /* 0x00 */ | ||
| 383 | u8 MSIxIndex; /* 0x01 */ | ||
| 384 | u16 SMID; /* 0x02 */ | ||
| 385 | u8 SequenceNumber; /* 0x04 */ | ||
| 386 | u8 Reserved1; /* 0x05 */ | ||
| 387 | u16 IoIndex; /* 0x06 */ | ||
| 388 | }; | ||
| 389 | |||
| 390 | /* Target Command Buffer Reply Descriptor */ | ||
| 391 | struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR { | ||
| 392 | u8 ReplyFlags; /* 0x00 */ | ||
| 393 | u8 MSIxIndex; /* 0x01 */ | ||
| 394 | u8 VP_ID; /* 0x02 */ | ||
| 395 | u8 Flags; /* 0x03 */ | ||
| 396 | u16 InitiatorDevHandle; /* 0x04 */ | ||
| 397 | u16 IoIndex; /* 0x06 */ | ||
| 398 | }; | ||
| 399 | |||
| 400 | /* RAID Accelerator Success Reply Descriptor */ | ||
| 401 | struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { | ||
| 402 | u8 ReplyFlags; /* 0x00 */ | ||
| 403 | u8 MSIxIndex; /* 0x01 */ | ||
| 404 | u16 SMID; /* 0x02 */ | ||
| 405 | u32 Reserved; /* 0x04 */ | ||
| 406 | }; | ||
| 407 | |||
| 408 | /* union of Reply Descriptors */ | ||
| 409 | union MPI2_REPLY_DESCRIPTORS_UNION { | ||
| 410 | struct MPI2_DEFAULT_REPLY_DESCRIPTOR Default; | ||
| 411 | struct MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; | ||
| 412 | struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; | ||
| 413 | struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; | ||
| 414 | struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; | ||
| 415 | struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR | ||
| 416 | RAIDAcceleratorSuccess; | ||
| 417 | u64 Words; | ||
| 418 | }; | ||
| 419 | |||
| 420 | /* IOCInit Request message */ | ||
| 421 | struct MPI2_IOC_INIT_REQUEST { | ||
| 422 | u8 WhoInit; /* 0x00 */ | ||
| 423 | u8 Reserved1; /* 0x01 */ | ||
| 424 | u8 ChainOffset; /* 0x02 */ | ||
| 425 | u8 Function; /* 0x03 */ | ||
| 426 | u16 Reserved2; /* 0x04 */ | ||
| 427 | u8 Reserved3; /* 0x06 */ | ||
| 428 | u8 MsgFlags; /* 0x07 */ | ||
| 429 | u8 VP_ID; /* 0x08 */ | ||
| 430 | u8 VF_ID; /* 0x09 */ | ||
| 431 | u16 Reserved4; /* 0x0A */ | ||
| 432 | u16 MsgVersion; /* 0x0C */ | ||
| 433 | u16 HeaderVersion; /* 0x0E */ | ||
| 434 | u32 Reserved5; /* 0x10 */ | ||
| 435 | u16 Reserved6; /* 0x14 */ | ||
| 436 | u8 Reserved7; /* 0x16 */ | ||
| 437 | u8 HostMSIxVectors; /* 0x17 */ | ||
| 438 | u16 Reserved8; /* 0x18 */ | ||
| 439 | u16 SystemRequestFrameSize; /* 0x1A */ | ||
| 440 | u16 ReplyDescriptorPostQueueDepth; /* 0x1C */ | ||
| 441 | u16 ReplyFreeQueueDepth; /* 0x1E */ | ||
| 442 | u32 SenseBufferAddressHigh; /* 0x20 */ | ||
| 443 | u32 SystemReplyAddressHigh; /* 0x24 */ | ||
| 444 | u64 SystemRequestFrameBaseAddress; /* 0x28 */ | ||
| 445 | u64 ReplyDescriptorPostQueueAddress;/* 0x30 */ | ||
| 446 | u64 ReplyFreeQueueAddress; /* 0x38 */ | ||
| 447 | u64 TimeStamp; /* 0x40 */ | ||
| 448 | }; | ||
| 449 | |||
| 450 | /* mrpriv defines */ | ||
| 451 | #define MR_PD_INVALID 0xFFFF | ||
| 452 | #define MAX_SPAN_DEPTH 8 | ||
| 453 | #define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH) | ||
| 454 | #define MAX_ROW_SIZE 32 | ||
| 455 | #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) | ||
| 456 | #define MAX_LOGICAL_DRIVES 64 | ||
| 457 | #define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) | ||
| 458 | #define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) | ||
| 459 | #define MAX_ARRAYS 128 | ||
| 460 | #define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) | ||
| 461 | #define MAX_PHYSICAL_DEVICES 256 | ||
| 462 | #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) | ||
| 463 | #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 | ||
| 464 | |||
| 465 | struct MR_DEV_HANDLE_INFO { | ||
| 466 | u16 curDevHdl; | ||
| 467 | u8 validHandles; | ||
| 468 | u8 reserved; | ||
| 469 | u16 devHandle[2]; | ||
| 470 | }; | ||
| 471 | |||
| 472 | struct MR_ARRAY_INFO { | ||
| 473 | u16 pd[MAX_RAIDMAP_ROW_SIZE]; | ||
| 474 | }; | ||
| 475 | |||
| 476 | struct MR_QUAD_ELEMENT { | ||
| 477 | u64 logStart; | ||
| 478 | u64 logEnd; | ||
| 479 | u64 offsetInSpan; | ||
| 480 | u32 diff; | ||
| 481 | u32 reserved1; | ||
| 482 | }; | ||
| 483 | |||
| 484 | struct MR_SPAN_INFO { | ||
| 485 | u32 noElements; | ||
| 486 | u32 reserved1; | ||
| 487 | struct MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH]; | ||
| 488 | }; | ||
| 489 | |||
| 490 | struct MR_LD_SPAN { | ||
| 491 | u64 startBlk; | ||
| 492 | u64 numBlks; | ||
| 493 | u16 arrayRef; | ||
| 494 | u8 reserved[6]; | ||
| 495 | }; | ||
| 496 | |||
| 497 | struct MR_SPAN_BLOCK_INFO { | ||
| 498 | u64 num_rows; | ||
| 499 | struct MR_LD_SPAN span; | ||
| 500 | struct MR_SPAN_INFO block_span_info; | ||
| 501 | }; | ||
| 502 | |||
| 503 | struct MR_LD_RAID { | ||
| 504 | struct { | ||
| 505 | u32 fpCapable:1; | ||
| 506 | u32 reserved5:3; | ||
| 507 | u32 ldPiMode:4; | ||
| 508 | u32 pdPiMode:4; | ||
| 509 | u32 encryptionType:8; | ||
| 510 | u32 fpWriteCapable:1; | ||
| 511 | u32 fpReadCapable:1; | ||
| 512 | u32 fpWriteAcrossStripe:1; | ||
| 513 | u32 fpReadAcrossStripe:1; | ||
| 514 | u32 reserved4:8; | ||
| 515 | } capability; | ||
| 516 | u32 reserved6; | ||
| 517 | u64 size; | ||
| 518 | u8 spanDepth; | ||
| 519 | u8 level; | ||
| 520 | u8 stripeShift; | ||
| 521 | u8 rowSize; | ||
| 522 | u8 rowDataSize; | ||
| 523 | u8 writeMode; | ||
| 524 | u8 PRL; | ||
| 525 | u8 SRL; | ||
| 526 | u16 targetId; | ||
| 527 | u8 ldState; | ||
| 528 | u8 regTypeReqOnWrite; | ||
| 529 | u8 modFactor; | ||
| 530 | u8 reserved2[1]; | ||
| 531 | u16 seqNum; | ||
| 532 | |||
| 533 | struct { | ||
| 534 | u32 ldSyncRequired:1; | ||
| 535 | u32 reserved:31; | ||
| 536 | } flags; | ||
| 537 | |||
| 538 | u8 reserved3[0x5C]; | ||
| 539 | }; | ||
| 540 | |||
| 541 | struct MR_LD_SPAN_MAP { | ||
| 542 | struct MR_LD_RAID ldRaid; | ||
| 543 | u8 dataArmMap[MAX_RAIDMAP_ROW_SIZE]; | ||
| 544 | struct MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH]; | ||
| 545 | }; | ||
| 546 | |||
| 547 | struct MR_FW_RAID_MAP { | ||
| 548 | u32 totalSize; | ||
| 549 | union { | ||
| 550 | struct { | ||
| 551 | u32 maxLd; | ||
| 552 | u32 maxSpanDepth; | ||
| 553 | u32 maxRowSize; | ||
| 554 | u32 maxPdCount; | ||
| 555 | u32 maxArrays; | ||
| 556 | } validationInfo; | ||
| 557 | u32 version[5]; | ||
| 558 | u32 reserved1[5]; | ||
| 559 | }; | ||
| 560 | |||
| 561 | u32 ldCount; | ||
| 562 | u32 Reserved1; | ||
| 563 | u8 ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+ | ||
| 564 | MAX_RAIDMAP_VIEWS]; | ||
| 565 | u8 fpPdIoTimeoutSec; | ||
| 566 | u8 reserved2[7]; | ||
| 567 | struct MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS]; | ||
| 568 | struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; | ||
| 569 | struct MR_LD_SPAN_MAP ldSpanMap[1]; | ||
| 570 | }; | ||
| 571 | |||
| 572 | struct IO_REQUEST_INFO { | ||
| 573 | u64 ldStartBlock; | ||
| 574 | u32 numBlocks; | ||
| 575 | u16 ldTgtId; | ||
| 576 | u8 isRead; | ||
| 577 | u16 devHandle; | ||
| 578 | u64 pdBlock; | ||
| 579 | u8 fpOkForIo; | ||
| 580 | }; | ||
| 581 | |||
| 582 | struct MR_LD_TARGET_SYNC { | ||
| 583 | u8 targetId; | ||
| 584 | u8 reserved; | ||
| 585 | u16 seqNum; | ||
| 586 | }; | ||
| 587 | |||
| 588 | #define IEEE_SGE_FLAGS_ADDR_MASK (0x03) | ||
| 589 | #define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) | ||
| 590 | #define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) | ||
| 591 | #define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) | ||
| 592 | #define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) | ||
| 593 | #define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) | ||
| 594 | #define IEEE_SGE_FLAGS_END_OF_LIST (0x40) | ||
| 595 | |||
| 596 | struct megasas_register_set; | ||
| 597 | struct megasas_instance; | ||
| 598 | |||
| 599 | union desc_word { | ||
| 600 | u64 word; | ||
| 601 | struct { | ||
| 602 | u32 low; | ||
| 603 | u32 high; | ||
| 604 | } u; | ||
| 605 | }; | ||
| 606 | |||
| 607 | struct megasas_cmd_fusion { | ||
| 608 | struct MPI2_RAID_SCSI_IO_REQUEST *io_request; | ||
| 609 | dma_addr_t io_request_phys_addr; | ||
| 610 | |||
| 611 | union MPI2_SGE_IO_UNION *sg_frame; | ||
| 612 | dma_addr_t sg_frame_phys_addr; | ||
| 613 | |||
| 614 | u8 *sense; | ||
| 615 | dma_addr_t sense_phys_addr; | ||
| 616 | |||
| 617 | struct list_head list; | ||
| 618 | struct scsi_cmnd *scmd; | ||
| 619 | struct megasas_instance *instance; | ||
| 620 | |||
| 621 | u8 retry_for_fw_reset; | ||
| 622 | union MEGASAS_REQUEST_DESCRIPTOR_UNION *request_desc; | ||
| 623 | |||
| 624 | /* | ||
| 625 | * Context for a MFI frame. | ||
| 626 | * Used to get the mfi cmd from list when a MFI cmd is completed | ||
| 627 | */ | ||
| 628 | u32 sync_cmd_idx; | ||
| 629 | u32 index; | ||
| 630 | u8 flags; | ||
| 631 | }; | ||
| 632 | |||
| 633 | struct LD_LOAD_BALANCE_INFO { | ||
| 634 | u8 loadBalanceFlag; | ||
| 635 | u8 reserved1; | ||
| 636 | u16 raid1DevHandle[2]; | ||
| 637 | atomic_t scsi_pending_cmds[2]; | ||
| 638 | u64 last_accessed_block[2]; | ||
| 639 | }; | ||
| 640 | |||
| 641 | struct MR_FW_RAID_MAP_ALL { | ||
| 642 | struct MR_FW_RAID_MAP raidMap; | ||
| 643 | struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1]; | ||
| 644 | } __attribute__ ((packed)); | ||
| 645 | |||
| 646 | struct fusion_context { | ||
| 647 | struct megasas_cmd_fusion **cmd_list; | ||
| 648 | struct list_head cmd_pool; | ||
| 649 | |||
| 650 | spinlock_t cmd_pool_lock; | ||
| 651 | |||
| 652 | dma_addr_t req_frames_desc_phys; | ||
| 653 | u8 *req_frames_desc; | ||
| 654 | |||
| 655 | struct dma_pool *io_request_frames_pool; | ||
| 656 | dma_addr_t io_request_frames_phys; | ||
| 657 | u8 *io_request_frames; | ||
| 658 | |||
| 659 | struct dma_pool *sg_dma_pool; | ||
| 660 | struct dma_pool *sense_dma_pool; | ||
| 661 | |||
| 662 | dma_addr_t reply_frames_desc_phys; | ||
| 663 | union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; | ||
| 664 | struct dma_pool *reply_frames_desc_pool; | ||
| 665 | |||
| 666 | u16 last_reply_idx; | ||
| 667 | |||
| 668 | u32 reply_q_depth; | ||
| 669 | u32 request_alloc_sz; | ||
| 670 | u32 reply_alloc_sz; | ||
| 671 | u32 io_frames_alloc_sz; | ||
| 672 | |||
| 673 | u16 max_sge_in_main_msg; | ||
| 674 | u16 max_sge_in_chain; | ||
| 675 | |||
| 676 | u8 chain_offset_io_request; | ||
| 677 | u8 chain_offset_mfi_pthru; | ||
| 678 | |||
| 679 | struct MR_FW_RAID_MAP_ALL *ld_map[2]; | ||
| 680 | dma_addr_t ld_map_phys[2]; | ||
| 681 | |||
| 682 | u32 map_sz; | ||
| 683 | u8 fast_path_io; | ||
| 684 | struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES]; | ||
| 685 | }; | ||
| 686 | |||
| 687 | union desc_value { | ||
| 688 | u64 word; | ||
| 689 | struct { | ||
| 690 | u32 low; | ||
| 691 | u32 high; | ||
| 692 | } u; | ||
| 693 | }; | ||
| 694 | |||
| 695 | #endif /* _MEGARAID_SAS_FUSION_H_ */ | ||
