Merge by hand (conflicts in sd.c)

This commit is contained in:
James Bottomley
2005-09-06 17:52:54 -05:00
49 changed files with 2487 additions and 760 deletions

View File

@@ -1,5 +1,11 @@
menu "SCSI device support"
config RAID_ATTRS
tristate "RAID Transport Class"
default n
---help---
Provides RAID
config SCSI
tristate "SCSI device support"
---help---

View File

@@ -22,6 +22,8 @@ subdir-$(CONFIG_PCMCIA) += pcmcia
obj-$(CONFIG_SCSI) += scsi_mod.o
obj-$(CONFIG_RAID_ATTRS) += raid_class.o
# --- NOTE ORDERING HERE ---
# For kernel non-modular link, transport attributes need to
# be initialised before drivers

View File

@@ -972,7 +972,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
fibsize = sizeof(struct aac_read64) +
((le32_to_cpu(readcmd->sg.count) - 1) *
sizeof (struct sgentry64));
BUG_ON (fibsize > (sizeof(struct hw_fib) -
BUG_ON (fibsize > (dev->max_fib_size -
sizeof(struct aac_fibhdr)));
/*
* Now send the Fib to the adapter

View File

@@ -48,12 +48,6 @@
static struct scsi_transport_template *ahd_linux_transport_template = NULL;
/*
* Include aiclib.c as part of our
* "module dependencies are hard" work around.
*/
#include "aiclib.c"
#include <linux/init.h> /* __setup */
#include <linux/mm.h> /* For fetching system memory size */
#include <linux/blkdev.h> /* For block_size() */
@@ -372,8 +366,6 @@ static int ahd_linux_run_command(struct ahd_softc*,
struct ahd_linux_device *,
struct scsi_cmnd *);
static void ahd_linux_setup_tag_info_global(char *p);
static aic_option_callback_t ahd_linux_setup_tag_info;
static aic_option_callback_t ahd_linux_setup_iocell_info;
static int aic79xx_setup(char *c);
static int ahd_linux_unit;
@@ -907,6 +899,86 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
}
}
static char *
ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
void (*callback)(u_long, int, int, int32_t),
u_long callback_arg)
{
char *tok_end;
char *tok_end2;
int i;
int instance;
int targ;
int done;
char tok_list[] = {'.', ',', '{', '}', '\0'};
/* All options use a ':' name/arg separator */
if (*opt_arg != ':')
return (opt_arg);
opt_arg++;
instance = -1;
targ = -1;
done = FALSE;
/*
* Restore separator that may be in
* the middle of our option argument.
*/
tok_end = strchr(opt_arg, '\0');
if (tok_end < end)
*tok_end = ',';
while (!done) {
switch (*opt_arg) {
case '{':
if (instance == -1) {
instance = 0;
} else {
if (depth > 1) {
if (targ == -1)
targ = 0;
} else {
printf("Malformed Option %s\n",
opt_name);
done = TRUE;
}
}
opt_arg++;
break;
case '}':
if (targ != -1)
targ = -1;
else if (instance != -1)
instance = -1;
opt_arg++;
break;
case ',':
case '.':
if (instance == -1)
done = TRUE;
else if (targ >= 0)
targ++;
else if (instance >= 0)
instance++;
opt_arg++;
break;
case '\0':
done = TRUE;
break;
default:
tok_end = end;
for (i = 0; tok_list[i]; i++) {
tok_end2 = strchr(opt_arg, tok_list[i]);
if ((tok_end2) && (tok_end2 < tok_end))
tok_end = tok_end2;
}
callback(callback_arg, instance, targ,
simple_strtol(opt_arg, NULL, 0));
opt_arg = tok_end;
break;
}
}
return (opt_arg);
}
/*
* Handle Linux boot parameters. This routine allows for assigning a value
* to a parameter with a ':' between the parameter and the value.
@@ -964,18 +1036,18 @@ aic79xx_setup(char *s)
if (strncmp(p, "global_tag_depth", n) == 0) {
ahd_linux_setup_tag_info_global(p + n);
} else if (strncmp(p, "tag_info", n) == 0) {
s = aic_parse_brace_option("tag_info", p + n, end,
s = ahd_parse_brace_option("tag_info", p + n, end,
2, ahd_linux_setup_tag_info, 0);
} else if (strncmp(p, "slewrate", n) == 0) {
s = aic_parse_brace_option("slewrate",
s = ahd_parse_brace_option("slewrate",
p + n, end, 1, ahd_linux_setup_iocell_info,
AIC79XX_SLEWRATE_INDEX);
} else if (strncmp(p, "precomp", n) == 0) {
s = aic_parse_brace_option("precomp",
s = ahd_parse_brace_option("precomp",
p + n, end, 1, ahd_linux_setup_iocell_info,
AIC79XX_PRECOMP_INDEX);
} else if (strncmp(p, "amplitude", n) == 0) {
s = aic_parse_brace_option("amplitude",
s = ahd_parse_brace_option("amplitude",
p + n, end, 1, ahd_linux_setup_iocell_info,
AIC79XX_AMPLITUDE_INDEX);
} else if (p[n] == ':') {

View File

@@ -53,6 +53,49 @@ static void ahd_dump_device_state(struct info_str *info,
static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
char *buffer, int length);
/*
* Table of syncrates that don't follow the "divisible by 4"
* rule. This table will be expanded in future SCSI specs.
*/
static struct {
u_int period_factor;
u_int period; /* in 100ths of ns */
} scsi_syncrates[] = {
{ 0x08, 625 }, /* FAST-160 */
{ 0x09, 1250 }, /* FAST-80 */
{ 0x0a, 2500 }, /* FAST-40 40MHz */
{ 0x0b, 3030 }, /* FAST-40 33MHz */
{ 0x0c, 5000 } /* FAST-20 */
};
/*
* Return the frequency in kHz corresponding to the given
* sync period factor.
*/
static u_int
ahd_calc_syncsrate(u_int period_factor)
{
int i;
int num_syncrates;
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
/* See if the period is in the "exception" table */
for (i = 0; i < num_syncrates; i++) {
if (period_factor == scsi_syncrates[i].period_factor) {
/* Period in kHz */
return (100000000 / scsi_syncrates[i].period);
}
}
/*
* Wasn't in the table, so use the standard
* 4 times conversion.
*/
return (10000000 / (period_factor * 4 * 10));
}
static void
copy_mem_info(struct info_str *info, char *data, int len)
{
@@ -109,7 +152,7 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
speed = 3300;
freq = 0;
if (tinfo->offset != 0) {
freq = aic_calc_syncsrate(tinfo->period);
freq = ahd_calc_syncsrate(tinfo->period);
speed = freq;
}
speed *= (0x01 << tinfo->width);

View File

@@ -125,12 +125,6 @@
static struct scsi_transport_template *ahc_linux_transport_template = NULL;
/*
* Include aiclib.c as part of our
* "module dependencies are hard" work around.
*/
#include "aiclib.c"
#include <linux/init.h> /* __setup */
#include <linux/mm.h> /* For fetching system memory size */
#include <linux/blkdev.h> /* For block_size() */
@@ -391,7 +385,6 @@ static int ahc_linux_run_command(struct ahc_softc*,
struct ahc_linux_device *,
struct scsi_cmnd *);
static void ahc_linux_setup_tag_info_global(char *p);
static aic_option_callback_t ahc_linux_setup_tag_info;
static int aic7xxx_setup(char *s);
static int ahc_linux_unit;
@@ -920,6 +913,86 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
}
}
static char *
ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
void (*callback)(u_long, int, int, int32_t),
u_long callback_arg)
{
char *tok_end;
char *tok_end2;
int i;
int instance;
int targ;
int done;
char tok_list[] = {'.', ',', '{', '}', '\0'};
/* All options use a ':' name/arg separator */
if (*opt_arg != ':')
return (opt_arg);
opt_arg++;
instance = -1;
targ = -1;
done = FALSE;
/*
* Restore separator that may be in
* the middle of our option argument.
*/
tok_end = strchr(opt_arg, '\0');
if (tok_end < end)
*tok_end = ',';
while (!done) {
switch (*opt_arg) {
case '{':
if (instance == -1) {
instance = 0;
} else {
if (depth > 1) {
if (targ == -1)
targ = 0;
} else {
printf("Malformed Option %s\n",
opt_name);
done = TRUE;
}
}
opt_arg++;
break;
case '}':
if (targ != -1)
targ = -1;
else if (instance != -1)
instance = -1;
opt_arg++;
break;
case ',':
case '.':
if (instance == -1)
done = TRUE;
else if (targ >= 0)
targ++;
else if (instance >= 0)
instance++;
opt_arg++;
break;
case '\0':
done = TRUE;
break;
default:
tok_end = end;
for (i = 0; tok_list[i]; i++) {
tok_end2 = strchr(opt_arg, tok_list[i]);
if ((tok_end2) && (tok_end2 < tok_end))
tok_end = tok_end2;
}
callback(callback_arg, instance, targ,
simple_strtol(opt_arg, NULL, 0));
opt_arg = tok_end;
break;
}
}
return (opt_arg);
}
/*
* Handle Linux boot parameters. This routine allows for assigning a value
* to a parameter with a ':' between the parameter and the value.
@@ -974,7 +1047,7 @@ aic7xxx_setup(char *s)
if (strncmp(p, "global_tag_depth", n) == 0) {
ahc_linux_setup_tag_info_global(p + n);
} else if (strncmp(p, "tag_info", n) == 0) {
s = aic_parse_brace_option("tag_info", p + n, end,
s = ahc_parse_brace_option("tag_info", p + n, end,
2, ahc_linux_setup_tag_info, 0);
} else if (p[n] == ':') {
*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);

View File

@@ -54,6 +54,49 @@ static void ahc_dump_device_state(struct info_str *info,
static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
char *buffer, int length);
/*
* Table of syncrates that don't follow the "divisible by 4"
* rule. This table will be expanded in future SCSI specs.
*/
static struct {
u_int period_factor;
u_int period; /* in 100ths of ns */
} scsi_syncrates[] = {
{ 0x08, 625 }, /* FAST-160 */
{ 0x09, 1250 }, /* FAST-80 */
{ 0x0a, 2500 }, /* FAST-40 40MHz */
{ 0x0b, 3030 }, /* FAST-40 33MHz */
{ 0x0c, 5000 } /* FAST-20 */
};
/*
* Return the frequency in kHz corresponding to the given
* sync period factor.
*/
static u_int
ahc_calc_syncsrate(u_int period_factor)
{
int i;
int num_syncrates;
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
/* See if the period is in the "exception" table */
for (i = 0; i < num_syncrates; i++) {
if (period_factor == scsi_syncrates[i].period_factor) {
/* Period in kHz */
return (100000000 / scsi_syncrates[i].period);
}
}
/*
* Wasn't in the table, so use the standard
* 4 times conversion.
*/
return (10000000 / (period_factor * 4 * 10));
}
static void
copy_mem_info(struct info_str *info, char *data, int len)
{
@@ -106,7 +149,7 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
speed = 3300;
freq = 0;
if (tinfo->offset != 0) {
freq = aic_calc_syncsrate(tinfo->period);
freq = ahc_calc_syncsrate(tinfo->period);
speed = freq;
}
speed *= (0x01 << tinfo->width);

View File

@@ -32,124 +32,3 @@
#include "aiclib.h"
/*
* Table of syncrates that don't follow the "divisible by 4"
* rule. This table will be expanded in future SCSI specs.
*/
static struct {
u_int period_factor;
u_int period; /* in 100ths of ns */
} scsi_syncrates[] = {
{ 0x08, 625 }, /* FAST-160 */
{ 0x09, 1250 }, /* FAST-80 */
{ 0x0a, 2500 }, /* FAST-40 40MHz */
{ 0x0b, 3030 }, /* FAST-40 33MHz */
{ 0x0c, 5000 } /* FAST-20 */
};
/*
* Return the frequency in kHz corresponding to the given
* sync period factor.
*/
u_int
aic_calc_syncsrate(u_int period_factor)
{
int i;
int num_syncrates;
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
/* See if the period is in the "exception" table */
for (i = 0; i < num_syncrates; i++) {
if (period_factor == scsi_syncrates[i].period_factor) {
/* Period in kHz */
return (100000000 / scsi_syncrates[i].period);
}
}
/*
* Wasn't in the table, so use the standard
* 4 times conversion.
*/
return (10000000 / (period_factor * 4 * 10));
}
char *
aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
aic_option_callback_t *callback, u_long callback_arg)
{
char *tok_end;
char *tok_end2;
int i;
int instance;
int targ;
int done;
char tok_list[] = {'.', ',', '{', '}', '\0'};
/* All options use a ':' name/arg separator */
if (*opt_arg != ':')
return (opt_arg);
opt_arg++;
instance = -1;
targ = -1;
done = FALSE;
/*
* Restore separator that may be in
* the middle of our option argument.
*/
tok_end = strchr(opt_arg, '\0');
if (tok_end < end)
*tok_end = ',';
while (!done) {
switch (*opt_arg) {
case '{':
if (instance == -1) {
instance = 0;
} else {
if (depth > 1) {
if (targ == -1)
targ = 0;
} else {
printf("Malformed Option %s\n",
opt_name);
done = TRUE;
}
}
opt_arg++;
break;
case '}':
if (targ != -1)
targ = -1;
else if (instance != -1)
instance = -1;
opt_arg++;
break;
case ',':
case '.':
if (instance == -1)
done = TRUE;
else if (targ >= 0)
targ++;
else if (instance >= 0)
instance++;
opt_arg++;
break;
case '\0':
done = TRUE;
break;
default:
tok_end = end;
for (i = 0; tok_list[i]; i++) {
tok_end2 = strchr(opt_arg, tok_list[i]);
if ((tok_end2) && (tok_end2 < tok_end))
tok_end = tok_end2;
}
callback(callback_arg, instance, targ,
simple_strtol(opt_arg, NULL, 0));
opt_arg = tok_end;
break;
}
}
return (opt_arg);
}

