diff options
author | adam radford <aradford@gmail.com> | 2010-12-21 16:34:31 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-23 00:26:53 -0500 |
commit | 9c915a8c99bce637226aa09cb05fc18486b229cb (patch) | |
tree | 7bc2330661366db6407548a12366f7340f1b31e9 /drivers/scsi | |
parent | cd50ba8ede5cd3c4606a8e5d163913da5ff36ad7 (diff) |
[SCSI] megaraid_sas: Add 9565/9285 specific code
This patch adds MegaRAID 9265/9285 (Device id 0x5b) specific code
Signed-off-by: Adam Radford <aradford@gmail.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-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_ */ | ||