/**
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
#include <scsi/iscsi_proto.h>
#include "be.h"
#include "be_mgmt.h"
#include "be_main.h"
int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
{
u32 sreset;
u8 *pci_reset_offset = 0;
u8 *pci_online0_offset = 0;
u8 *pci_online1_offset = 0;
u32 pconline0 = 0;
u32 pconline1 = 0;
u32 i;
pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET;
pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0;
pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1;
sreset = readl((void *)pci_reset_offset);
sreset |= BE2_SET_RESET;
writel(sreset, (void *)pci_reset_offset);
i = 0;
while (sreset & BE2_SET_RESET) {
if (i > 64)
break;
msleep(100);
sreset = readl((void *)pci_reset_offset);
i++;
}
if (sreset & BE2_SET_RESET) {
printk(KERN_ERR DRV_NAME
" Soft Reset did not deassert\n");
return -EIO;
}
pconline1 = BE2_MPU_IRAM_ONLINE;
writel(pconline0, (void *)pci_online0_offset);
writel(pconline1, (void *)pci_online1_offset);
sreset = BE2_SET_RESET;
writel(sreset, (void *)pci_reset_offset);
i = 0;
while (sreset & BE2_SET_RESET) {
if (i > 64)
break;
msleep(1);
sreset = readl((void *)pci_reset_offset);
i++;
}
if (sreset & BE2_SET_RESET) {
printk(KERN_ERR DRV_NAME
" MPU Online Soft Reset did not deassert\n");
return -EIO;
}
return 0;
}
int be_chk_reset_complete(struct beiscsi_hba *phba)
{
unsigned int num_loop;
u8 *mpu_sem = 0;
u32 status;
num_loop = 1000;
mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
msleep(5000);
while (num_loop) {
status = readl((void *)mpu_sem);
if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000)
break;
msleep(60);
num_loop--;
}
if ((status & 0x80000000) || (!num_loop)) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BC_%d : Failed in be_chk_reset_complete"
"status = 0x%x\n", status);
return -EIO;
}
return 0;
}
void be_mcc_notify(struct beiscsi_hba *phba)
{
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
u32 val = 0;
val |= mccq->id & DB_MCCQ_RING_ID_MASK;
val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
}
unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
{
unsigned int tag = 0;
if (phba->ctrl.mcc_tag_available) {
tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
phba->ctrl.mcc_numtag[tag] = 0;
}
if (tag) {
phba->ctrl.mcc_tag_available--;
if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
phba->ctrl.mcc_alloc_index = 0;
else
phba->ctrl.mcc_alloc_index++;
}
return tag;
}
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag)
{
spin_lock(&ctrl->mbox_lock);
tag = tag & 0x000000FF;
ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
ctrl->mcc_free_index = 0;
else