View File

@@ -141,28 +141,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors)
return (int)capacity;
}
/**************************** Module Library Hack *****************************/
/*
* What we'd like to do is have a single "scsi library" module that both the
* aic7xxx and aic79xx drivers could load and depend on. A cursory examination
* of implementing module dependencies in Linux (handling the install and
* initrd cases) does not look promissing. For now, we just duplicate this
* code in both drivers using a simple symbol renaming scheme that hides this
* hack from the drivers.
*/
#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x
#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix)
#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX)
#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate)
u_int aic_calc_syncsrate(u_int /*period_factor*/);
typedef void aic_option_callback_t(u_long, int, int, int32_t);
char * aic_parse_brace_option(char *opt_name, char *opt_arg,
char *end, int depth,
aic_option_callback_t *, u_long);
static __inline uint32_t
scsi_4btoul(uint8_t *bytes)
{

View File

@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -225,15 +226,8 @@ static void scsi_host_dev_release(struct device *dev)
struct Scsi_Host *shost = dev_to_shost(dev);
struct device *parent = dev->parent;
if (shost->ehandler) {
DECLARE_COMPLETION(sem);
shost->eh_notify = &sem;
shost->eh_kill = 1;
up(shost->eh_wait);
wait_for_completion(&sem);
shost->eh_notify = NULL;
}
if (shost->ehandler)
kthread_stop(shost->ehandler);
if (shost->work_q)
destroy_workqueue(shost->work_q);
@@ -263,7 +257,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
struct Scsi_Host *shost;
int gfp_mask = GFP_KERNEL, rval;
DECLARE_COMPLETION(complete);
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
@@ -369,12 +362,12 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->eh_notify = &complete;
rval = kernel_thread(scsi_error_handler, shost, 0);
if (rval < 0)
shost->ehandler = kthread_run(scsi_error_handler, shost,
"scsi_eh_%d", shost->host_no);
if (IS_ERR(shost->ehandler)) {
rval = PTR_ERR(shost->ehandler);
goto fail_destroy_freelist;
wait_for_completion(&complete);
shost->eh_notify = NULL;
}
scsi_proc_hostdir_add(shost->hostt);
return shost;

View File

@@ -87,7 +87,7 @@ static int max_channel = 3;
static int init_timeout = 5;
static int max_requests = 50;
#define IBMVSCSI_VERSION "1.5.6"
#define IBMVSCSI_VERSION "1.5.7"
MODULE_DESCRIPTION("IBM Virtual SCSI");
MODULE_AUTHOR("Dave Boutcher");
@@ -145,6 +145,8 @@ static int initialize_event_pool(struct event_pool *pool,
sizeof(*evt->xfer_iu) * i;
evt->xfer_iu = pool->iu_storage + i;
evt->hostdata = hostdata;
evt->ext_list = NULL;
evt->ext_list_token = 0;
}
return 0;
@@ -161,9 +163,16 @@ static void release_event_pool(struct event_pool *pool,
struct ibmvscsi_host_data *hostdata)
{
int i, in_use = 0;
for (i = 0; i < pool->size; ++i)
for (i = 0; i < pool->size; ++i) {
if (atomic_read(&pool->events[i].free) != 1)
++in_use;
if (pool->events[i].ext_list) {
dma_free_coherent(hostdata->dev,
SG_ALL * sizeof(struct memory_descriptor),
pool->events[i].ext_list,
pool->events[i].ext_list_token);
}
}
if (in_use)
printk(KERN_WARNING
"ibmvscsi: releasing event pool with %d "
@@ -286,24 +295,41 @@ static void set_srp_direction(struct scsi_cmnd *cmd,
} else {
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
srp_cmd->data_out_format = SRP_INDIRECT_BUFFER;
srp_cmd->data_out_count = numbuf;
srp_cmd->data_out_count =
numbuf < MAX_INDIRECT_BUFS ?
numbuf: MAX_INDIRECT_BUFS;
} else {
srp_cmd->data_in_format = SRP_INDIRECT_BUFFER;
srp_cmd->data_in_count = numbuf;
srp_cmd->data_in_count =
numbuf < MAX_INDIRECT_BUFS ?
numbuf: MAX_INDIRECT_BUFS;
}
}
}
static void unmap_sg_list(int num_entries,
struct device *dev,
struct memory_descriptor *md)
{
int i;
for (i = 0; i < num_entries; ++i) {
dma_unmap_single(dev,
md[i].virtual_address,
md[i].length, DMA_BIDIRECTIONAL);
}
}
/**
* unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
* @cmd: srp_cmd whose additional_data member will be unmapped
* @dev: device for which the memory is mapped
*
*/
static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
static void unmap_cmd_data(struct srp_cmd *cmd,
struct srp_event_struct *evt_struct,
struct device *dev)
{
int i;
if ((cmd->data_out_format == SRP_NO_BUFFER) &&
(cmd->data_in_format == SRP_NO_BUFFER))
return;
@@ -318,15 +344,34 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
(struct indirect_descriptor *)cmd->additional_data;
int num_mapped = indirect->head.length /
sizeof(indirect->list[0]);
for (i = 0; i < num_mapped; ++i) {
struct memory_descriptor *data = &indirect->list[i];
dma_unmap_single(dev,
data->virtual_address,
data->length, DMA_BIDIRECTIONAL);
if (num_mapped <= MAX_INDIRECT_BUFS) {
unmap_sg_list(num_mapped, dev, &indirect->list[0]);
return;
}
unmap_sg_list(num_mapped, dev, evt_struct->ext_list);
}
}
static int map_sg_list(int num_entries,
struct scatterlist *sg,
struct memory_descriptor *md)
{
int i;
u64 total_length = 0;
for (i = 0; i < num_entries; ++i) {
struct memory_descriptor *descr = md + i;
struct scatterlist *sg_entry = &sg[i];
descr->virtual_address = sg_dma_address(sg_entry);
descr->length = sg_dma_len(sg_entry);
descr->memory_handle = 0;
total_length += sg_dma_len(sg_entry);
}
return total_length;
}
/**
* map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
* @cmd: Scsi_Cmnd with the scatterlist
@@ -337,10 +382,11 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
* Returns 1 on success.
*/
static int map_sg_data(struct scsi_cmnd *cmd,
struct srp_event_struct *evt_struct,
struct srp_cmd *srp_cmd, struct device *dev)
{
int i, sg_mapped;
int sg_mapped;
u64 total_length = 0;
struct scatterlist *sg = cmd->request_buffer;
struct memory_descriptor *data =
@@ -363,27 +409,46 @@ static int map_sg_data(struct scsi_cmnd *cmd,
return 1;
}
if (sg_mapped > MAX_INDIRECT_BUFS) {
if (sg_mapped > SG_ALL) {
printk(KERN_ERR
"ibmvscsi: More than %d mapped sg entries, got %d\n",
MAX_INDIRECT_BUFS, sg_mapped);
SG_ALL, sg_mapped);
return 0;
}
indirect->head.virtual_address = 0;
indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
indirect->head.memory_handle = 0;
for (i = 0; i < sg_mapped; ++i) {
struct memory_descriptor *descr = &indirect->list[i];
struct scatterlist *sg_entry = &sg[i];
descr->virtual_address = sg_dma_address(sg_entry);
descr->length = sg_dma_len(sg_entry);
descr->memory_handle = 0;
total_length += sg_dma_len(sg_entry);
}
indirect->total_length = total_length;
return 1;
if (sg_mapped <= MAX_INDIRECT_BUFS) {
total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]);
indirect->total_length = total_length;
return 1;
}
/* get indirect table */
if (!evt_struct->ext_list) {
evt_struct->ext_list =(struct memory_descriptor*)
dma_alloc_coherent(dev,
SG_ALL * sizeof(struct memory_descriptor),
&evt_struct->ext_list_token, 0);
if (!evt_struct->ext_list) {
printk(KERN_ERR
"ibmvscsi: Can't allocate memory for indirect table\n");
return 0;
}
}
total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);
indirect->total_length = total_length;
indirect->head.virtual_address = evt_struct->ext_list_token;
indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
memcpy(indirect->list, evt_struct->ext_list,
MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor));
return 1;
}
/**
@@ -428,6 +493,7 @@ static int map_single_data(struct scsi_cmnd *cmd,
* Returns 1 on success.
*/
static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
struct srp_event_struct *evt_struct,
struct srp_cmd *srp_cmd, struct device *dev)
{
switch (cmd->sc_data_direction) {
@@ -450,7 +516,7 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
if (!cmd->request_buffer)
return 1;
if (cmd->use_sg)
return map_sg_data(cmd, srp_cmd, dev);
return map_sg_data(cmd, evt_struct, srp_cmd, dev);
return map_single_data(cmd, srp_cmd, dev);
}
@@ -486,6 +552,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
printk(KERN_WARNING
"ibmvscsi: Warning, request_limit exceeded\n");
unmap_cmd_data(&evt_struct->iu.srp.cmd,
evt_struct,
hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
@@ -513,7 +580,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
return 0;
send_error:
unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
if ((cmnd = evt_struct->cmnd) != NULL) {
cmnd->result = DID_ERROR << 16;
@@ -551,6 +618,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
rsp->sense_and_response_data,
rsp->sense_data_list_length);
unmap_cmd_data(&evt_struct->iu.srp.cmd,
evt_struct,
evt_struct->hostdata->dev);
if (rsp->doover)
@@ -583,6 +651,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
{
struct srp_cmd *srp_cmd;
struct srp_event_struct *evt_struct;
struct indirect_descriptor *indirect;
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
u16 lun = lun_from_dev(cmnd->device);
@@ -591,6 +660,19 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
if (!evt_struct)
return SCSI_MLQUEUE_HOST_BUSY;
/* Set up the actual SRP IU */
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, sizeof(*srp_cmd));
srp_cmd->type = SRP_CMD_TYPE;
memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
}
init_event_struct(evt_struct,
handle_cmd_rsp,
VIOSRP_SRP_FORMAT,
@@ -599,24 +681,11 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
evt_struct->cmnd = cmnd;
evt_struct->cmnd_done = done;
/* Set up the actual SRP IU */
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, sizeof(*srp_cmd));
srp_cmd->type = SRP_CMD_TYPE;
memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) {
printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
}
/* Fix up dma address of the buffer itself */
if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
(srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) {
struct indirect_descriptor *indirect =
(struct indirect_descriptor *)srp_cmd->additional_data;
indirect = (struct indirect_descriptor *)srp_cmd->additional_data;
if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
(srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) &&
(indirect->head.virtual_address == 0)) {
indirect->head.virtual_address = evt_struct->crq.IU_data_ptr +
offsetof(struct srp_cmd, additional_data) +
offsetof(struct indirect_descriptor, list);
@@ -931,7 +1000,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
cmd->result = (DID_ABORT << 16);
list_del(&found_evt->list);
unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev);
unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
found_evt->hostdata->dev);
free_event_struct(&found_evt->hostdata->pool, found_evt);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
atomic_inc(&hostdata->request_limit);
@@ -1023,7 +1093,8 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
if (tmp_evt->cmnd)
tmp_evt->cmnd->result = (DID_RESET << 16);
list_del(&tmp_evt->list);
unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev);
unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
tmp_evt->hostdata->dev);
free_event_struct(&tmp_evt->hostdata->pool,
tmp_evt);
atomic_inc(&hostdata->request_limit);
@@ -1052,6 +1123,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata)
if (tmp_evt->cmnd) {
tmp_evt->cmnd->result = (DID_ERROR << 16);
unmap_cmd_data(&tmp_evt->iu.srp.cmd,
tmp_evt,
tmp_evt->hostdata->dev);
if (tmp_evt->cmnd_done)
tmp_evt->cmnd_done(tmp_evt->cmnd);
@@ -1356,7 +1428,7 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 16,
.can_queue = 1, /* Updated after SRP_LOGIN */
.this_id = -1,
.sg_tablesize = MAX_INDIRECT_BUFS,
.sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = ibmvscsi_attrs,
};

