/*
* Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
* All rights reserved
* www.brocade.com
*
* Linux driver for Brocade Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
* published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/uaccess.h>
#include "bfad_drv.h"
#include "bfad_im.h"
#include "bfad_bsg.h"
BFA_TRC_FILE(LDRV, BSG);
/* bfad_im_bsg_get_kobject - increment the bfa refcnt */
static void
bfad_im_bsg_get_kobject(struct fc_bsg_job *job)
{
struct Scsi_Host *shost = job->shost;
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
__module_get(shost->dma_dev->driver->owner);
spin_unlock_irqrestore(shost->host_lock, flags);
}
/* bfad_im_bsg_put_kobject - decrement the bfa refcnt */
static void
bfad_im_bsg_put_kobject(struct fc_bsg_job *job)
{
struct Scsi_Host *shost = job->shost;
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
module_put(shost->dma_dev->driver->owner);
spin_unlock_irqrestore(shost->host_lock, flags);
}
static int
bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd)
{
int i;
struct bfa_bsg_ioc_info_s *iocmd = (struct bfa_bsg_ioc_info_s *)cmd;
struct bfad_im_port_s *im_port;
struct bfa_port_attr_s pattr;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
bfa_fcport_get_attr(&bfad->bfa, &pattr);
iocmd->nwwn = pattr.nwwn;
iocmd->pwwn = pattr.pwwn;
iocmd->ioc_type = bfa_get_type(&bfad->bfa);
iocmd->mac = bfa_get_mac(&bfad->bfa);
iocmd->factory_mac = bfa_get_mfg_mac(&bfad->bfa);
bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum);
iocmd->factorynwwn = pattr.factorynwwn;
iocmd->factorypwwn = pattr.factorypwwn;
im_port = bfad->pport.im_port;
iocmd->host = im_port->shost->host_no;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
strcpy(iocmd->name, bfad->adapter_name);
strcpy(iocmd->port_name, bfad->port_name);
strcpy(iocmd->hwpath, bfad->pci_name);
/* set adapter hw path */
strcpy(iocmd->adapter_hwpath, bfad->pci_name);
i = strlen(iocmd->adapter_hwpath) - 1;
while (iocmd->adapter_hwpath[i] != '.')
i--;
iocmd->adapter_hwpath[i] = '\0';
iocmd->status = BFA_STATUS_OK;
return 0;
}
static int
bfad_iocmd_ioc_get_attr(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_ioc_attr_s *iocmd = (struct bfa_bsg_ioc_attr_s *)cmd;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
bfa_ioc_get_attr(&bfad->bfa.ioc, &iocmd->ioc_attr);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
/* fill in driver attr info */
strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME);
strncpy(iocmd->ioc_attr.driver_attr.driver_ver,
BFAD_DRIVER_VERSION, BFA_VERSION_LEN);
strcpy(iocmd->ioc_attr.driver_attr.fw_ver,
iocmd->ioc_attr.adapter_attr.fw_ver);
strcpy(iocmd->ioc_attr.driver_attr.bios_ver,
iocmd->ioc_attr.adapter_attr.optrom_ver);
/* copy chip rev info first otherwise it will be overwritten */
memcpy(bfad->pci_attr.chip_rev, iocmd->ioc_attr.pci_attr.chip_rev,
sizeof(bfad->pci_attr.chip_rev));
memcpy(&iocmd->ioc_attr.pci_attr, &bfad->pci_attr,
sizeof(struct bfa_ioc_pci_attr_s));
iocmd->status = BFA_STATUS_OK;
return 0;
}
static int
bfad_iocmd_port_get_attr(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_port_attr_s *iocmd = (struct bfa_bsg_port_attr_s *)cmd;
struct bfa_lport_attr_s port_attr;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
bfa_fcport_get_attr(&bfad->bfa, &iocmd->attr);
bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
if (iocmd->attr.topology != BFA_PORT_TOPOLOGY_NONE)
iocmd->attr.pid = port_attr.pid;
else
iocmd->attr.pid = 0;
iocmd->attr.port_type = port_attr.port_type;
iocmd<