/*
* zfcp device driver
*
* Module interface and handling of zfcp data structures.
*
* Copyright IBM Corporation 2002, 2008
*/
/*
* Driver authors:
* Martin Peschke (originator of the driver)
* Raimund Schroeder
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader
* Heiko Carstens (kernel 2.6 port of the driver)
* Andreas Herrmann
* Maxim Shchetynin
* Volker Sameske
* Ralph Wuerthner
* Michael Loehr
* Swen Schillig
* Christof Schmitt
* Martin Petermann
* Sven Schuetz
*/
#include <linux/miscdevice.h>
#include "zfcp_ext.h"
static char *device;
/*********************** FUNCTION PROTOTYPES *********************************/
/* written against the module interface */
static int __init zfcp_module_init(void);
/*********************** KERNEL/MODULE PARAMETERS ***************************/
/* declare driver module init/cleanup functions */
module_init(zfcp_module_init);
MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com");
MODULE_DESCRIPTION
("FCP (SCSI over Fibre Channel) HBA driver for IBM System z9 and zSeries");
MODULE_LICENSE("GPL");
module_param(device, charp, 0400);
MODULE_PARM_DESC(device, "specify initial device");
/****************************************************************/
/************** Functions without logging ***********************/
/****************************************************************/
void
_zfcp_hex_dump(char *addr, int count)
{
int i;
for (i = 0; i < count; i++) {
printk("%02x", addr[i]);
if ((i % 4) == 3)
printk(" ");
if ((i % 32) == 31)
printk("\n");
}
if (((i-1) % 32) != 31)
printk("\n");
}
/****************************************************************/
/****** Functions to handle the request ID hash table ********/
/****************************************************************/
static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
{
int idx;
adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
GFP_KERNEL);
if (!adapter->req_list)
return -ENOMEM;
for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
INIT_LIST_HEAD(&adapter->req_list[idx]);
return 0;
}
static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
{
kfree(adapter->req_list);
}
int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
{
unsigned int idx;
for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
if (!list_empty(&adapter->req_list[idx]))
return 0;
return 1;
}
/****************************************************************/
/************** Uncategorised Functions *************************/
/****************************************************************/
/**
* zfcp_device_setup - setup function
* @str: pointer to parameter string
*
* Parse "device=..." parameter string.
*/
static int __init
zfcp_device_setup(char *devstr)
{
char *tmp, *str;
size_t len;
if (!devstr)
return 0;
len = strlen(devstr) + 1;
str = kmalloc(len, GFP_KERNEL);
if (!str) {
pr_err("zfcp: Could not allocate memory for "
"device parameter string, device not attached.\n");
return 0;
}
memcpy(str, devstr, len);
tmp = strchr(str, ',');
if (!tmp)
goto err_out;
*tmp++ = '\0';
strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE);
zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0';
zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0);
if (*tmp++ != ',')
goto err_out;
if (*tmp == '\0')
goto err_out;
zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0);
if (*tmp != '\0')
goto err_out;
kfree(str);
return 1;
err_out:
pr_err("zfcp: Parse error for device parameter string %s, "
"device not attached.\n", str);
kfree(str);
return 0;
}
static void __init
zfcp_init_device_configure(void)
{
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
down(&zfcp_data.config_sema);
read_lock_irq(&zfcp_data.config_lock);
adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid);
if (adapter)
zfcp_adapter_get(adapter);
read_unlock_irq(&zfcp_data.config_lock);
if (adapter == NULL)
goto out_adapter;
port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0);
if (!port)
goto out_port;
unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun);
if (!unit)
goto out_unit;
up(&zfcp_data.config_sema);
ccw_device_set_online(adapter->ccw_device);
zfcp_erp_wait(adapter);
down(&zfcp_data.config_sema);
zfcp_unit_put(unit);
out_unit:
zfcp_port_put(port);
out_port:
zfcp_adapter_put(adapter);
out_adapter:
up(&zfcp_data.config_sema);
return;
}
static int calc_alignment(