View File

@@ -68,6 +68,8 @@ struct srp_event_struct {
void (*cmnd_done) (struct scsi_cmnd *);
struct completion comp;
union viosrp_iu *sync_srp;
struct memory_descriptor *ext_list;
dma_addr_t ext_list_token;
};
/* a pool of event structs for use */

View File

@@ -211,6 +211,138 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
}
/* Scsi_Host attributes. */
static ssize_t
qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
}
static ssize_t
qla2x00_fw_version_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
char fw_str[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
ha->isp_ops.fw_version_str(ha, fw_str));
}
static ssize_t
qla2x00_serial_num_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
uint32_t sn;
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
sn % 100000);
}
static ssize_t
qla2x00_isp_name_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name);
}
static ssize_t
qla2x00_isp_id_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
}
static ssize_t
qla2x00_model_name_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
}
static ssize_t
qla2x00_model_desc_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n",
ha->model_desc ? ha->model_desc: "");
}
static ssize_t
qla2x00_pci_info_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
char pci_info[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
ha->isp_ops.pci_info_str(ha, pci_info));
}
static ssize_t
qla2x00_state_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
int len = 0;
if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
atomic_read(&ha->loop_state) == LOOP_DEAD)
len = snprintf(buf, PAGE_SIZE, "Link Down\n");
else if (atomic_read(&ha->loop_state) != LOOP_READY ||
test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags))
len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
else {
len = snprintf(buf, PAGE_SIZE, "Link Up - ");
switch (ha->current_topology) {
case ISP_CFG_NL:
len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
break;
case ISP_CFG_FL:
len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
break;
case ISP_CFG_N:
len += snprintf(buf + len, PAGE_SIZE-len,
"N_Port to N_Port\n");
break;
case ISP_CFG_F:
len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
break;
default:
len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
break;
}
}
return len;
}
static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
NULL);
static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
struct class_device_attribute *qla2x00_host_attrs[] = {
&class_device_attr_driver_version,
&class_device_attr_fw_version,
&class_device_attr_serial_num,
&class_device_attr_isp_name,
&class_device_attr_isp_id,
&class_device_attr_model_name,
&class_device_attr_model_desc,
&class_device_attr_pci_info,
&class_device_attr_state,
NULL,
};
/* Host attributes. */
static void
@@ -304,10 +436,13 @@ struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
.show_host_port_name = 1,
.show_host_supported_classes = 1,
.get_host_port_id = qla2x00_get_host_port_id,
.show_host_port_id = 1,
.dd_fcrport_size = sizeof(struct fc_port *),
.show_rport_supported_classes = 1,
.get_starget_node_name = qla2x00_get_starget_node_name,
.show_starget_node_name = 1,
@@ -329,4 +464,5 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
be64_to_cpu(*(uint64_t *)ha->init_cb->node_name);
fc_host_port_name(ha->host) =
be64_to_cpu(*(uint64_t *)ha->init_cb->port_name);
fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
}

