Commit a4632aae authored by Xiangliang Yu's avatar Xiangliang Yu Committed by James Bottomley

[SCSI] mvsas: Add new macros and functions

Add new macros: MVS_SOFT_RESET, MVS_HARD_RESET, MVS_PHY_TUNE,
	MVS_COMMAND_ACTIVE, EXP_BRCT_CHG, MVS_MAX_SG
Add new member sg_width in struct mvs_chip_info
Use macros rather than magic number
Add new functions: mvs_fill_ssp_resp_iu, mvs_set_sense,
	mvs_94xx_clear_srs_irq, mvs_94xx_phy_set_link_rate
Signed-off-by: default avatarXiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent b89e8f53
......@@ -48,7 +48,7 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
u32 tmp;
tmp = mr32(MVS_PCS);
if (mvi->chip->n_phy <= 4)
if (mvi->chip->n_phy <= MVS_SOC_PORTS)
tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
else
tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
......@@ -95,7 +95,7 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
u32 reg, tmp;
if (!(mvi->flags & MVF_FLAG_SOC)) {
if (phy_id < 4)
if (phy_id < MVS_SOC_PORTS)
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
else
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
......@@ -104,13 +104,13 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
reg = mr32(MVS_PHY_CTL);
tmp = reg;
if (phy_id < 4)
if (phy_id < MVS_SOC_PORTS)
tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
else
tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS;
if (!(mvi->flags & MVF_FLAG_SOC)) {
if (phy_id < 4) {
if (phy_id < MVS_SOC_PORTS) {
pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
mdelay(10);
pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
......@@ -133,9 +133,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
tmp &= ~PHYEV_RDY_CH;
mvs_write_port_irq_stat(mvi, phy_id, tmp);
tmp = mvs_read_phy_ctl(mvi, phy_id);
if (hard == 1)
if (hard == MVS_HARD_RESET)
tmp |= PHY_RST_HARD;
else if (hard == 0)
else if (hard == MVS_SOFT_RESET)
tmp |= PHY_RST;
mvs_write_phy_ctl(mvi, phy_id, tmp);
if (hard) {
......@@ -346,7 +346,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
mvs_64xx_enable_xmt(mvi, i);
mvs_64xx_phy_reset(mvi, i, 1);
mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET);
msleep(500);
mvs_64xx_detect_porttype(mvi, i);
}
......@@ -661,7 +661,7 @@ void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
tmp |= lrmax;
}
mvs_write_phy_ctl(mvi, phy_id, tmp);
mvs_64xx_phy_reset(mvi, phy_id, 1);
mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET);
}
static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
......
......@@ -389,7 +389,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
mvs_phy_hacks(mvi);
/* set LED blink when IO*/
mw32(MVS_PA_VSR_ADDR, 0x00000030);
mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED);
tmp = mr32(MVS_PA_VSR_PORT);
tmp &= 0xFFFF00FF;
tmp |= 0x00003300;
......@@ -419,7 +419,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
mvs_94xx_config_reg_from_hba(mvi, i);
mvs_94xx_phy_enable(mvi, i);
mvs_94xx_phy_reset(mvi, i, 1);
mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD);
msleep(500);
mvs_94xx_detect_porttype(mvi, i);
}
......@@ -585,23 +585,59 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
{
u32 tmp;
mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32));
tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3));
if (tmp && 1 << (slot_idx % 32)) {
mv_printk("command active %08X, slot [%x].\n", tmp, slot_idx);
mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3),
1 << (slot_idx % 32));
do {
tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3));
tmp = mvs_cr32(mvi,
MVS_COMMAND_ACTIVE + (slot_idx >> 3));
} while (tmp & 1 << (slot_idx % 32));
}
}
static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
u32 tfs)
void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
{
void __iomem *regs = mvi->regs;
u32 tmp;
if (type == PORT_TYPE_SATA) {
tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
if (clear_all) {
tmp = mr32(MVS_INT_STAT_SRS_0);
if (tmp) {
mv_dprintk("check SRS 0 %08X.\n", tmp);
mw32(MVS_INT_STAT_SRS_0, tmp);
}
mw32(MVS_INT_STAT, CINT_CI_STOP);
tmp = mr32(MVS_INT_STAT_SRS_1);
if (tmp) {
mv_dprintk("check SRS 1 %08X.\n", tmp);
mw32(MVS_INT_STAT_SRS_1, tmp);
}
} else {
if (reg_set > 31)
tmp = mr32(MVS_INT_STAT_SRS_1);
else
tmp = mr32(MVS_INT_STAT_SRS_0);
if (tmp & (1 << (reg_set % 32))) {
mv_dprintk("register set 0x%x was stopped.\n", reg_set);
if (reg_set > 31)
mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32));
else
mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32));
}
}
}
static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
u32 tfs)
{
void __iomem *regs = mvi->regs;
u32 tmp;
mvs_94xx_clear_srs_irq(mvi, 0, 1);
tmp = mr32(MVS_INT_STAT);
mw32(MVS_INT_STAT, tmp | CINT_CI_STOP);
tmp = mr32(MVS_PCS) | 0xFF00;
mw32(MVS_PCS, tmp);
}
......@@ -794,7 +830,18 @@ static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
struct sas_phy_linkrates *rates)
{
/* TODO */
u32 lrmax = 0;
u32 tmp;
tmp = mvs_read_phy_ctl(mvi, phy_id);
lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12;
if (lrmax) {
tmp &= ~(0x3 << 12);
tmp |= lrmax;
}
mvs_write_phy_ctl(mvi, phy_id, tmp);
mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD);
}
static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
......@@ -893,15 +940,6 @@ void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
}
}
/*
* FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work
* with 64xx fixes
*/
static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
u8 clear_all)
{
}
static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
{
void __iomem *regs = mvi->regs;
......
......@@ -109,6 +109,7 @@ enum hw_registers {
MVS_P4_VSR_DATA = 0x254, /* phy4 VSR data */
MVS_PA_VSR_ADDR = 0x290, /* All port VSR addr */
MVS_PA_VSR_PORT = 0x294, /* All port VSR data */
MVS_COMMAND_ACTIVE = 0x300,
};
enum pci_cfg_registers {
......@@ -132,6 +133,7 @@ enum sas_sata_vsp_regs {
VSR_PHY_MODE9 = 0x09 * 4, /* Test */
VSR_PHY_MODE10 = 0x0A * 4, /* Power */
VSR_PHY_MODE11 = 0x0B * 4, /* Phy Mode */
VSR_PHY_ACT_LED = 0x0C * 4, /* Activity LED control */
VSR_PHY_FFE_CONTROL = 0x10C,
VSR_PHY_DFE_UPDATE_CRTL = 0x110,
......
......@@ -398,6 +398,7 @@ enum mvs_event_flags {
PHY_PLUG_EVENT = (3U),
PHY_PLUG_IN = (1U << 0), /* phy plug in */
PHY_PLUG_OUT = (1U << 1), /* phy plug out */
EXP_BRCT_CHG = (1U << 2), /* broadcast change */
};
enum mvs_port_type {
......
......@@ -39,15 +39,15 @@ int interrupt_coalescing = 0x80;
static struct scsi_transport_template *mvs_stt;
struct kmem_cache *mvs_task_list_cache;
static const struct mvs_chip_info mvs_chips[] = {
[chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
[chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
[chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
[chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
[chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
[chip_9445] = { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
[chip_9485] = { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
[chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
[chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
[chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, },
[chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, },
[chip_6485] = { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, },
[chip_9180] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, },
[chip_9480] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, },
[chip_9445] = { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
[chip_9485] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
[chip_1300] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, },
[chip_1320] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, },
};
struct device_attribute *mvst_host_attrs[];
......@@ -466,7 +466,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr;
shost->transportt = mvs_stt;
shost->max_id = 128;
shost->max_id = MVS_MAX_DEVICES;
shost->max_lun = ~0;
shost->max_channel = 1;
shost->max_cmd_len = 16;
......@@ -512,6 +512,7 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
can_queue = MVS_CHIP_SLOT_SZ;
sha->lldd_queue_size = can_queue;
shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG);
shost->can_queue = can_queue;
mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE;
sha->core.shost = mvi->shost;
......
......@@ -203,12 +203,12 @@ int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
if (tmp & PHY_RST_HARD)
break;
MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET);
break;
case PHY_FUNC_LINK_RESET:
MVS_CHIP_DISP->phy_enable(mvi, phy_id);
MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET);
break;
case PHY_FUNC_DISABLE:
......@@ -1758,12 +1758,63 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
return stat;
}
void mvs_set_sense(u8 *buffer, int len, int d_sense,
int key, int asc, int ascq)
{
memset(buffer, 0, len);
if (d_sense) {
/* Descriptor format */
if (len < 4) {
mv_printk("Length %d of sense buffer too small to "
"fit sense %x:%x:%x", len, key, asc, ascq);
}
buffer[0] = 0x72; /* Response Code */
if (len > 1)
buffer[1] = key; /* Sense Key */
if (len > 2)
buffer[2] = asc; /* ASC */
if (len > 3)
buffer[3] = ascq; /* ASCQ */
} else {
if (len < 14) {
mv_printk("Length %d of sense buffer too small to "
"fit sense %x:%x:%x", len, key, asc, ascq);
}
buffer[0] = 0x70; /* Response Code */
if (len > 2)
buffer[2] = key; /* Sense Key */
if (len > 7)
buffer[7] = 0x0a; /* Additional Sense Length */
if (len > 12)
buffer[12] = asc; /* ASC */
if (len > 13)
buffer[13] = ascq; /* ASCQ */
}
return;
}
void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
u8 key, u8 asc, u8 asc_q)
{
iu->datapres = 2;
iu->response_data_len = 0;
iu->sense_data_len = 17;
iu->status = 02;
mvs_set_sense(iu->sense_data, 17, 0,
key, asc, asc_q);
}
static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
u32 slot_idx)
{
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
int stat;
u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
u32 tfs = 0;
enum mvs_port_type type = PORT_TYPE_SAS;
......@@ -1775,8 +1826,19 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
stat = SAM_STAT_CHECK_CONDITION;
switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
{
stat = SAS_ABORTED_TASK;
if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) {
struct ssp_response_iu *iu = slot->response +
sizeof(struct mvs_err_info);
mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01);
sas_ssp_task_response(mvi->dev, task, iu);
stat = SAM_STAT_CHECK_CONDITION;
}
if (err_dw1 & bit(31))
mv_printk("reuse same slot, retry command.\n");
break;
}
case SAS_PROTOCOL_SMP:
stat = SAM_STAT_CHECK_CONDITION;
break;
......@@ -1974,14 +2036,14 @@ static void mvs_work_queue(struct work_struct *work)
struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
struct mvs_info *mvi = mwq->mvi;
unsigned long flags;
spin_lock_irqsave(&mvi->lock, flags);
if (mwq->handler & PHY_PLUG_EVENT) {
u32 phy_no = (unsigned long) mwq->data;
struct sas_ha_struct *sas_ha = mvi->sas;
struct mvs_phy *phy = &mvi->phy[phy_no];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
spin_lock_irqsave(&mvi->lock, flags);
if (mwq->handler & PHY_PLUG_EVENT) {
if (phy->phy_event & PHY_PLUG_OUT) {
u32 tmp;
struct sas_identify_frame *id;
......@@ -2002,6 +2064,11 @@ static void mvs_work_queue(struct work_struct *work)
mv_dprintk("phy%d Attached Device\n", phy_no);
}
}
} else if (mwq->handler & EXP_BRCT_CHG) {
phy->phy_event &= ~EXP_BRCT_CHG;
sas_ha->notify_port_event(sas_phy,
PORTE_BROADCAST_RCVD);
mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
}
list_del(&mwq->entry);
spin_unlock_irqrestore(&mvi->lock, flags);
......@@ -2037,7 +2104,7 @@ static void mvs_sig_time_out(unsigned long tphy)
if (&mvi->phy[phy_no] == phy) {
mv_dprintk("Get signature time out, reset phy %d\n",
phy_no+mvi->id*mvi->chip->n_phy);
MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET);
}
}
}
......@@ -2045,9 +2112,7 @@ static void mvs_sig_time_out(unsigned long tphy)
void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
{
u32 tmp;
struct sas_ha_struct *sas_ha = mvi->sas;
struct mvs_phy *phy = &mvi->phy[phy_no];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
......@@ -2086,7 +2151,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
phy_no);
else
MVS_CHIP_DISP->phy_reset(mvi,
phy_no, 0);
phy_no, MVS_SOFT_RESET);
return;
}
}
......@@ -2118,14 +2183,14 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
}
mvs_update_phyinfo(mvi, phy_no, 0);
if (phy->phy_type & PORT_TYPE_SAS) {
MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE);
mdelay(10);
}
mvs_bytes_dmaed(mvi, phy_no);
/* whether driver is going to handle hot plug */
if (phy->phy_event & PHY_PLUG_OUT) {
mvs_port_notify_formed(sas_phy, 0);
mvs_port_notify_formed(&phy->sas_phy, 0);
phy->phy_event &= ~PHY_PLUG_OUT;
}
} else {
......@@ -2135,9 +2200,8 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
} else if (phy->irq_status & PHYEV_BROAD_CH) {
mv_dprintk("port %d broadcast change.\n",
phy_no + mvi->id*mvi->chip->n_phy);
/* exception for Samsung disk drive*/
mdelay(1000);
sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
EXP_BRCT_CHG);
}
MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
}
......
......@@ -96,6 +96,11 @@ enum dev_status {
MVS_DEV_EH = 0x1,
};
enum dev_reset {
MVS_SOFT_RESET = 0,
MVS_HARD_RESET = 1,
MVS_PHY_TUNE = 2,
};
struct mvs_info;
......@@ -176,9 +181,11 @@ struct mvs_chip_info {
u32 fis_offs;
u32 fis_count;
u32 srs_sz;
u32 sg_width;
u32 slot_width;
const struct mvs_dispatch *dispatch;
};
#define MVS_MAX_SG (1U << mvi->chip->sg_width)
#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
#define MVS_RX_FISL_SZ \
(mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment