|
@@ -10,7 +10,7 @@
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
*
|
|
|
* FILE : megaraid_sas.c
|
|
|
- * Version : v00.00.02.01
|
|
|
+ * Version : v00.00.02.02
|
|
|
*
|
|
|
* Authors:
|
|
|
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
|
|
@@ -55,13 +55,13 @@ static struct pci_device_id megasas_pci_table[] = {
|
|
|
|
|
|
{
|
|
|
PCI_VENDOR_ID_LSI_LOGIC,
|
|
|
- PCI_DEVICE_ID_LSI_SAS1064R,
|
|
|
+ PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP
|
|
|
PCI_ANY_ID,
|
|
|
PCI_ANY_ID,
|
|
|
},
|
|
|
{
|
|
|
PCI_VENDOR_ID_DELL,
|
|
|
- PCI_DEVICE_ID_DELL_PERC5,
|
|
|
+ PCI_DEVICE_ID_DELL_PERC5, // xscale IOP
|
|
|
PCI_ANY_ID,
|
|
|
PCI_ANY_ID,
|
|
|
},
|
|
@@ -119,12 +119,18 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
|
|
|
spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+* The following functions are defined for xscale
|
|
|
+* (deviceid : 1064R, PERC5) controllers
|
|
|
+*/
|
|
|
+
|
|
|
/**
|
|
|
- * megasas_enable_intr - Enables interrupts
|
|
|
+ * megasas_enable_intr_xscale - Enables interrupts
|
|
|
* @regs: MFI register set
|
|
|
*/
|
|
|
static inline void
|
|
|
-megasas_enable_intr(struct megasas_register_set __iomem * regs)
|
|
|
+megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
|
|
|
{
|
|
|
writel(1, &(regs)->outbound_intr_mask);
|
|
|
|
|
@@ -132,6 +138,66 @@ megasas_enable_intr(struct megasas_register_set __iomem * regs)
|
|
|
readl(®s->outbound_intr_mask);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * megasas_read_fw_status_reg_xscale - returns the current FW status value
|
|
|
+ * @regs: MFI register set
|
|
|
+ */
|
|
|
+static u32
|
|
|
+megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
|
|
|
+{
|
|
|
+ return readl(&(regs)->outbound_msg_0);
|
|
|
+}
|
|
|
+/**
|
|
|
+ * megasas_clear_interrupt_xscale - Check & clear interrupt
|
|
|
+ * @regs: MFI register set
|
|
|
+ */
|
|
|
+static int
|
|
|
+megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
|
|
|
+{
|
|
|
+ u32 status;
|
|
|
+ /*
|
|
|
+ * Check if it is our interrupt
|
|
|
+ */
|
|
|
+ status = readl(®s->outbound_intr_status);
|
|
|
+
|
|
|
+ if (!(status & MFI_OB_INTR_STATUS_MASK)) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear the interrupt by writing back the same value
|
|
|
+ */
|
|
|
+ writel(status, ®s->outbound_intr_status);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * megasas_fire_cmd_xscale - Sends command to the FW
|
|
|
+ * @frame_phys_addr : Physical address of cmd
|
|
|
+ * @frame_count : Number of frames for the command
|
|
|
+ * @regs : MFI register set
|
|
|
+ */
|
|
|
+static inline void
|
|
|
+megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
|
|
|
+{
|
|
|
+ writel((frame_phys_addr >> 3)|(frame_count),
|
|
|
+ &(regs)->inbound_queue_port);
|
|
|
+}
|
|
|
+
|
|
|
+static struct megasas_instance_template megasas_instance_template_xscale = {
|
|
|
+
|
|
|
+ .fire_cmd = megasas_fire_cmd_xscale,
|
|
|
+ .enable_intr = megasas_enable_intr_xscale,
|
|
|
+ .clear_intr = megasas_clear_intr_xscale,
|
|
|
+ .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+* This is the end of set of functions & definitions specific
|
|
|
+* to xscale (deviceid : 1064R, PERC5) controllers
|
|
|
+*/
|
|
|
+
|
|
|
/**
|
|
|
* megasas_disable_intr - Disables interrupts
|
|
|
* @regs: MFI register set
|
|
@@ -139,7 +205,7 @@ megasas_enable_intr(struct megasas_register_set __iomem * regs)
|
|
|
static inline void
|
|
|
megasas_disable_intr(struct megasas_register_set __iomem * regs)
|
|
|
{
|
|
|
- u32 mask = readl(®s->outbound_intr_mask) & (~0x00000001);
|
|
|
+ u32 mask = 0x1f;
|
|
|
writel(mask, ®s->outbound_intr_mask);
|
|
|
|
|
|
/* Dummy readl to force pci flush */
|
|
@@ -167,8 +233,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
|
|
|
/*
|
|
|
* Issue the frame using inbound queue port
|
|
|
*/
|
|
|
- writel(cmd->frame_phys_addr >> 3,
|
|
|
- &instance->reg_set->inbound_queue_port);
|
|
|
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
|
|
|
|
|
|
/*
|
|
|
* Wait for cmd_status to change
|
|
@@ -198,8 +263,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
|
|
{
|
|
|
cmd->cmd_status = ENODATA;
|
|
|
|
|
|
- writel(cmd->frame_phys_addr >> 3,
|
|
|
- &instance->reg_set->inbound_queue_port);
|
|
|
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
|
|
|
|
|
|
wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
|
|
|
|
|
@@ -242,8 +306,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
|
|
cmd->sync_cmd = 1;
|
|
|
cmd->cmd_status = 0xFF;
|
|
|
|
|
|
- writel(cmd->frame_phys_addr >> 3,
|
|
|
- &instance->reg_set->inbound_queue_port);
|
|
|
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
|
|
|
|
|
|
/*
|
|
|
* Wait for this cmd to complete
|
|
@@ -633,8 +696,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
|
|
|
instance->fw_outstanding++;
|
|
|
spin_unlock_irqrestore(&instance->instance_lock, flags);
|
|
|
|
|
|
- writel(((cmd->frame_phys_addr >> 3) | (cmd->frame_count - 1)),
|
|
|
- &instance->reg_set->inbound_queue_port);
|
|
|
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -1045,7 +1107,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
|
|
|
static int
|
|
|
megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
|
|
|
{
|
|
|
- u32 status;
|
|
|
u32 producer;
|
|
|
u32 consumer;
|
|
|
u32 context;
|
|
@@ -1053,17 +1114,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
|
|
|
|
|
|
/*
|
|
|
* Check if it is our interrupt
|
|
|
+ * Clear the interrupt
|
|
|
*/
|
|
|
- status = readl(&instance->reg_set->outbound_intr_status);
|
|
|
-
|
|
|
- if (!(status & MFI_OB_INTR_STATUS_MASK)) {
|
|
|
+ if(instance->instancet->clear_intr(instance->reg_set))
|
|
|
return IRQ_NONE;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Clear the interrupt by writing back the same value
|
|
|
- */
|
|
|
- writel(status, &instance->reg_set->outbound_intr_status);
|
|
|
|
|
|
producer = *instance->producer;
|
|
|
consumer = *instance->consumer;
|
|
@@ -1097,7 +1151,7 @@ static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
|
|
|
|
|
|
/**
|
|
|
* megasas_transition_to_ready - Move the FW to READY state
|
|
|
- * @reg_set: MFI register set
|
|
|
+ * @instance: Adapter soft state
|
|
|
*
|
|
|
* During the initialization, FW passes can potentially be in any one of
|
|
|
* several possible states. If the FW in operational, waiting-for-handshake
|
|
@@ -1105,14 +1159,14 @@ static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
|
|
|
* has to wait for the ready state.
|
|
|
*/
|
|
|
static int
|
|
|
-megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
|
|
|
+megasas_transition_to_ready(struct megasas_instance* instance)
|
|
|
{
|
|
|
int i;
|
|
|
u8 max_wait;
|
|
|
u32 fw_state;
|
|
|
u32 cur_state;
|
|
|
|
|
|
- fw_state = readl(®_set->outbound_msg_0) & MFI_STATE_MASK;
|
|
|
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
|
|
|
|
|
|
while (fw_state != MFI_STATE_READY) {
|
|
|
|
|
@@ -1130,7 +1184,7 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
|
|
|
* Set the CLR bit in inbound doorbell
|
|
|
*/
|
|
|
writel(MFI_INIT_CLEAR_HANDSHAKE,
|
|
|
- ®_set->inbound_doorbell);
|
|
|
+ &instance->reg_set->inbound_doorbell);
|
|
|
|
|
|
max_wait = 2;
|
|
|
cur_state = MFI_STATE_WAIT_HANDSHAKE;
|
|
@@ -1140,8 +1194,8 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
|
|
|
/*
|
|
|
* Bring it to READY state; assuming max wait 2 secs
|
|
|
*/
|
|
|
- megasas_disable_intr(reg_set);
|
|
|
- writel(MFI_INIT_READY, ®_set->inbound_doorbell);
|
|
|
+ megasas_disable_intr(instance->reg_set);
|
|
|
+ writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
|
|
|
|
|
|
max_wait = 10;
|
|
|
cur_state = MFI_STATE_OPERATIONAL;
|
|
@@ -1190,8 +1244,8 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
|
|
|
* The cur_state should not last for more than max_wait secs
|
|
|
*/
|
|
|
for (i = 0; i < (max_wait * 1000); i++) {
|
|
|
- fw_state = MFI_STATE_MASK &
|
|
|
- readl(®_set->outbound_msg_0);
|
|
|
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
|
|
|
+ MFI_STATE_MASK ;
|
|
|
|
|
|
if (fw_state == cur_state) {
|
|
|
msleep(1);
|
|
@@ -1553,18 +1607,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
|
|
|
|
|
|
reg_set = instance->reg_set;
|
|
|
|
|
|
+ instance->instancet = &megasas_instance_template_xscale;
|
|
|
+
|
|
|
/*
|
|
|
* We expect the FW state to be READY
|
|
|
*/
|
|
|
- if (megasas_transition_to_ready(instance->reg_set))
|
|
|
+ if (megasas_transition_to_ready(instance))
|
|
|
goto fail_ready_state;
|
|
|
|
|
|
/*
|
|
|
* Get various operational parameters from status register
|
|
|
*/
|
|
|
- instance->max_fw_cmds = readl(®_set->outbound_msg_0) & 0x00FFFF;
|
|
|
- instance->max_num_sge = (readl(®_set->outbound_msg_0) & 0xFF0000) >>
|
|
|
- 0x10;
|
|
|
+ instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
|
|
|
+ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
|
|
|
+ 0x10;
|
|
|
/*
|
|
|
* Create a pool of commands
|
|
|
*/
|
|
@@ -1873,8 +1929,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
|
|
|
/*
|
|
|
* Issue the aen registration frame
|
|
|
*/
|
|
|
- writel(cmd->frame_phys_addr >> 3,
|
|
|
- &instance->reg_set->inbound_queue_port);
|
|
|
+ instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2063,7 +2118,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
goto fail_irq;
|
|
|
}
|
|
|
|
|
|
- megasas_enable_intr(instance->reg_set);
|
|
|
+ instance->instancet->enable_intr(instance->reg_set);
|
|
|
|
|
|
/*
|
|
|
* Store instance in PCI softstate
|