View File

@@ -81,6 +81,7 @@
#define DEBUG2_3_11(x) do {x;} while (0);
#define DEBUG2_9_10(x) do {x;} while (0);
#define DEBUG2_11(x) do {x;} while (0);
#define DEBUG2_13(x) do {x;} while (0);
#else
#define DEBUG2(x) do {} while (0);
#endif
@@ -169,8 +170,14 @@
#if defined(QL_DEBUG_LEVEL_13)
#define DEBUG13(x) do {x;} while (0)
#if !defined(DEBUG2_13)
#define DEBUG2_13(x) do {x;} while(0)
#endif
#else
#define DEBUG13(x) do {} while (0)
#if !defined(QL_DEBUG_LEVEL_2)
#define DEBUG2_13(x) do {} while(0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_14)

View File

@@ -214,6 +214,7 @@
* valid range of an N-PORT id is 0 through 0x7ef.
*/
#define NPH_LAST_HANDLE 0x7ef
#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */
#define NPH_SNS 0x7fc /* FFFFFC */
#define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */
#define NPH_F_PORT 0x7fe /* FFFFFE */
@@ -630,6 +631,7 @@ typedef struct {
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
#define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */
#define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */
#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */
#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */
#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */
#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */
@@ -913,7 +915,7 @@ typedef struct {
* MSB BIT 1 =
* MSB BIT 2 =
* MSB BIT 3 =
* MSB BIT 4 =
* MSB BIT 4 = LED mode
* MSB BIT 5 = enable 50 ohm termination
* MSB BIT 6 = Data Rate (2300 only)
* MSB BIT 7 = Data Rate (2300 only)
@@ -1035,7 +1037,7 @@ typedef struct {
* MSB BIT 1 =
* MSB BIT 2 =
* MSB BIT 3 =
* MSB BIT 4 =
* MSB BIT 4 = LED mode
* MSB BIT 5 = enable 50 ohm termination
* MSB BIT 6 = Data Rate (2300 only)
* MSB BIT 7 = Data Rate (2300 only)
@@ -1131,10 +1133,7 @@ typedef struct {
uint8_t link_down_timeout;
uint8_t adapter_id_0[4];
uint8_t adapter_id_1[4];
uint8_t adapter_id_2[4];
uint8_t adapter_id_3[4];
uint8_t adapter_id[16];
uint8_t alt1_boot_node_name[WWN_SIZE];
uint16_t alt1_boot_lun_number;
@@ -1673,6 +1672,7 @@ typedef struct fc_port {
uint8_t cur_path; /* current path id */
struct fc_rport *rport;
u32 supported_classes;
} fc_port_t;
/*
@@ -1727,6 +1727,8 @@ typedef struct fc_port {
#define CT_REJECT_RESPONSE 0x8001
#define CT_ACCEPT_RESPONSE 0x8002
#define CT_REASON_CANNOT_PERFORM 0x09
#define CT_EXPL_ALREADY_REGISTERED 0x10
#define NS_N_PORT_TYPE 0x01
#define NS_NL_PORT_TYPE 0x02
@@ -1768,6 +1770,100 @@ typedef struct fc_port {
#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
#define RSNN_NN_RSP_SIZE 16
/*
* HBA attribute types.
*/
#define FDMI_HBA_ATTR_COUNT 9
#define FDMI_HBA_NODE_NAME 1
#define FDMI_HBA_MANUFACTURER 2
#define FDMI_HBA_SERIAL_NUMBER 3
#define FDMI_HBA_MODEL 4
#define FDMI_HBA_MODEL_DESCRIPTION 5
#define FDMI_HBA_HARDWARE_VERSION 6
#define FDMI_HBA_DRIVER_VERSION 7
#define FDMI_HBA_OPTION_ROM_VERSION 8
#define FDMI_HBA_FIRMWARE_VERSION 9
#define FDMI_HBA_OS_NAME_AND_VERSION 0xa
#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb
struct ct_fdmi_hba_attr {
uint16_t type;
uint16_t len;
union {
uint8_t node_name[WWN_SIZE];
uint8_t manufacturer[32];
uint8_t serial_num[8];
uint8_t model[16];
uint8_t model_desc[80];
uint8_t hw_version[16];
uint8_t driver_version[32];
uint8_t orom_version[16];
uint8_t fw_version[16];
uint8_t os_version[128];
uint8_t max_ct_len[4];
} a;
};
struct ct_fdmi_hba_attributes {
uint32_t count;
struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT];
};
/*
* Port attribute types.
*/
#define FDMI_PORT_ATTR_COUNT 5
#define FDMI_PORT_FC4_TYPES 1
#define FDMI_PORT_SUPPORT_SPEED 2
#define FDMI_PORT_CURRENT_SPEED 3
#define FDMI_PORT_MAX_FRAME_SIZE 4
#define FDMI_PORT_OS_DEVICE_NAME 5
#define FDMI_PORT_HOST_NAME 6
struct ct_fdmi_port_attr {
uint16_t type;
uint16_t len;
union {
uint8_t fc4_types[32];
uint32_t sup_speed;
uint32_t cur_speed;
uint32_t max_frame_size;
uint8_t os_dev_name[32];
uint8_t host_name[32];
} a;
};
/*
* Port Attribute Block.
*/
struct ct_fdmi_port_attributes {
uint32_t count;
struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT];
};
/* FDMI definitions. */
#define GRHL_CMD 0x100
#define GHAT_CMD 0x101
#define GRPL_CMD 0x102
#define GPAT_CMD 0x110
#define RHBA_CMD 0x200
#define RHBA_RSP_SIZE 16
#define RHAT_CMD 0x201
#define RPRT_CMD 0x210
#define RPA_CMD 0x211
#define RPA_RSP_SIZE 16
#define DHBA_CMD 0x300
#define DHBA_REQ_SIZE (16 + 8)
#define DHBA_RSP_SIZE 16
#define DHAT_CMD 0x301
#define DPRT_CMD 0x310
#define DPA_CMD 0x311
/* CT command header -- request/response common fields */
struct ct_cmd_hdr {
uint8_t revision;
@@ -1825,6 +1921,43 @@ struct ct_sns_req {
uint8_t name_len;
uint8_t sym_node_name[255];
} rsnn_nn;
struct {
uint8_t hba_indentifier[8];
} ghat;
struct {
uint8_t hba_identifier[8];
uint32_t entry_count;
uint8_t port_name[8];
struct ct_fdmi_hba_attributes attrs;
} rhba;
struct {
uint8_t hba_identifier[8];
struct ct_fdmi_hba_attributes attrs;
} rhat;
struct {
uint8_t port_name[8];
struct ct_fdmi_port_attributes attrs;
} rpa;
struct {
uint8_t port_name[8];
} dhba;
struct {
uint8_t port_name[8];
} dhat;
struct {
uint8_t port_name[8];
} dprt;
struct {
uint8_t port_name[8];
} dpa;
} req;
};
@@ -1882,6 +2015,12 @@ struct ct_sns_rsp {
struct {
uint8_t fc4_types[32];
} gft_id;
struct {
uint32_t entry_count;
uint8_t port_name[8];
struct ct_fdmi_hba_attributes attrs;
} ghat;
} rsp;
};
@@ -2032,6 +2171,8 @@ struct isp_operations {
uint16_t (*calc_req_entries) (uint16_t);
void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t);
void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t);
void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t,
uint32_t);
uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
@@ -2111,6 +2252,7 @@ typedef struct scsi_qla_host {
#define IOCTL_ERROR_RECOVERY 23
#define LOOP_RESET_NEEDED 24
#define BEACON_BLINK_NEEDED 25
#define REGISTER_FDMI_NEEDED 26
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2204,6 +2346,7 @@ typedef struct scsi_qla_host {
int port_down_retry_count;
uint8_t mbx_count;
uint16_t last_loop_id;
uint16_t mgmt_svr_loop_id;
uint32_t login_retry_count;
@@ -2318,6 +2461,7 @@ typedef struct scsi_qla_host {
uint8_t model_number[16+1];
#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
char *model_desc;
uint8_t adapter_id[16+1];
uint8_t *node_name;
uint8_t *port_name;
@@ -2377,6 +2521,7 @@ typedef struct scsi_qla_host {
#define QLA_SUSPENDED 0x106
#define QLA_BUSY 0x107
#define QLA_RSCNS_HANDLED 0x108
#define QLA_ALREADY_REGISTERED 0x109
/*
* Stat info for all adpaters

View File

@@ -79,6 +79,7 @@ extern int ql2xplogiabsentdevice;
extern int ql2xenablezio;
extern int ql2xintrdelaytimer;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -146,9 +147,6 @@ extern int
qla2x00_abort_target(fc_port_t *);
#endif
extern int
qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *);
extern int
qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
uint8_t *, uint16_t *);
@@ -215,6 +213,9 @@ qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
extern int
qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
qla2x00_stop_firmware(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -269,6 +270,9 @@ extern int qla2x00_rft_id(scsi_qla_host_t *);
extern int qla2x00_rff_id(scsi_qla_host_t *);
extern int qla2x00_rnn_id(scsi_qla_host_t *);
extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_rscn.c source file.
@@ -289,6 +293,8 @@ extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_attr.c source file.
*/
struct class_device_attribute;
extern struct class_device_attribute *qla2x00_host_attrs[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);

View File

@@ -1099,3 +1099,567 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha)
return (rval);
}
/**
* qla2x00_mgmt_svr_login() - Login to fabric Managment Service.
* @ha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
{
int ret;
uint16_t mb[MAILBOX_REGISTER_COUNT];
ret = QLA_SUCCESS;
if (ha->flags.management_server_logged_in)
return ret;
ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
mb, BIT_1);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
"loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
__func__, ha->host_no, ha->mgmt_svr_loop_id, mb[0], mb[1],
mb[2], mb[6], mb[7]));
ret = QLA_FUNCTION_FAILED;
} else
ha->flags.management_server_logged_in = 1;
return ret;
}
/**
* qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
* @ha: HA context
* @req_size: request size in bytes
* @rsp_size: response size in bytes
*
* Returns a pointer to the @ha's ms_iocb.
*/
void *
qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
uint32_t rsp_size)
{
ms_iocb_entry_t *ms_pkt;
ms_pkt = ha->ms_iocb;
memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
ms_pkt->entry_type = MS_IOCB_TYPE;
ms_pkt->entry_count = 1;
SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id);
ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
ms_pkt->timeout = __constant_cpu_to_le16(59);
ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
ms_pkt->req_bytecount = cpu_to_le32(req_size);
ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
return ms_pkt;
}
/**
* qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
* @ha: HA context
* @req_size: request size in bytes
* @rsp_size: response size in bytes
*
* Returns a pointer to the @ha's ms_iocb.
*/
void *
qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
uint32_t rsp_size)
{
struct ct_entry_24xx *ct_pkt;
ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
ct_pkt->entry_type = CT_IOCB_TYPE;
ct_pkt->entry_count = 1;
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
ct_pkt->timeout = __constant_cpu_to_le16(59);
ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
return ct_pkt;
}
static inline ms_iocb_entry_t *
qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size)
{
ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
} else {
ms_pkt->req_bytecount = cpu_to_le32(req_size);
ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
}
return ms_pkt;
}
/**
* qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
* @ct_req: CT request buffer
* @cmd: GS command
* @rsp_size: response size in bytes
*
* Returns a pointer to the intitialized @ct_req.
*/
static inline struct ct_sns_req *
qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd,
uint16_t rsp_size)
{
memset(ct_req, 0, sizeof(struct ct_sns_pkt));
ct_req->header.revision = 0x01;
ct_req->header.gs_type = 0xFA;
ct_req->header.gs_subtype = 0x10;
ct_req->command = cpu_to_be16(cmd);
ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
return ct_req;
}
/**
* qla2x00_fdmi_rhba() -
* @ha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
{
int rval, alen;
uint32_t size, sn;
ms_iocb_entry_t *ms_pkt;
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
uint8_t *entries;
struct ct_fdmi_hba_attr *eiter;
/* Issue RHBA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
RHBA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- attribute block, attributes. */
memcpy(ct_req->req.rhba.hba_identifier, ha->port_name, WWN_SIZE);
ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1);
memcpy(ct_req->req.rhba.port_name, ha->port_name, WWN_SIZE);
size = 2 * WWN_SIZE + 4 + 4;
/* Attributes */
ct_req->req.rhba.attrs.count =
__constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT);
entries = ct_req->req.rhba.hba_identifier;
/* Nodename. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME);
eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE);
memcpy(eiter->a.node_name, ha->node_name, WWN_SIZE);
size += 4 + WWN_SIZE;
DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n",
__func__, ha->host_no,
eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2],
eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5],
eiter->a.node_name[6], eiter->a.node_name[7]));
/* Manufacturer. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER);
strcpy(eiter->a.manufacturer, "QLogic Corporation");
alen = strlen(eiter->a.manufacturer);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, ha->host_no,
eiter->a.manufacturer));
/* Serial number. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER);
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000);
alen = strlen(eiter->a.serial_num);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, ha->host_no,
eiter->a.serial_num));
/* Model name. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL);
strcpy(eiter->a.model, ha->model_number);
alen = strlen(eiter->a.model);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, ha->host_no,
eiter->a.model));
/* Model description. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION);
if (ha->model_desc)
strncpy(eiter->a.model_desc, ha->model_desc, 80);
alen = strlen(eiter->a.model_desc);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, ha->host_no,
eiter->a.model_desc));
/* Hardware version. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION);
strcpy(eiter->a.hw_version, ha->adapter_id);
alen = strlen(eiter->a.hw_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, ha->host_no,
eiter->a.hw_version));
/* Driver version. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION);
strcpy(eiter->a.driver_version, qla2x00_version_str);
alen = strlen(eiter->a.driver_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, ha->host_no,
eiter->a.driver_version));
/* Option ROM version. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION);
strcpy(eiter->a.orom_version, "0.00");
alen = strlen(eiter->a.orom_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, ha->host_no,
eiter->a.orom_version));
/* Firmware version */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
ha->isp_ops.fw_version_str(ha, eiter->a.fw_version);
alen = strlen(eiter->a.fw_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, ha->host_no,
eiter->a.fw_version));
/* Update MS request size. */
qla2x00_update_ms_fdmi_iocb(ha, size + 16);
DEBUG13(printk("%s(%ld): RHBA identifier="
"%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
ha->host_no, ct_req->req.rhba.hba_identifier[0],
ct_req->req.rhba.hba_identifier[1],
ct_req->req.rhba.hba_identifier[2],
ct_req->req.rhba.hba_identifier[3],
ct_req->req.rhba.hba_identifier[4],
ct_req->req.rhba.hba_identifier[5],
ct_req->req.rhba.hba_identifier[6],
ct_req->req.rhba.hba_identifier[7], size));
DEBUG13(qla2x00_dump_buffer(entries, size));
/* Execute MS IOCB */
rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
sizeof(ms_iocb_entry_t));
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n",
ha->host_no, rval));
} else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RHBA") !=
QLA_SUCCESS) {
rval = QLA_FUNCTION_FAILED;
if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM &&
ct_rsp->header.explanation_code ==
CT_EXPL_ALREADY_REGISTERED) {
DEBUG2_13(printk("%s(%ld): HBA already registered.\n",
__func__, ha->host_no));
rval = QLA_ALREADY_REGISTERED;
}
} else {
DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n",
ha->host_no));
}
return rval;
}
/**
* qla2x00_fdmi_dhba() -
* @ha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_fdmi_dhba(scsi_qla_host_t *ha)
{
int rval;
ms_iocb_entry_t *ms_pkt;
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
/* Issue RPA */
/* Prepare common MS IOCB */
ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
DHBA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD,
DHBA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- portname. */
memcpy(ct_req->req.dhba.port_name, ha->port_name, WWN_SIZE);
DEBUG13(printk("%s(%ld): DHBA portname="
"%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, ha->host_no,
ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]));
/* Execute MS IOCB */
rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
sizeof(ms_iocb_entry_t));
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n",
ha->host_no, rval));
} else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "DHBA") !=
QLA_SUCCESS) {
rval = QLA_FUNCTION_FAILED;
} else {
DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n",
ha->host_no));
}
return rval;
}
/**
* qla2x00_fdmi_rpa() -
* @ha: HA context
*
* Returns 0 on success.
*/
static int
qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
{
int rval, alen;
uint32_t size, max_frame_size;
ms_iocb_entry_t *ms_pkt;
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
uint8_t *entries;
struct ct_fdmi_port_attr *eiter;
struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb;
/* Issue RPA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
RPA_RSP_SIZE);
ct_rsp = &ha->ct_sns->p.rsp;
/* Prepare FDMI command arguments -- attribute block, attributes. */
memcpy(ct_req->req.rpa.port_name, ha->port_name, WWN_SIZE);
size = WWN_SIZE + 4;
/* Attributes */
ct_req->req.rpa.attrs.count =
__constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
entries = ct_req->req.rpa.port_name;
/* FC4 types. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES);
eiter->len = __constant_cpu_to_be16(4 + 32);
eiter->a.fc4_types[2] = 0x01;
size += 4 + 32;
DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__, ha->host_no,
eiter->a.fc4_types[2], eiter->a.fc4_types[1]));
/* Supported speed. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
if (IS_QLA25XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(4);
else if (IS_QLA24XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(8);
else if (IS_QLA23XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(2);
else
eiter->a.sup_speed = __constant_cpu_to_be32(1);
size += 4 + 4;
DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no,
eiter->a.sup_speed));
/* Current speed. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
switch (ha->link_data_rate) {
case 0:
eiter->a.cur_speed = __constant_cpu_to_be32(1);
break;
case 1:
eiter->a.cur_speed = __constant_cpu_to_be32(2);
break;
case 3:
eiter->a.cur_speed = __constant_cpu_to_be32(8);
break;
case 4:
eiter->a.cur_speed = __constant_cpu_to_be32(4);
break;
}
size += 4 + 4;
DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, ha->host_no,
eiter->a.cur_speed));
/* Max frame size. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
eiter->len = __constant_cpu_to_be16(4 + 4);
max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ?
(uint32_t) icb24->frame_payload_size:
(uint32_t) ha->init_cb->frame_payload_size;
eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
size += 4 + 4;
DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, ha->host_no,
eiter->a.max_frame_size));
/* OS device name. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no);
alen = strlen(eiter->a.os_dev_name);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
size += 4 + alen;
DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
eiter->a.os_dev_name));
/* Update MS request size. */
qla2x00_update_ms_fdmi_iocb(ha, size + 16);
DEBUG13(printk("%s(%ld): RPA portname="
"%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
ha->host_no, ct_req->req.rpa.port_name[0],
ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2],
ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4],
ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6],
ct_req->req.rpa.port_name[7], size));
DEBUG13(qla2x00_dump_buffer(entries, size));
/* Execute MS IOCB */
rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
sizeof(ms_iocb_entry_t));
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n",
ha->host_no, rval));
} else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RPA") !=
QLA_SUCCESS) {
rval = QLA_FUNCTION_FAILED;
} else {
DEBUG2(printk("scsi(%ld): RPA exiting normally.\n",
ha->host_no));
}
return rval;
}
/**
* qla2x00_fdmi_register() -
* @ha: HA context
*
* Returns 0 on success.
*/
int
qla2x00_fdmi_register(scsi_qla_host_t *ha)
{
int rval;
rval = qla2x00_mgmt_svr_login(ha);
if (rval)
return rval;
rval = qla2x00_fdmi_rhba(ha);
if (rval) {
if (rval != QLA_ALREADY_REGISTERED)
return rval;
rval = qla2x00_fdmi_dhba(ha);
if (rval)
return rval;
rval = qla2x00_fdmi_rhba(ha);
if (rval)
return rval;
}
rval = qla2x00_fdmi_rpa(ha);
return rval;
}

View File

@@ -88,6 +88,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
ha->mbx_flags = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
rval = ha->isp_ops.pci_config(ha);
@@ -1563,7 +1564,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
ha->flags.enable_led_scheme = ((nv->efi_parameters & BIT_3) ? 1 : 0);
ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
ha->operating_mode =
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -1697,6 +1698,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags)
fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
atomic_set(&fcport->state, FCS_UNCONFIGURED);
fcport->flags = FCF_RLC_SUPPORT;
fcport->supported_classes = FC_COS_UNSPECIFIED;
return (fcport);
}
@@ -1898,7 +1900,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
continue;
/* Bypass if not same domain and area of adapter. */
if (area != ha->d_id.b.area || domain != ha->d_id.b.domain)
if (area && domain &&
(area != ha->d_id.b.area || domain != ha->d_id.b.domain))
continue;
/* Bypass invalid local loop ID. */
@@ -2075,6 +2078,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
return;
}
rport->dd_data = fcport;
rport->supported_classes = fcport->supported_classes;
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
if (fcport->port_type == FCT_INITIATOR)
@@ -2130,6 +2134,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
return (QLA_SUCCESS);
}
do {
/* FDMI support. */
if (ql2xfdmienable &&
test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags))
qla2x00_fdmi_register(ha);
/* Ensure we are logged into the SNS. */
if (IS_QLA24XX(ha) || IS_QLA25XX(ha))
loop_id = NPH_SNS;
@@ -2392,6 +2401,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
if (new_fcport->d_id.b24 == ha->d_id.b24)
continue;
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
ISP_CFG_FL)
continue;
/* Bypass reserved domain fields. */
if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
continue;
@@ -2794,6 +2809,11 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
}
}
if (mb[10] & BIT_0)
fcport->supported_classes |= FC_COS_CLASS2;
if (mb[10] & BIT_1)
fcport->supported_classes |= FC_COS_CLASS3;
rval = QLA_SUCCESS;
break;
} else if (mb[0] == MBS_LOOP_ID_USED) {

View File

@@ -810,12 +810,8 @@ qla24xx_start_scsi(srb_t *sp)
ha->req_q_cnt = ha->request_q_length -
(ha->req_ring_index - cnt);
}
if (ha->req_q_cnt < (req_cnt + 2)) {
if (cmd->use_sg)
pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
cmd->sc_data_direction);
if (ha->req_q_cnt < (req_cnt + 2))
goto queuing_error;
}
/* Build command packet. */
ha->current_outstanding_cmd = handle;

View File

@@ -451,6 +451,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = 0;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
/* Update AEN queue. */
qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);

View File

@@ -19,6 +19,7 @@
#include "qla_def.h"
#include <linux/delay.h>
#include <scsi/scsi_transport_fc.h>
static void
qla2x00_mbx_sem_timeout(unsigned long data)
@@ -251,7 +252,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
ictrl = RD_REG_DWORD(&reg->isp24.ictrl);
} else {
mb0 = RD_MAILBOX_REG(ha, reg->isp, 0);
mb0 = RD_MAILBOX_REG(ha, &reg->isp, 0);
ictrl = RD_REG_WORD(&reg->isp.ictrl);
}
printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n",
@@ -982,58 +983,6 @@ qla2x00_abort_target(fc_port_t *fcport)
}
#endif
/*
* qla2x00_target_reset
* Issue target reset mailbox command.
*
* Input:
* ha = adapter block pointer.
* TARGET_QUEUE_LOCK must be released.
* ADAPTER_STATE_LOCK must be released.
*
* Returns:
* qla2x00 local function return status code.
*
* Context:
* Kernel context.
*/
int
qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);)
if (atomic_read(&fcport->state) != FCS_ONLINE)
return 0;
mcp->mb[0] = MBC_TARGET_RESET;
if (HAS_EXTENDED_IDS(ha))
mcp->mb[1] = fcport->loop_id;
else
mcp->mb[1] = fcport->loop_id << 8;
mcp->mb[2] = ha->loop_reset_delay;
mcp->out_mb = MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n",
ha->host_no, rval);)
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_target_reset(%ld): done.\n",
ha->host_no);)
}
return rval;
}
/*
* qla2x00_get_adapter_id
* Get adapter ID and topology.
@@ -1326,6 +1275,10 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
/* Passback COS information. */
fcport->supported_classes = (pd->options & BIT_4) ?
FC_COS_CLASS2: FC_COS_CLASS3;
}
gpd_error_out:
@@ -1661,6 +1614,13 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mb[1] |= BIT_1;
} else
mb[1] = BIT_0;
/* Passback COS information. */
mb[10] = 0;
if (lg->io_parameter[7] || lg->io_parameter[8])
mb[10] |= BIT_0; /* Class 2. */
if (lg->io_parameter[9] || lg->io_parameter[10])
mb[10] |= BIT_1; /* Class 3. */
}
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1723,6 +1683,8 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mb[2] = mcp->mb[2];
mb[6] = mcp->mb[6];
mb[7] = mcp->mb[7];
/* COS retrieved from Get-Port-Database mailbox command. */
mb[10] = 0;
}
if (rval != QLA_SUCCESS) {
@@ -2465,3 +2427,32 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g,
return rval;
}
int
qla2x00_stop_firmware(scsi_qla_host_t *ha)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_STOP_FIRMWARE;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_0;
mcp->tov = 5;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
ha->host_no, rval));
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
}

View File

@@ -79,7 +79,7 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xloginretrycount,
"Specify an alternate value for the NVRAM login retry count.");
int ql2xfwloadbin;
int ql2xfwloadbin=1;
module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xfwloadbin,
"Load ISP2xxx firmware image via hotplug.");
@@ -88,6 +88,12 @@ static void qla2x00_free_device(scsi_qla_host_t *);
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
int ql2xfdmienable;
module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registratons "
"Default is 0 - no FDMI. 1 - perfom FDMI.");
/*
* SCSI host template entry points
*/
@@ -105,6 +111,9 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
static int qla2x00_loop_reset(scsi_qla_host_t *ha);
static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
static struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = "qla2xxx",
@@ -119,6 +128,8 @@ static struct scsi_host_template qla2x00_driver_template = {
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
@@ -129,6 +140,7 @@ static struct scsi_host_template qla2x00_driver_template = {
* which equates to 0x800000 sectors.
*/
.max_sectors = 0xFFFF,
.shost_attrs = qla2x00_host_attrs,
};
static struct scsi_host_template qla24xx_driver_template = {
@@ -145,12 +157,15 @@ static struct scsi_host_template qla24xx_driver_template = {
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
.shost_attrs = qla2x00_host_attrs,
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
@@ -487,14 +502,13 @@ qc24_fail_command:
static int
qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
{
#define ABORT_POLLING_PERIOD HZ
#define ABORT_WAIT_ITER ((10 * HZ) / (ABORT_POLLING_PERIOD))
#define ABORT_POLLING_PERIOD 1000
#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD))
unsigned long wait_iter = ABORT_WAIT_ITER;
int ret = QLA_SUCCESS;
while (CMD_SP(cmd)) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(ABORT_POLLING_PERIOD);
msleep(ABORT_POLLING_PERIOD);
if (--wait_iter)
break;
@@ -1016,7 +1030,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
if (fcport->port_type != FCT_TARGET)
continue;
status = qla2x00_target_reset(ha, fcport);
status = qla2x00_device_reset(ha, fcport);
if (status != QLA_SUCCESS)
break;
}
@@ -1103,6 +1117,28 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
sdev->hostdata = NULL;
}
static int
qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
return sdev->queue_depth;
}
static int
qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
{
if (sdev->tagged_supported) {
scsi_set_tag_type(sdev, tag_type);
if (tag_type)
scsi_activate_tcq(sdev, sdev->queue_depth);
else
scsi_deactivate_tcq(sdev, sdev->queue_depth);
} else
tag_type = 0;
return tag_type;
}
/**
* qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
* @ha: HA context
@@ -1113,36 +1149,23 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
static void
qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
{
/* Assume 32bit DMA address */
/* Assume a 32bit DMA mask. */
ha->flags.enable_64bit_addressing = 0;
/*
* Given the two variants pci_set_dma_mask(), allow the compiler to
* assist in setting the proper dma mask.
*/
if (sizeof(dma_addr_t) > 4) {
if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) {
/* Any upper-dword bits set? */
if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
!pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
/* Ok, a 64bit DMA mask is applicable. */
ha->flags.enable_64bit_addressing = 1;
ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
if (pci_set_consistent_dma_mask(ha->pdev,
DMA_64BIT_MASK)) {
qla_printk(KERN_DEBUG, ha,
"Failed to set 64 bit PCI consistent mask; "
"using 32 bit.\n");
pci_set_consistent_dma_mask(ha->pdev,
DMA_32BIT_MASK);
}
} else {
qla_printk(KERN_DEBUG, ha,
"Failed to set 64 bit PCI DMA mask, falling back "
"to 32 bit MASK.\n");
pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
return;
}
} else {
pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
static int
@@ -1316,6 +1339,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->prev_topology = 0;
ha->ports = MAX_BUSES;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
/* Assign ISP specific operations. */
ha->isp_ops.pci_config = qla2100_pci_config;
@@ -1338,6 +1362,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32;
ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32;
ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb;
ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb;
ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
ha->isp_ops.fw_dump = qla2100_fw_dump;
@@ -1375,6 +1400,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct init_cb_24xx);
ha->mgmt_svr_loop_id = 10;
ha->isp_ops.pci_config = qla24xx_pci_config;
ha->isp_ops.reset_chip = qla24xx_reset_chip;
ha->isp_ops.chip_diag = qla24xx_chip_diag;
@@ -1395,6 +1421,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->isp_ops.fabric_login = qla24xx_login_fabric;
ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
ha->isp_ops.fw_dump = qla24xx_fw_dump;
@@ -1558,8 +1585,6 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
return 0;
probe_failed:
fc_remove_host(ha->host);
qla2x00_free_device(ha);
scsi_host_put(host);
@@ -1601,10 +1626,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
qla2x00_cancel_io_descriptors(ha);
/* turn-off interrupts on the card */
if (ha->interrupts_on)
ha->isp_ops.disable_intrs(ha);
/* Disable timer */
if (ha->timer_active)
qla2x00_stop_timer(ha);
@@ -1624,8 +1645,14 @@ qla2x00_free_device(scsi_qla_host_t *ha)
}
}
qla2x00_mem_free(ha);
/* Stop currently executing firmware. */
qla2x00_stop_firmware(ha);
/* turn-off interrupts on the card */
if (ha->interrupts_on)
ha->isp_ops.disable_intrs(ha);
qla2x00_mem_free(ha);
ha->flags.online = 0;
@@ -1934,7 +1961,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
{
struct list_head *fcpl, *fcptemp;
fc_port_t *fcport;
unsigned long wtime;/* max wait time if mbx cmd is busy. */
unsigned int wtime;/* max wait time if mbx cmd is busy. */
if (ha == NULL) {
/* error */
@@ -1943,11 +1970,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
}
/* Make sure all other threads are stopped. */
wtime = 60 * HZ;
while (ha->dpc_wait && wtime) {
set_current_state(TASK_INTERRUPTIBLE);
wtime = schedule_timeout(wtime);
}
wtime = 60 * 1000;
while (ha->dpc_wait && wtime)
wtime = msleep_interruptible(wtime);
/* free ioctl memory */
qla2x00_free_ioctl_mem(ha);
@@ -2478,15 +2503,15 @@ qla2x00_timer(scsi_qla_host_t *ha)
int
qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
{
const unsigned int step = HZ/10;
const unsigned int step = 100; /* msecs */
unsigned int iterations = jiffies_to_msecs(timeout)/100;
do {
if (!down_trylock(sema))
return 0;
set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout(step))
if (msleep_interruptible(step))
break;
} while ((timeout -= step) > 0);
} while (--iterations >= 0);
return -ETIMEDOUT;
}

View File

@@ -468,21 +468,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
uint32_t i;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
/* Pause RISC. */
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
/* Dword reads to flash. */
for (i = 0; i < dwords; i++, faddr++)
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
flash_data_to_access_addr(faddr)));
/* Release RISC pause. */
WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
return dwptr;
}
@@ -532,10 +523,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
ret = QLA_SUCCESS;
/* Pause RISC. */
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
ha->host_no, man_id, flash_id));
@@ -599,10 +586,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
/* Release RISC pause. */
WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
return ret;
}
@@ -630,11 +613,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
{
uint32_t i;
uint32_t *dwptr;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
/* Pause RISC. */
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
/* Dword reads to flash. */
dwptr = (uint32_t *)buf;
@@ -642,10 +620,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
nvram_data_to_access_addr(naddr)));
/* Release RISC pause. */
WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
return buf;
}
@@ -690,10 +664,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
ret = QLA_SUCCESS;
/* Pause RISC. */
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
/* Enable flash write. */
WRT_REG_DWORD(&reg->ctrl_status,
RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -728,9 +698,5 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
/* Release RISC pause. */
WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
return ret;
}

View File

@@ -19,9 +19,9 @@
/*
* Driver version
*/
#define QLA2XXX_VERSION "8.01.00b5-k"
#define QLA2XXX_VERSION "8.01.00-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 5
#define QLA_DRIVER_BETA_VER 0

250
drivers/scsi/raid_class.c Normal file
View File

@@ -0,0 +1,250 @@
/*
* RAID Attributes
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/raid_class.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#define RAID_NUM_ATTRS 3
struct raid_internal {
struct raid_template r;
struct raid_function_template *f;
/* The actual attributes */
struct class_device_attribute private_attrs[RAID_NUM_ATTRS];
/* The array of null terminated pointers to attributes
* needed by scsi_sysfs.c */
struct class_device_attribute *attrs[RAID_NUM_ATTRS + 1];
};
struct raid_component {
struct list_head node;
struct device *dev;
int num;
};
#define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r)
#define tc_to_raid_internal(tcont) ({ \
struct raid_template *r = \
container_of(tcont, struct raid_template, raid_attrs); \
to_raid_internal(r); \
})
#define ac_to_raid_internal(acont) ({ \
struct transport_container *tc = \
container_of(acont, struct transport_container, ac); \
tc_to_raid_internal(tc); \
})
#define class_device_to_raid_internal(cdev) ({ \
struct attribute_container *ac = \
attribute_container_classdev_to_container(cdev); \
ac_to_raid_internal(ac); \
})
static int raid_match(struct attribute_container *cont, struct device *dev)
{
/* We have to look for every subsystem that could house
* emulated RAID devices, so start with SCSI */
struct raid_internal *i = ac_to_raid_internal(cont);
if (scsi_is_sdev_device(dev)) {
struct scsi_device *sdev = to_scsi_device(dev);
if (i->f->cookie != sdev->host->hostt)
return 0;
return i->f->is_raid(dev);
}
/* FIXME: look at other subsystems too */
return 0;
}
static int raid_setup(struct transport_container *tc, struct device *dev,
struct class_device *cdev)
{
struct raid_data *rd;
BUG_ON(class_get_devdata(cdev));
rd = kmalloc(sizeof(*rd), GFP_KERNEL);
if (!rd)
return -ENOMEM;
memset(rd, 0, sizeof(*rd));
INIT_LIST_HEAD(&rd->component_list);
class_set_devdata(cdev, rd);
return 0;
}
static int raid_remove(struct transport_container *tc, struct device *dev,
struct class_device *cdev)
{
struct raid_data *rd = class_get_devdata(cdev);
struct raid_component *rc, *next;
class_set_devdata(cdev, NULL);
list_for_each_entry_safe(rc, next, &rd->component_list, node) {
char buf[40];
snprintf(buf, sizeof(buf), "component-%d", rc->num);
list_del(&rc->node);
sysfs_remove_link(&cdev->kobj, buf);
kfree(rc);
}
kfree(class_get_devdata(cdev));
return 0;
}
static DECLARE_TRANSPORT_CLASS(raid_class,
"raid_devices",
raid_setup,
raid_remove,
NULL);
static struct {
enum raid_state value;
char *name;
} raid_states[] = {
{ RAID_ACTIVE, "active" },
{ RAID_DEGRADED, "degraded" },
{ RAID_RESYNCING, "resyncing" },
{ RAID_OFFLINE, "offline" },
};
static const char *raid_state_name(enum raid_state state)
{
int i;
char *name = NULL;
for (i = 0; i < sizeof(raid_states)/sizeof(raid_states[0]); i++) {
if (raid_states[i].value == state) {
name = raid_states[i].name;
break;
}
}
return name;
}
#define raid_attr_show_internal(attr, fmt, var, code) \
static ssize_t raid_show_##attr(struct class_device *cdev, char *buf) \
{ \
struct raid_data *rd = class_get_devdata(cdev); \
code \
return snprintf(buf, 20, #fmt "\n", var); \
}
#define raid_attr_ro_states(attr, states, code) \
raid_attr_show_internal(attr, %s, name, \
const char *name; \
code \
name = raid_##states##_name(rd->attr); \
) \
static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
#define raid_attr_ro_internal(attr, code) \
raid_attr_show_internal(attr, %d, rd->attr, code) \
static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
#define ATTR_CODE(attr) \
struct raid_internal *i = class_device_to_raid_internal(cdev); \
if (i->f->get_##attr) \
i->f->get_##attr(cdev->dev);
#define raid_attr_ro(attr) raid_attr_ro_internal(attr, )
#define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr))
#define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr))
raid_attr_ro(level);
raid_attr_ro_fn(resync);
raid_attr_ro_state(state);
void raid_component_add(struct raid_template *r,struct device *raid_dev,
struct device *component_dev)
{
struct class_device *cdev =
attribute_container_find_class_device(&r->raid_attrs.ac,
raid_dev);
struct raid_component *rc;
struct raid_data *rd = class_get_devdata(cdev);
char buf[40];
rc = kmalloc(sizeof(*rc), GFP_KERNEL);
if (!rc)
return;
INIT_LIST_HEAD(&rc->node);
rc->dev = component_dev;
rc->num = rd->component_count++;
snprintf(buf, sizeof(buf), "component-%d", rc->num);
list_add_tail(&rc->node, &rd->component_list);
sysfs_create_link(&cdev->kobj, &component_dev->kobj, buf);
}
EXPORT_SYMBOL(raid_component_add);
struct raid_template *
raid_class_attach(struct raid_function_template *ft)
{
struct raid_internal *i = kmalloc(sizeof(struct raid_internal),
GFP_KERNEL);
int count = 0;
if (unlikely(!i))
return NULL;
memset(i, 0, sizeof(*i));
i->f = ft;
i->r.raid_attrs.ac.class = &raid_class.class;
i->r.raid_attrs.ac.match = raid_match;
i->r.raid_attrs.ac.attrs = &i->attrs[0];
attribute_container_register(&i->r.raid_attrs.ac);
i->attrs[count++] = &class_device_attr_level;
i->attrs[count++] = &class_device_attr_resync;
i->attrs[count++] = &class_device_attr_state;
i->attrs[count] = NULL;
BUG_ON(count > RAID_NUM_ATTRS);
return &i->r;
}
EXPORT_SYMBOL(raid_class_attach);
void
raid_class_release(struct raid_template *r)
{
struct raid_internal *i = to_raid_internal(r);
attribute_container_unregister(&i->r.raid_attrs.ac);
kfree(i);
}
EXPORT_SYMBOL(raid_class_release);
static __init int raid_init(void)
{
return transport_class_register(&raid_class);
}
static __exit void raid_exit(void)
{
transport_class_unregister(&raid_class);
}
MODULE_AUTHOR("James Bottomley");
MODULE_DESCRIPTION("RAID device class");
MODULE_LICENSE("GPL");
module_init(raid_init);
module_exit(raid_exit);

View File

@@ -192,6 +192,7 @@ static struct {
{"SGI", "RAID5", "*", BLIST_SPARSELUN},
{"SGI", "TP9100", "*", BLIST_REPORTLUN2},
{"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
{"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
{"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
{"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */

View File

@@ -20,6 +20,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -115,7 +116,6 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
add_timer(&scmd->eh_timeout);
}
EXPORT_SYMBOL(scsi_add_timer);
/**
* scsi_delete_timer - Delete/cancel timer for a given function.
@@ -143,7 +143,6 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
return rtn;
}
EXPORT_SYMBOL(scsi_delete_timer);
/**
* scsi_times_out - Timeout function for normal scsi commands.
@@ -776,9 +775,11 @@ retry_tur:
__FUNCTION__, scmd, rtn));
if (rtn == SUCCESS)
return 0;
else if (rtn == NEEDS_RETRY)
else if (rtn == NEEDS_RETRY) {
if (retry_cnt--)
goto retry_tur;
return 0;
}
return 1;
}
@@ -1583,16 +1584,8 @@ int scsi_error_handler(void *data)
int rtn;
DECLARE_MUTEX_LOCKED(sem);
/*
* Flush resources
*/
daemonize("scsi_eh_%d", shost->host_no);
current->flags |= PF_NOFREEZE;
shost->eh_wait = &sem;
shost->ehandler = current;
/*
* Wake up the thread that created us.
@@ -1600,8 +1593,6 @@ int scsi_error_handler(void *data)
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of"
" scsi_eh_%d\n",shost->host_no));
complete(shost->eh_notify);
while (1) {
/*
* If we get a signal, it means we are supposed to go
@@ -1622,7 +1613,7 @@ int scsi_error_handler(void *data)
* semaphores isn't unreasonable.
*/
down_interruptible(&sem);
if (shost->eh_kill)
if (kthread_should_stop())
break;
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
@@ -1661,22 +1652,6 @@ int scsi_error_handler(void *data)
* Make sure that nobody tries to wake us up again.
*/
shost->eh_wait = NULL;
/*
* Knock this down too. From this point on, the host is flying
* without a pilot. If this is because the module is being unloaded,
* that's fine. If the user sent a signal to this thing, we are
* potentially in real danger.
*/
shost->eh_active = 0;
shost->ehandler = NULL;
/*
* If anyone is waiting for us to exit (i.e. someone trying to unload
* a driver), then wake up that process to let them know we are on
* the way out the door.
*/
complete_and_exit(shost->eh_notify, 0);
return 0;
}

View File

@@ -30,20 +30,20 @@
#define MAX_BUF PAGE_SIZE
/*
* If we are told to probe a host, we will return 0 if the host is not
* present, 1 if the host is present, and will return an identifying
* string at *arg, if arg is non null, filling to the length stored at
* (int *) arg
/**
* ioctl_probe -- return host identification
* @host: host to identify
* @buffer: userspace buffer for identification
*
* Return an identifying string at @buffer, if @buffer is non-NULL, filling
* to the length stored at * (int *) @buffer.
*/
static int ioctl_probe(struct Scsi_Host *host, void __user *buffer)
{
unsigned int len, slen;
const char *string;
int temp = host->hostt->present;
if (temp && buffer) {
if (buffer) {
if (get_user(len, (unsigned int __user *) buffer))
return -EFAULT;
@@ -59,7 +59,7 @@ static int ioctl_probe(struct Scsi_Host *host, void __user *buffer)
return -EFAULT;
}
}
return temp;
return 1;
}
/*

View File

@@ -63,6 +63,9 @@ extern int __init scsi_init_devinfo(void);
extern void scsi_exit_devinfo(void);
/* scsi_error.c */
extern void scsi_add_timer(struct scsi_cmnd *, int,
void (*)(struct scsi_cmnd *));
extern int scsi_delete_timer(struct scsi_cmnd *);
extern void scsi_times_out(struct scsi_cmnd *cmd);
extern int scsi_error_handler(void *host);
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);

View File

@@ -972,7 +972,7 @@ static void
sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
{
unsigned char cmd[10];
unsigned long spintime_value = 0;
unsigned long spintime_expire = 0;
int retries, spintime;
unsigned int the_result;
struct scsi_sense_hdr sshdr;
@@ -1049,12 +1049,27 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
scsi_execute_req(sdkp->device, cmd, DMA_NONE,
NULL, 0, &sshdr,
SD_TIMEOUT, SD_MAX_RETRIES);
spintime_value = jiffies;
spintime_expire = jiffies + 100 * HZ;
spintime = 1;
}
spintime = 1;
/* Wait 1 second for next try */
msleep(1000);
printk(".");
/*
* Wait for USB flash devices with slow firmware.
* Yes, this sense key/ASC combination shouldn't
* occur here. It's characteristic of these devices.
*/
} else if (sense_valid &&
sshdr.sense_key == UNIT_ATTENTION &&
sshdr.asc == 0x28) {
if (!spintime) {
spintime_expire = jiffies + 5 * HZ;
spintime = 1;
}
/* Wait 1 second for next try */
msleep(1000);
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
@@ -1066,8 +1081,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
break;
}
} while (spintime &&
time_after(spintime_value + 100 * HZ, jiffies));
} while (spintime && time_before_eq(jiffies, spintime_expire));
if (spintime) {
if (scsi_status_is_good(the_result))

View File

@@ -61,7 +61,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
static char *sg_version_date = "20050328";
static char *sg_version_date = "20050901";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -1794,12 +1794,12 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
unsigned long uaddr, size_t count, int rw,
unsigned long max_pfn)
{
unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned long start = uaddr >> PAGE_SHIFT;
const int nr_pages = end - start;
int res, i, j;
unsigned int nr_pages;
struct page **pages;
nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
return -EINVAL;

View File

@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
static char *verstr = "20050802";
static char *verstr = "20050830";
#include <linux/module.h>
@@ -4440,12 +4440,12 @@ static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pag
static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
unsigned long uaddr, size_t count, int rw)
{
unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned long start = uaddr >> PAGE_SHIFT;
const int nr_pages = end - start;
int res, i, j;
unsigned int nr_pages;
struct page **pages;
nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
return -EINVAL;