mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
SCSI misc on 20150911
The major pieces of this patch are a set patches facilitating better integration between scsi and scsi_dh (the device handling layer used by multi-path; all the dm parts are acked by Mike Snitzer). It also includes driver updates for mp3sas, scsi_debug and an assortment of bug fixes. Signed-off-by: James Bottomley <JBottomley@Odin.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABAgAGBQJV8yt5AAoJEDeqqVYsXL0MBsQH+wXvlx3o0BGuz5ZXfIs/RxzI MwGnu1J0LSA9FPakkMUVOBtsxIG+pCV+4eKorQMkfGCKAZ8daaYsyYvSEM2mcqIX 1Y/srEnbzfE94JHbsI2pbiMPkB7QdtW27WjTSjQGgD9igAyVmmITiQJrXbpAlSLF F6n++9avng+GhjXQ5TF8/y13OYgabIoAPM1j4B/ut/Ok8ReruBvMBnOla5w5RMKR rBZKTZfUwvX5S0cuREwj8tFsRVUgdBNSrcGswFJrZo5x9WAsSHLC6+SOLZuUy1vC ua0tNtEiyXiuR0/jSP9qv7hJ/j0BW+EGdnW6GZEzKpeMK5PxfVspOsbNunUDRsY= =Y9G1 -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull second round of SCSI updates from James Bottomley: "There's one late arriving patch here (added today), fixing a build issue which the scsi_dh patch set in here uncovered. Other than that, everything has been incubated in -next and the checkers for a week. The major pieces of this patch are a set patches facilitating better integration between scsi and scsi_dh (the device handling layer used by multi-path; all the dm parts are acked by Mike Snitzer). This also includes driver updates for mp3sas, scsi_debug and an assortment of bug fixes" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (50 commits) scsi_dh: fix randconfig build error scsi: fix scsi_error_handler vs. scsi_host_dev_release race fcoe: Convert use of __constant_htons to htons mpt2sas: setpci reset kernel oops fix pm80xx: Don't override ts->stat on IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY lpfc: Fix possible use-after-free and double free in lpfc_mbx_cmpl_rdp_page_a2() bfa: Fix incorrect de-reference of pointer bfa: Fix indentation scsi_transport_sas: Remove check for SAS expander when querying bay/enclosure IDs. scsi_debug: resp_request: remove unused variable scsi_debug: fix REPORT LUNS Well Known LU scsi_debug: schedule_resp fix input variable check scsi_debug: make dump_sector static scsi_debug: vfree is null safe so drop the check scsi_debug: use SCSI_W_LUN_REPORT_LUNS instead of SAM2_WLUN_REPORT_LUNS; scsi_debug: define pr_fmt() for consistent logging mpt2sas: Refcount fw_events and fix unsafe list usage mpt2sas: Refcount sas_device objects and fix unsafe list usage scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() scsi_dh: don't allow to detach device handlers at runtime ...
This commit is contained in:
commit
8e78b7dc93
@ -393,7 +393,7 @@ config DM_MULTIPATH
|
||||
# of SCSI_DH if the latter isn't defined but if
|
||||
# it is, DM_MULTIPATH must depend on it. We get a build
|
||||
# error if SCSI_DH=m and DM_MULTIPATH=y
|
||||
depends on SCSI_DH || !SCSI_DH
|
||||
depends on !SCSI_DH || SCSI
|
||||
---help---
|
||||
Allow volume managers to support multipath hardware.
|
||||
|
||||
|
@ -159,12 +159,9 @@ static struct priority_group *alloc_priority_group(void)
|
||||
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
|
||||
{
|
||||
struct pgpath *pgpath, *tmp;
|
||||
struct multipath *m = ti->private;
|
||||
|
||||
list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
|
||||
list_del(&pgpath->list);
|
||||
if (m->hw_handler_name)
|
||||
scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
|
||||
dm_put_device(ti, pgpath->path.dev);
|
||||
free_pgpath(pgpath);
|
||||
}
|
||||
@ -580,6 +577,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
|
||||
q = bdev_get_queue(p->path.dev->bdev);
|
||||
|
||||
if (m->retain_attached_hw_handler) {
|
||||
retain:
|
||||
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
|
||||
if (attached_handler_name) {
|
||||
/*
|
||||
@ -599,20 +597,14 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
|
||||
}
|
||||
|
||||
if (m->hw_handler_name) {
|
||||
/*
|
||||
* Increments scsi_dh reference, even when using an
|
||||
* already-attached handler.
|
||||
*/
|
||||
r = scsi_dh_attach(q, m->hw_handler_name);
|
||||
if (r == -EBUSY) {
|
||||
/*
|
||||
* Already attached to different hw_handler:
|
||||
* try to reattach with correct one.
|
||||
*/
|
||||
scsi_dh_detach(q);
|
||||
r = scsi_dh_attach(q, m->hw_handler_name);
|
||||
}
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
printk(KERN_INFO "dm-mpath: retaining handler on device %s\n",
|
||||
bdevname(p->path.dev->bdev, b));
|
||||
goto retain;
|
||||
}
|
||||
if (r < 0) {
|
||||
ti->error = "error attaching hardware handler";
|
||||
dm_put_device(ti, p->path.dev);
|
||||
@ -624,7 +616,6 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
|
||||
if (r < 0) {
|
||||
ti->error = "unable to set hardware "
|
||||
"handler parameters";
|
||||
scsi_dh_detach(q);
|
||||
dm_put_device(ti, p->path.dev);
|
||||
goto bad;
|
||||
}
|
||||
@ -734,12 +725,6 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
|
||||
return 0;
|
||||
|
||||
m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL);
|
||||
if (!try_then_request_module(scsi_dh_handler_exist(m->hw_handler_name),
|
||||
"scsi_dh_%s", m->hw_handler_name)) {
|
||||
ti->error = "unknown hardware handler type";
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hw_argc > 1) {
|
||||
char *p;
|
||||
|
@ -172,6 +172,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
|
||||
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
|
||||
scsi_mod-y += scsi_trace.o scsi_logging.o
|
||||
scsi_mod-$(CONFIG_PM) += scsi_pm.o
|
||||
scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o
|
||||
|
||||
hv_storvsc-y := storvsc_drv.o
|
||||
|
||||
|
@ -983,7 +983,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
|
||||
{
|
||||
int err, i;
|
||||
u32 offs, size;
|
||||
struct asd_ll_el *el;
|
||||
struct asd_ll_el *el = NULL;
|
||||
struct asd_ctrla_phy_settings *ps;
|
||||
struct asd_ctrla_phy_settings dflt_ps;
|
||||
|
||||
@ -1004,6 +1004,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
|
||||
|
||||
size = sizeof(struct asd_ctrla_phy_settings);
|
||||
ps = &dflt_ps;
|
||||
goto out_process;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
@ -1028,7 +1029,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
|
||||
ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
out_process:
|
||||
err = asd_process_ctrla_phy_settings(asd_ha, ps);
|
||||
if (err) {
|
||||
ASD_DPRINTK("couldn't process ctrla phy settings\n");
|
||||
|
@ -3665,19 +3665,19 @@ bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp)
|
||||
if (sfp->state_query_cbfn)
|
||||
sfp->state_query_cbfn(sfp->state_query_cbarg,
|
||||
sfp->status);
|
||||
sfp->media = NULL;
|
||||
}
|
||||
sfp->media = NULL;
|
||||
}
|
||||
|
||||
if (sfp->portspeed) {
|
||||
sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed);
|
||||
if (sfp->state_query_cbfn)
|
||||
sfp->state_query_cbfn(sfp->state_query_cbarg,
|
||||
sfp->status);
|
||||
sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;
|
||||
}
|
||||
if (sfp->portspeed) {
|
||||
sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed);
|
||||
if (sfp->state_query_cbfn)
|
||||
sfp->state_query_cbfn(sfp->state_query_cbarg,
|
||||
sfp->status);
|
||||
sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
sfp->state_query_lock = 0;
|
||||
sfp->state_query_cbfn = NULL;
|
||||
sfp->state_query_lock = 0;
|
||||
sfp->state_query_cbfn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3878,7 +3878,7 @@ bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
|
||||
bfa_trc(sfp, sfp->data_valid);
|
||||
if (sfp->data_valid) {
|
||||
u32 size = sizeof(struct sfp_mem_s);
|
||||
u8 *des = (u8 *) &(sfp->sfpmem);
|
||||
u8 *des = (u8 *)(sfp->sfpmem);
|
||||
memcpy(des, sfp->dbuf_kva, size);
|
||||
}
|
||||
/*
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
menuconfig SCSI_DH
|
||||
tristate "SCSI Device Handlers"
|
||||
bool "SCSI Device Handlers"
|
||||
depends on SCSI
|
||||
default n
|
||||
help
|
||||
|
@ -1,7 +1,6 @@
|
||||
#
|
||||
# SCSI Device Handler
|
||||
#
|
||||
obj-$(CONFIG_SCSI_DH) += scsi_dh.o
|
||||
obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
|
||||
obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
|
||||
obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o
|
||||
|
@ -1,621 +0,0 @@
|
||||
/*
|
||||
* SCSI device handler infrastruture.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright IBM Corporation, 2007
|
||||
* Authors:
|
||||
* Chandra Seetharaman <sekharan@us.ibm.com>
|
||||
* Mike Anderson <andmike@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
#include "../scsi_priv.h"
|
||||
|
||||
static DEFINE_SPINLOCK(list_lock);
|
||||
static LIST_HEAD(scsi_dh_list);
|
||||
|
||||
static struct scsi_device_handler *get_device_handler(const char *name)
|
||||
{
|
||||
struct scsi_device_handler *tmp, *found = NULL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
||||
if (!strncmp(tmp->name, name, strlen(tmp->name))) {
|
||||
found = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_handler_match_function - Match a device handler to a device
|
||||
* @sdev - SCSI device to be tested
|
||||
*
|
||||
* Tests @sdev against the match function of all registered device_handler.
|
||||
* Returns the found device handler or NULL if not found.
|
||||
*/
|
||||
static struct scsi_device_handler *
|
||||
device_handler_match_function(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_device_handler *tmp_dh, *found_dh = NULL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
|
||||
if (tmp_dh->match && tmp_dh->match(sdev)) {
|
||||
found_dh = tmp_dh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
return found_dh;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_handler_match - Attach a device handler to a device
|
||||
* @scsi_dh - The device handler to match against or NULL
|
||||
* @sdev - SCSI device to be tested against @scsi_dh
|
||||
*
|
||||
* Tests @sdev against the device handler @scsi_dh or against
|
||||
* all registered device_handler if @scsi_dh == NULL.
|
||||
* Returns the found device handler or NULL if not found.
|
||||
*/
|
||||
static struct scsi_device_handler *
|
||||
device_handler_match(struct scsi_device_handler *scsi_dh,
|
||||
struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_device_handler *found_dh;
|
||||
|
||||
found_dh = device_handler_match_function(sdev);
|
||||
|
||||
if (scsi_dh && found_dh != scsi_dh)
|
||||
found_dh = NULL;
|
||||
|
||||
return found_dh;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_attach - Attach a device handler to a device
|
||||
* @sdev - SCSI device the device handler should attach to
|
||||
* @scsi_dh - The device handler to attach
|
||||
*/
|
||||
static int scsi_dh_handler_attach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
struct scsi_dh_data *d;
|
||||
|
||||
if (sdev->scsi_dh_data) {
|
||||
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
|
||||
return -EBUSY;
|
||||
|
||||
kref_get(&sdev->scsi_dh_data->kref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!try_module_get(scsi_dh->module))
|
||||
return -EINVAL;
|
||||
|
||||
d = scsi_dh->attach(sdev);
|
||||
if (IS_ERR(d)) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
|
||||
scsi_dh->name, PTR_ERR(d));
|
||||
module_put(scsi_dh->module);
|
||||
return PTR_ERR(d);
|
||||
}
|
||||
|
||||
d->scsi_dh = scsi_dh;
|
||||
kref_init(&d->kref);
|
||||
d->sdev = sdev;
|
||||
|
||||
spin_lock_irq(sdev->request_queue->queue_lock);
|
||||
sdev->scsi_dh_data = d;
|
||||
spin_unlock_irq(sdev->request_queue->queue_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __detach_handler (struct kref *kref)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data =
|
||||
container_of(kref, struct scsi_dh_data, kref);
|
||||
struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
|
||||
struct scsi_device *sdev = scsi_dh_data->sdev;
|
||||
|
||||
scsi_dh->detach(sdev);
|
||||
|
||||
spin_lock_irq(sdev->request_queue->queue_lock);
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irq(sdev->request_queue->queue_lock);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
|
||||
module_put(scsi_dh->module);
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_detach - Detach a device handler from a device
|
||||
* @sdev - SCSI device the device handler should be detached from
|
||||
* @scsi_dh - Device handler to be detached
|
||||
*
|
||||
* Detach from a device handler. If a device handler is specified,
|
||||
* only detach if the currently attached handler matches @scsi_dh.
|
||||
*/
|
||||
static void scsi_dh_handler_detach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
if (!sdev->scsi_dh_data)
|
||||
return;
|
||||
|
||||
if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
|
||||
return;
|
||||
|
||||
if (!scsi_dh)
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
|
||||
if (scsi_dh)
|
||||
kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for sysfs attribute 'dh_state'
|
||||
*/
|
||||
static ssize_t
|
||||
store_dh_state(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (sdev->sdev_state == SDEV_CANCEL ||
|
||||
sdev->sdev_state == SDEV_DEL)
|
||||
return -ENODEV;
|
||||
|
||||
if (!sdev->scsi_dh_data) {
|
||||
/*
|
||||
* Attach to a device handler
|
||||
*/
|
||||
if (!(scsi_dh = get_device_handler(buf)))
|
||||
return err;
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
} else {
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
if (!strncmp(buf, "detach", 6)) {
|
||||
/*
|
||||
* Detach from a device handler
|
||||
*/
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
err = 0;
|
||||
} else if (!strncmp(buf, "activate", 8)) {
|
||||
/*
|
||||
* Activate a device handler
|
||||
*/
|
||||
if (scsi_dh->activate)
|
||||
err = scsi_dh->activate(sdev, NULL, NULL);
|
||||
else
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err<0?err:count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
|
||||
if (!sdev->scsi_dh_data)
|
||||
return snprintf(buf, 20, "detached\n");
|
||||
|
||||
return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
|
||||
}
|
||||
|
||||
static struct device_attribute scsi_dh_state_attr =
|
||||
__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
|
||||
store_dh_state);
|
||||
|
||||
/*
|
||||
* scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
|
||||
*/
|
||||
static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
int err;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
err = device_create_file(&sdev->sdev_gendev,
|
||||
&scsi_dh_state_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
|
||||
*/
|
||||
static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
device_remove_file(&sdev->sdev_gendev,
|
||||
&scsi_dh_state_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier - notifier chain callback
|
||||
*/
|
||||
static int scsi_dh_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct scsi_device *sdev;
|
||||
int err = 0;
|
||||
struct scsi_device_handler *devinfo = NULL;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
||||
err = device_create_file(dev, &scsi_dh_state_attr);
|
||||
/* don't care about err */
|
||||
devinfo = device_handler_match(NULL, sdev);
|
||||
if (devinfo)
|
||||
err = scsi_dh_handler_attach(sdev, devinfo);
|
||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
||||
device_remove_file(dev, &scsi_dh_state_attr);
|
||||
scsi_dh_handler_detach(sdev, NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier_add - Callback for scsi_register_device_handler
|
||||
*/
|
||||
static int scsi_dh_notifier_add(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device_handler *scsi_dh = data;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
if (!get_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (device_handler_match(scsi_dh, sdev))
|
||||
scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
|
||||
*/
|
||||
static int scsi_dh_notifier_remove(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device_handler *scsi_dh = data;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
return 0;
|
||||
|
||||
if (!get_device(dev))
|
||||
return 0;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_register_device_handler - register a device handler personality
|
||||
* module.
|
||||
* @scsi_dh - device handler to be registered.
|
||||
*
|
||||
* Returns 0 on success, -EBUSY if handler already registered.
|
||||
*/
|
||||
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
|
||||
if (get_device_handler(scsi_dh->name))
|
||||
return -EBUSY;
|
||||
|
||||
if (!scsi_dh->attach || !scsi_dh->detach)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_add(&scsi_dh->list, &scsi_dh_list);
|
||||
spin_unlock(&list_lock);
|
||||
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
|
||||
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
|
||||
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_register_device_handler);
|
||||
|
||||
/*
|
||||
* scsi_unregister_device_handler - register a device handler personality
|
||||
* module.
|
||||
* @scsi_dh - device handler to be unregistered.
|
||||
*
|
||||
* Returns 0 on success, -ENODEV if handler not registered.
|
||||
*/
|
||||
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
|
||||
if (!get_device_handler(scsi_dh->name))
|
||||
return -ENODEV;
|
||||
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
|
||||
scsi_dh_notifier_remove);
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_del(&scsi_dh->list);
|
||||
spin_unlock(&list_lock);
|
||||
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
|
||||
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
|
||||
|
||||
/*
|
||||
* scsi_dh_activate - activate the path associated with the scsi_device
|
||||
* corresponding to the given request queue.
|
||||
* Returns immediately without waiting for activation to be completed.
|
||||
* @q - Request queue that is associated with the scsi_device to be
|
||||
* activated.
|
||||
* @fn - Function to be called upon completion of the activation.
|
||||
* Function fn is called with data (below) and the error code.
|
||||
* Function fn may be called from the same calling context. So,
|
||||
* do not hold the lock in the caller which may be needed in fn.
|
||||
* @data - data passed to the function fn upon completion.
|
||||
*
|
||||
*/
|
||||
int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh = NULL;
|
||||
struct device *dev = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev) {
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
err = SCSI_DH_NOSYS;
|
||||
if (fn)
|
||||
fn(data, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (sdev->scsi_dh_data)
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
dev = get_device(&sdev->sdev_gendev);
|
||||
if (!scsi_dh || !dev ||
|
||||
sdev->sdev_state == SDEV_CANCEL ||
|
||||
sdev->sdev_state == SDEV_DEL)
|
||||
err = SCSI_DH_NOSYS;
|
||||
if (sdev->sdev_state == SDEV_OFFLINE)
|
||||
err = SCSI_DH_DEV_OFFLINED;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (err) {
|
||||
if (fn)
|
||||
fn(data, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (scsi_dh->activate)
|
||||
err = scsi_dh->activate(sdev, fn, data);
|
||||
out:
|
||||
put_device(dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_activate);
|
||||
|
||||
/*
|
||||
* scsi_dh_set_params - set the parameters for the device as per the
|
||||
* string specified in params.
|
||||
* @q - Request queue that is associated with the scsi_device for
|
||||
* which the parameters to be set.
|
||||
* @params - parameters in the following format
|
||||
* "no_of_params\0param1\0param2\0param3\0...\0"
|
||||
* for example, string for 2 parameters with value 10 and 21
|
||||
* is specified as "2\010\021\0".
|
||||
*/
|
||||
int scsi_dh_set_params(struct request_queue *q, const char *params)
|
||||
{
|
||||
int err = -SCSI_DH_NOSYS;
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (sdev && sdev->scsi_dh_data)
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
|
||||
err = 0;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
err = scsi_dh->set_params(sdev, params);
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_set_params);
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
|
||||
* the given name. FALSE(0) otherwise.
|
||||
* @name - name of the device handler.
|
||||
*/
|
||||
int scsi_dh_handler_exist(const char *name)
|
||||
{
|
||||
return (get_device_handler(name) != NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
|
||||
|
||||
/*
|
||||
* scsi_dh_attach - Attach device handler
|
||||
* @q - Request queue that is associated with the scsi_device
|
||||
* the handler should be attached to
|
||||
* @name - name of the handler to attach
|
||||
*/
|
||||
int scsi_dh_attach(struct request_queue *q, const char *name)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = 0;
|
||||
|
||||
scsi_dh = get_device_handler(name);
|
||||
if (!scsi_dh)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
err = -ENODEV;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (!err) {
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
put_device(&sdev->sdev_gendev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_attach);
|
||||
|
||||
/*
|
||||
* scsi_dh_detach - Detach device handler
|
||||
* @q - Request queue that is associated with the scsi_device
|
||||
* the handler should be detached from
|
||||
*
|
||||
* This function will detach the device handler only
|
||||
* if the sdev is not part of the internal list, ie
|
||||
* if it has been attached manually.
|
||||
*/
|
||||
void scsi_dh_detach(struct request_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
sdev = NULL;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (!sdev)
|
||||
return;
|
||||
|
||||
if (sdev->scsi_dh_data) {
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
scsi_dh_handler_detach(sdev, scsi_dh);
|
||||
}
|
||||
put_device(&sdev->sdev_gendev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_detach);
|
||||
|
||||
/*
|
||||
* scsi_dh_attached_handler_name - Get attached device handler's name
|
||||
* @q - Request queue that is associated with the scsi_device
|
||||
* that may have a device handler attached
|
||||
* @gfp - the GFP mask used in the kmalloc() call when allocating memory
|
||||
*
|
||||
* Returns name of attached handler, NULL if no handler is attached.
|
||||
* Caller must take care to free the returned string.
|
||||
*/
|
||||
const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev;
|
||||
const char *handler_name = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
sdev = NULL;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
if (!sdev)
|
||||
return NULL;
|
||||
|
||||
if (sdev->scsi_dh_data)
|
||||
handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp);
|
||||
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return handler_name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
|
||||
|
||||
static struct notifier_block scsi_dh_nb = {
|
||||
.notifier_call = scsi_dh_notifier
|
||||
};
|
||||
|
||||
static int __init scsi_dh_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
|
||||
|
||||
if (!r)
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, NULL,
|
||||
scsi_dh_sysfs_attr_add);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit scsi_dh_exit(void)
|
||||
{
|
||||
bus_for_each_dev(&scsi_bus_type, NULL, NULL,
|
||||
scsi_dh_sysfs_attr_remove);
|
||||
bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
|
||||
}
|
||||
|
||||
module_init(scsi_dh_init);
|
||||
module_exit(scsi_dh_exit);
|
||||
|
||||
MODULE_DESCRIPTION("SCSI device handler");
|
||||
MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -62,7 +62,6 @@
|
||||
#define ALUA_OPTIMIZE_STPG 1
|
||||
|
||||
struct alua_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
int group_id;
|
||||
int rel_port;
|
||||
int tpgs;
|
||||
@ -86,11 +85,6 @@ struct alua_dh_data {
|
||||
static char print_alua_state(int);
|
||||
static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
|
||||
|
||||
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
|
||||
{
|
||||
return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data);
|
||||
}
|
||||
|
||||
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
|
||||
{
|
||||
if (h->buff && h->buff != h->inq)
|
||||
@ -708,7 +702,7 @@ out:
|
||||
*/
|
||||
static int alua_set_params(struct scsi_device *sdev, const char *params)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
struct alua_dh_data *h = sdev->handler_data;
|
||||
unsigned int optimize = 0, argc;
|
||||
const char *p = params;
|
||||
int result = SCSI_DH_OK;
|
||||
@ -746,7 +740,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than
|
||||
static int alua_activate(struct scsi_device *sdev,
|
||||
activate_complete fn, void *data)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
struct alua_dh_data *h = sdev->handler_data;
|
||||
int err = SCSI_DH_OK;
|
||||
int stpg = 0;
|
||||
|
||||
@ -804,7 +798,7 @@ out:
|
||||
*/
|
||||
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
struct alua_dh_data *h = sdev->handler_data;
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->state == TPGS_STATE_TRANSITIONING)
|
||||
@ -819,23 +813,18 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
|
||||
}
|
||||
|
||||
static bool alua_match(struct scsi_device *sdev)
|
||||
{
|
||||
return (scsi_device_tpgs(sdev) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_bus_attach - Attach device handler
|
||||
* @sdev: device to be attached to
|
||||
*/
|
||||
static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
|
||||
static int alua_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct alua_dh_data *h;
|
||||
int err;
|
||||
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
h->tpgs = TPGS_MODE_UNINITIALIZED;
|
||||
h->state = TPGS_STATE_OPTIMIZED;
|
||||
h->group_id = -1;
|
||||
@ -848,11 +837,11 @@ static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
|
||||
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
|
||||
goto failed;
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME);
|
||||
return &h->dh_data;
|
||||
sdev->handler_data = h;
|
||||
return 0;
|
||||
failed:
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -861,10 +850,11 @@ failed:
|
||||
*/
|
||||
static void alua_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
struct alua_dh_data *h = sdev->handler_data;
|
||||
|
||||
if (h->buff && h->inq != h->buff)
|
||||
kfree(h->buff);
|
||||
sdev->handler_data = NULL;
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
@ -877,7 +867,6 @@ static struct scsi_device_handler alua_dh = {
|
||||
.check_sense = alua_check_sense,
|
||||
.activate = alua_activate,
|
||||
.set_params = alua_set_params,
|
||||
.match = alua_match,
|
||||
};
|
||||
|
||||
static int __init alua_init(void)
|
||||
|
@ -72,7 +72,6 @@ static const char * lun_state[] =
|
||||
};
|
||||
|
||||
struct clariion_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
/*
|
||||
* Flags:
|
||||
* CLARIION_SHORT_TRESPASS
|
||||
@ -114,13 +113,6 @@ struct clariion_dh_data {
|
||||
int current_sp;
|
||||
};
|
||||
|
||||
static inline struct clariion_dh_data
|
||||
*get_clariion_data(struct scsi_device *sdev)
|
||||
{
|
||||
return container_of(sdev->scsi_dh_data, struct clariion_dh_data,
|
||||
dh_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse MODE_SELECT cmd reply.
|
||||
*/
|
||||
@ -450,7 +442,7 @@ static int clariion_check_sense(struct scsi_device *sdev,
|
||||
|
||||
static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct clariion_dh_data *h = get_clariion_data(sdev);
|
||||
struct clariion_dh_data *h = sdev->handler_data;
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->lun_state != CLARIION_LUN_OWNED) {
|
||||
@ -533,7 +525,7 @@ retry:
|
||||
static int clariion_activate(struct scsi_device *sdev,
|
||||
activate_complete fn, void *data)
|
||||
{
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
struct clariion_dh_data *csdev = sdev->handler_data;
|
||||
int result;
|
||||
|
||||
result = clariion_send_inquiry(sdev, csdev);
|
||||
@ -574,7 +566,7 @@ done:
|
||||
*/
|
||||
static int clariion_set_params(struct scsi_device *sdev, const char *params)
|
||||
{
|
||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||
struct clariion_dh_data *csdev = sdev->handler_data;
|
||||
unsigned int hr = 0, st = 0, argc;
|
||||
const char *p = params;
|
||||
int result = SCSI_DH_OK;
|
||||
@ -622,42 +614,14 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} clariion_dev_list[] = {
|
||||
{"DGC", "RAID"},
|
||||
{"DGC", "DISK"},
|
||||
{"DGC", "VRAID"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static bool clariion_match(struct scsi_device *sdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (scsi_device_tpgs(sdev))
|
||||
return false;
|
||||
|
||||
for (i = 0; clariion_dev_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
|
||||
strlen(clariion_dev_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, clariion_dev_list[i].model,
|
||||
strlen(clariion_dev_list[i].model))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
|
||||
static int clariion_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct clariion_dh_data *h;
|
||||
int err;
|
||||
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
h->lun_state = CLARIION_LUN_UNINITIALIZED;
|
||||
h->default_sp = CLARIION_UNBOUND_LU;
|
||||
h->current_sp = CLARIION_UNBOUND_LU;
|
||||
@ -675,18 +639,19 @@ static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
|
||||
CLARIION_NAME, h->current_sp + 'A',
|
||||
h->port, lun_state[h->lun_state],
|
||||
h->default_sp + 'A');
|
||||
return &h->dh_data;
|
||||
|
||||
sdev->handler_data = h;
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void clariion_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct clariion_dh_data *h = get_clariion_data(sdev);
|
||||
|
||||
kfree(h);
|
||||
kfree(sdev->handler_data);
|
||||
sdev->handler_data = NULL;
|
||||
}
|
||||
|
||||
static struct scsi_device_handler clariion_dh = {
|
||||
@ -698,7 +663,6 @@ static struct scsi_device_handler clariion_dh = {
|
||||
.activate = clariion_activate,
|
||||
.prep_fn = clariion_prep_fn,
|
||||
.set_params = clariion_set_params,
|
||||
.match = clariion_match,
|
||||
};
|
||||
|
||||
static int __init clariion_init(void)
|
||||
|
@ -38,7 +38,6 @@
|
||||
#define HP_SW_PATH_PASSIVE 1
|
||||
|
||||
struct hp_sw_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
int path_state;
|
||||
int retries;
|
||||
@ -50,11 +49,6 @@ struct hp_sw_dh_data {
|
||||
|
||||
static int hp_sw_start_stop(struct hp_sw_dh_data *);
|
||||
|
||||
static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
|
||||
{
|
||||
return container_of(sdev->scsi_dh_data, struct hp_sw_dh_data, dh_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* tur_done - Handle TEST UNIT READY return status
|
||||
* @sdev: sdev the command has been sent to
|
||||
@ -267,7 +261,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
|
||||
|
||||
static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
struct hp_sw_dh_data *h = sdev->handler_data;
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->path_state != HP_SW_PATH_ACTIVE) {
|
||||
@ -292,7 +286,7 @@ static int hp_sw_activate(struct scsi_device *sdev,
|
||||
activate_complete fn, void *data)
|
||||
{
|
||||
int ret = SCSI_DH_OK;
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
struct hp_sw_dh_data *h = sdev->handler_data;
|
||||
|
||||
ret = hp_sw_tur(sdev, h);
|
||||
|
||||
@ -311,43 +305,14 @@ static int hp_sw_activate(struct scsi_device *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} hp_sw_dh_data_list[] = {
|
||||
{"COMPAQ", "MSA1000 VOLUME"},
|
||||
{"COMPAQ", "HSV110"},
|
||||
{"HP", "HSV100"},
|
||||
{"DEC", "HSG80"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static bool hp_sw_match(struct scsi_device *sdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (scsi_device_tpgs(sdev))
|
||||
return false;
|
||||
|
||||
for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
|
||||
strlen(hp_sw_dh_data_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, hp_sw_dh_data_list[i].model,
|
||||
strlen(hp_sw_dh_data_list[i].model))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
static int hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct hp_sw_dh_data *h;
|
||||
int ret;
|
||||
|
||||
h = kzalloc(sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
h->path_state = HP_SW_PATH_UNINITIALIZED;
|
||||
h->retries = HP_SW_RETRIES;
|
||||
h->sdev = sdev;
|
||||
@ -359,17 +324,18 @@ static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
|
||||
HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
|
||||
"active":"passive");
|
||||
return &h->dh_data;
|
||||
|
||||
sdev->handler_data = h;
|
||||
return 0;
|
||||
failed:
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void hp_sw_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
|
||||
kfree(h);
|
||||
kfree(sdev->handler_data);
|
||||
sdev->handler_data = NULL;
|
||||
}
|
||||
|
||||
static struct scsi_device_handler hp_sw_dh = {
|
||||
@ -379,7 +345,6 @@ static struct scsi_device_handler hp_sw_dh = {
|
||||
.detach = hp_sw_bus_detach,
|
||||
.activate = hp_sw_activate,
|
||||
.prep_fn = hp_sw_prep_fn,
|
||||
.match = hp_sw_match,
|
||||
};
|
||||
|
||||
static int __init hp_sw_init(void)
|
||||
|
@ -181,7 +181,6 @@ struct c2_inquiry {
|
||||
};
|
||||
|
||||
struct rdac_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
struct rdac_controller *ctlr;
|
||||
#define UNINITIALIZED_LUN (1 << 8)
|
||||
unsigned lun;
|
||||
@ -260,11 +259,6 @@ do { \
|
||||
sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \
|
||||
} while (0);
|
||||
|
||||
static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
|
||||
{
|
||||
return container_of(sdev->scsi_dh_data, struct rdac_dh_data, dh_data);
|
||||
}
|
||||
|
||||
static struct request *get_rdac_req(struct scsi_device *sdev,
|
||||
void *buffer, unsigned buflen, int rw)
|
||||
{
|
||||
@ -544,7 +538,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
|
||||
{
|
||||
struct scsi_sense_hdr sense_hdr;
|
||||
int err = SCSI_DH_IO, ret;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
|
||||
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
|
||||
if (!ret)
|
||||
@ -589,7 +583,7 @@ static void send_mode_select(struct work_struct *work)
|
||||
container_of(work, struct rdac_controller, ms_work);
|
||||
struct request *rq;
|
||||
struct scsi_device *sdev = ctlr->ms_sdev;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
int err, retry_cnt = RDAC_RETRY_COUNT;
|
||||
struct rdac_queue_data *tmp, *qdata;
|
||||
@ -648,7 +642,7 @@ static int queue_mode_select(struct scsi_device *sdev,
|
||||
if (!qdata)
|
||||
return SCSI_DH_RETRY;
|
||||
|
||||
qdata->h = get_rdac_data(sdev);
|
||||
qdata->h = sdev->handler_data;
|
||||
qdata->callback_fn = fn;
|
||||
qdata->callback_data = data;
|
||||
|
||||
@ -667,7 +661,7 @@ static int queue_mode_select(struct scsi_device *sdev,
|
||||
static int rdac_activate(struct scsi_device *sdev,
|
||||
activate_complete fn, void *data)
|
||||
{
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
int err = SCSI_DH_OK;
|
||||
int act = 0;
|
||||
|
||||
@ -702,7 +696,7 @@ done:
|
||||
|
||||
static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
int ret = BLKPREP_OK;
|
||||
|
||||
if (h->state != RDAC_STATE_ACTIVE) {
|
||||
@ -716,7 +710,7 @@ static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
|
||||
static int rdac_check_sense(struct scsi_device *sdev,
|
||||
struct scsi_sense_hdr *sense_hdr)
|
||||
{
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
|
||||
RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, "
|
||||
"I/O returned with sense %02x/%02x/%02x",
|
||||
@ -778,56 +772,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
|
||||
return SCSI_RETURN_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} rdac_dev_list[] = {
|
||||
{"IBM", "1722"},
|
||||
{"IBM", "1724"},
|
||||
{"IBM", "1726"},
|
||||
{"IBM", "1742"},
|
||||
{"IBM", "1745"},
|
||||
{"IBM", "1746"},
|
||||
{"IBM", "1813"},
|
||||
{"IBM", "1814"},
|
||||
{"IBM", "1815"},
|
||||
{"IBM", "1818"},
|
||||
{"IBM", "3526"},
|
||||
{"SGI", "TP9"},
|
||||
{"SGI", "IS"},
|
||||
{"STK", "OPENstorage D280"},
|
||||
{"STK", "FLEXLINE 380"},
|
||||
{"SUN", "CSM"},
|
||||
{"SUN", "LCSM100"},
|
||||
{"SUN", "STK6580_6780"},
|
||||
{"SUN", "SUN_6180"},
|
||||
{"SUN", "ArrayStorage"},
|
||||
{"DELL", "MD3"},
|
||||
{"NETAPP", "INF-01-00"},
|
||||
{"LSI", "INF-01-00"},
|
||||
{"ENGENIO", "INF-01-00"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static bool rdac_match(struct scsi_device *sdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (scsi_device_tpgs(sdev))
|
||||
return false;
|
||||
|
||||
for (i = 0; rdac_dev_list[i].vendor; i++) {
|
||||
if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
|
||||
strlen(rdac_dev_list[i].vendor)) &&
|
||||
!strncmp(sdev->model, rdac_dev_list[i].model,
|
||||
strlen(rdac_dev_list[i].model))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
|
||||
static int rdac_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct rdac_dh_data *h;
|
||||
int err;
|
||||
@ -836,7 +781,7 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
|
||||
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
h->lun = UNINITIALIZED_LUN;
|
||||
h->state = RDAC_STATE_ACTIVE;
|
||||
|
||||
@ -861,7 +806,8 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
|
||||
RDAC_NAME, h->lun, mode[(int)h->mode],
|
||||
lun_state[(int)h->lun_state]);
|
||||
|
||||
return &h->dh_data;
|
||||
sdev->handler_data = h;
|
||||
return 0;
|
||||
|
||||
clean_ctlr:
|
||||
spin_lock(&list_lock);
|
||||
@ -870,12 +816,12 @@ clean_ctlr:
|
||||
|
||||
failed:
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void rdac_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
struct rdac_dh_data *h = sdev->handler_data;
|
||||
|
||||
if (h->ctlr && h->ctlr->ms_queued)
|
||||
flush_workqueue(kmpath_rdacd);
|
||||
@ -884,6 +830,7 @@ static void rdac_bus_detach( struct scsi_device *sdev )
|
||||
if (h->ctlr)
|
||||
kref_put(&h->ctlr->kref, release_controller);
|
||||
spin_unlock(&list_lock);
|
||||
sdev->handler_data = NULL;
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
@ -895,7 +842,6 @@ static struct scsi_device_handler rdac_dh = {
|
||||
.attach = rdac_bus_attach,
|
||||
.detach = rdac_bus_detach,
|
||||
.activate = rdac_activate,
|
||||
.match = rdac_match,
|
||||
};
|
||||
|
||||
static int __init rdac_init(void)
|
||||
|
@ -364,7 +364,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
|
||||
* on the ethertype for the given device
|
||||
*/
|
||||
fcoe->fcoe_packet_type.func = fcoe_rcv;
|
||||
fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
|
||||
fcoe->fcoe_packet_type.type = htons(ETH_P_FCOE);
|
||||
fcoe->fcoe_packet_type.dev = netdev;
|
||||
dev_add_pack(&fcoe->fcoe_packet_type);
|
||||
|
||||
|
@ -4555,7 +4555,7 @@ static ssize_t ipr_store_raw_mode(struct device *dev,
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
res = (struct ipr_resource_entry *)sdev->hostdata;
|
||||
if (res) {
|
||||
if (ioa_cfg->sis64 && ipr_is_af_dasd_device(res)) {
|
||||
if (ipr_is_af_dasd_device(res)) {
|
||||
res->raw_mode = simple_strtoul(buf, NULL, 10);
|
||||
len = strlen(buf);
|
||||
if (res->sdev)
|
||||
@ -6383,9 +6383,13 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
|
||||
(!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE)) {
|
||||
ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
|
||||
}
|
||||
if (res->raw_mode && ipr_is_af_dasd_device(res))
|
||||
if (res->raw_mode && ipr_is_af_dasd_device(res)) {
|
||||
ioarcb->cmd_pkt.request_type = IPR_RQTYPE_PIPE;
|
||||
|
||||
if (scsi_cmd->underflow == 0)
|
||||
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
|
||||
}
|
||||
|
||||
if (ioa_cfg->sis64)
|
||||
rc = ipr_build_ioadl64(ioa_cfg, ipr_cmd);
|
||||
else
|
||||
|
@ -2284,7 +2284,7 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
|
||||
(struct lpfc_rdp_context *)(mbox->context2);
|
||||
|
||||
if (bf_get(lpfc_mqe_status, &mbox->u.mqe))
|
||||
goto error;
|
||||
goto error_mbuf_free;
|
||||
|
||||
lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2,
|
||||
DMP_SFF_PAGE_A2_SIZE);
|
||||
@ -2299,13 +2299,14 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
|
||||
mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_link_stat;
|
||||
mbox->context2 = (struct lpfc_rdp_context *) rdp_context;
|
||||
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED)
|
||||
goto error;
|
||||
goto error_cmd_free;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
error_mbuf_free:
|
||||
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
||||
kfree(mp);
|
||||
error_cmd_free:
|
||||
lpfc_sli4_mbox_cmd_free(phba, mbox);
|
||||
rdp_context->cmpl(phba, rdp_context, FAILURE);
|
||||
}
|
||||
|
@ -112,9 +112,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* global ioc spinlock to protect controller list on list operations */
|
||||
printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug);
|
||||
spin_lock(&gioc_lock);
|
||||
list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
|
||||
ioc->fwfault_debug = mpt2sas_fwfault_debug;
|
||||
spin_unlock(&gioc_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4437,6 +4440,8 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
||||
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
/* synchronizing freeing resource with pci_access_mutex lock */
|
||||
mutex_lock(&ioc->pci_access_mutex);
|
||||
if (ioc->chip_phys && ioc->chip) {
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
@ -4456,6 +4461,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
mutex_unlock(&ioc->pci_access_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,7 @@
|
||||
* @flags: MPT_TARGET_FLAGS_XXX flags
|
||||
* @deleted: target flaged for deletion
|
||||
* @tm_busy: target is busy with TM request.
|
||||
* @sdev: The sas_device associated with this target
|
||||
*/
|
||||
struct MPT2SAS_TARGET {
|
||||
struct scsi_target *starget;
|
||||
@ -248,6 +249,7 @@ struct MPT2SAS_TARGET {
|
||||
u32 flags;
|
||||
u8 deleted;
|
||||
u8 tm_busy;
|
||||
struct _sas_device *sdev;
|
||||
};
|
||||
|
||||
|
||||
@ -376,8 +378,24 @@ struct _sas_device {
|
||||
u8 phy;
|
||||
u8 responding;
|
||||
u8 pfa_led_on;
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
static inline void sas_device_get(struct _sas_device *s)
|
||||
{
|
||||
kref_get(&s->refcount);
|
||||
}
|
||||
|
||||
static inline void sas_device_free(struct kref *r)
|
||||
{
|
||||
kfree(container_of(r, struct _sas_device, refcount));
|
||||
}
|
||||
|
||||
static inline void sas_device_put(struct _sas_device *s)
|
||||
{
|
||||
kref_put(&s->refcount, sas_device_free);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct _raid_device - raid volume link list
|
||||
* @list: sas device list
|
||||
@ -799,6 +817,12 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
|
||||
* @delayed_tr_list: target reset link list
|
||||
* @delayed_tr_volume_list: volume target reset link list
|
||||
* @@temp_sensors_count: flag to carry the number of temperature sensors
|
||||
* @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
|
||||
* pci resource handling. PCI resource freeing will lead to free
|
||||
* vital hardware/memory resource, which might be in use by cli/sysfs
|
||||
* path functions resulting in Null pointer reference followed by kernel
|
||||
* crash. To avoid the above race condition we use mutex syncrhonization
|
||||
* which ensures the syncrhonization between cli/sysfs_show path
|
||||
*/
|
||||
struct MPT2SAS_ADAPTER {
|
||||
struct list_head list;
|
||||
@ -1015,6 +1039,7 @@ struct MPT2SAS_ADAPTER {
|
||||
u8 mfg_pg10_hide_flag;
|
||||
u8 hide_drives;
|
||||
|
||||
struct mutex pci_access_mutex;
|
||||
};
|
||||
|
||||
typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
@ -1023,6 +1048,17 @@ typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
|
||||
/* base shared API */
|
||||
extern struct list_head mpt2sas_ioc_list;
|
||||
/* spinlock on list operations over IOCs
|
||||
* Case: when multiple warpdrive cards(IOCs) are in use
|
||||
* Each IOC will added to the ioc list stucture on initialization.
|
||||
* Watchdog threads run at regular intervals to check IOC for any
|
||||
* fault conditions which will trigger the dead_ioc thread to
|
||||
* deallocate pci resource, resulting deleting the IOC netry from list,
|
||||
* this deletion need to protected by spinlock to enusre that
|
||||
* ioc removal is syncrhonized, if not synchronized it might lead to
|
||||
* list_del corruption as the ioc list is traversed in cli path
|
||||
*/
|
||||
extern spinlock_t gioc_lock;
|
||||
void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc);
|
||||
void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc);
|
||||
|
||||
@ -1095,11 +1131,12 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *
|
||||
u16 handle);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
|
||||
*ioc, u64 sas_address);
|
||||
struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
|
||||
struct _sas_device *mpt2sas_get_sdev_by_addr(
|
||||
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
|
||||
struct _sas_device *__mpt2sas_get_sdev_by_addr(
|
||||
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
|
||||
|
||||
void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc);
|
||||
|
||||
void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
|
||||
|
||||
/* config shared API */
|
||||
|
@ -427,13 +427,16 @@ static int
|
||||
_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)
|
||||
{
|
||||
struct MPT2SAS_ADAPTER *ioc;
|
||||
|
||||
/* global ioc lock to protect controller on list operations */
|
||||
spin_lock(&gioc_lock);
|
||||
list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
|
||||
if (ioc->id != ioc_number)
|
||||
continue;
|
||||
spin_unlock(&gioc_lock);
|
||||
*iocpp = ioc;
|
||||
return ioc_number;
|
||||
}
|
||||
spin_unlock(&gioc_lock);
|
||||
*iocpp = NULL;
|
||||
return -1;
|
||||
}
|
||||
@ -522,10 +525,15 @@ _ctl_poll(struct file *filep, poll_table *wait)
|
||||
|
||||
poll_wait(filep, &ctl_poll_wait, wait);
|
||||
|
||||
/* global ioc lock to protect controller on list operations */
|
||||
spin_lock(&gioc_lock);
|
||||
list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
|
||||
if (ioc->aen_event_read_flag)
|
||||
if (ioc->aen_event_read_flag) {
|
||||
spin_unlock(&gioc_lock);
|
||||
return POLLIN | POLLRDNORM;
|
||||
}
|
||||
}
|
||||
spin_unlock(&gioc_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2168,16 +2176,23 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
|
||||
|
||||
if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
|
||||
return -ENODEV;
|
||||
/* pci_access_mutex lock acquired by ioctl path */
|
||||
mutex_lock(&ioc->pci_access_mutex);
|
||||
if (ioc->shost_recovery || ioc->pci_error_recovery ||
|
||||
ioc->is_driver_loading)
|
||||
return -EAGAIN;
|
||||
ioc->is_driver_loading || ioc->remove_host) {
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock_pciaccess;
|
||||
}
|
||||
|
||||
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
|
||||
if (state == NON_BLOCKING) {
|
||||
if (!mutex_trylock(&ioc->ctl_cmds.mutex))
|
||||
return -EAGAIN;
|
||||
if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock_pciaccess;
|
||||
}
|
||||
} else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
|
||||
return -ERESTARTSYS;
|
||||
ret = -ERESTARTSYS;
|
||||
goto out_unlock_pciaccess;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
@ -2258,6 +2273,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
|
||||
}
|
||||
|
||||
mutex_unlock(&ioc->ctl_cmds.mutex);
|
||||
out_unlock_pciaccess:
|
||||
mutex_unlock(&ioc->pci_access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2711,6 +2728,12 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
|
||||
"warpdrive\n", ioc->name, __func__);
|
||||
goto out;
|
||||
}
|
||||
/* pci_access_mutex lock acquired by sysfs show path */
|
||||
mutex_lock(&ioc->pci_access_mutex);
|
||||
if (ioc->pci_error_recovery || ioc->remove_host) {
|
||||
mutex_unlock(&ioc->pci_access_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate upto GPIOVal 36 entries */
|
||||
sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
|
||||
@ -2749,6 +2772,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
|
||||
|
||||
out:
|
||||
kfree(io_unit_pg3);
|
||||
mutex_unlock(&ioc->pci_access_mutex);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1323,15 +1323,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
sas_device = __mpt2sas_get_sdev_by_addr(ioc,
|
||||
rphy->identify.sas_address);
|
||||
if (sas_device) {
|
||||
*identifier = sas_device->enclosure_logical_id;
|
||||
rc = 0;
|
||||
sas_device_put(sas_device);
|
||||
} else {
|
||||
*identifier = 0;
|
||||
rc = -ENXIO;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
@ -1351,12 +1353,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
sas_device = __mpt2sas_get_sdev_by_addr(ioc,
|
||||
rphy->identify.sas_address);
|
||||
if (sas_device)
|
||||
if (sas_device) {
|
||||
rc = sas_device->slot;
|
||||
else
|
||||
sas_device_put(sas_device);
|
||||
} else {
|
||||
rc = -ENXIO;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
* scatter/gather formats.
|
||||
* Creation Date: June 21, 2006
|
||||
*
|
||||
* mpi2.h Version: 02.00.31
|
||||
* mpi2.h Version: 02.00.35
|
||||
*
|
||||
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
|
||||
* prefix are for use only on MPI v2.5 products, and must not be used
|
||||
@ -88,6 +88,10 @@
|
||||
* Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
|
||||
* 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT
|
||||
* 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -121,7 +125,7 @@
|
||||
#define MPI2_VERSION_02_05 (0x0205)
|
||||
|
||||
/*Unit and Dev versioning for this MPI header set */
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x1F)
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x23)
|
||||
#define MPI2_HEADER_VERSION_DEV (0x00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Title: MPI Configuration messages and pages
|
||||
* Creation Date: November 10, 2006
|
||||
*
|
||||
* mpi2_cnfg.h Version: 02.00.26
|
||||
* mpi2_cnfg.h Version: 02.00.29
|
||||
*
|
||||
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
|
||||
* prefix are for use only on MPI v2.5 products, and must not be used
|
||||
@ -165,6 +165,20 @@
|
||||
* match the specification.
|
||||
* 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for
|
||||
* future use.
|
||||
* 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
|
||||
* MPI2_CONFIG_PAGE_MAN_7.
|
||||
* Added EnclosureLevel and ConnectorName fields to
|
||||
* MPI2_CONFIG_PAGE_SAS_DEV_0.
|
||||
* Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
|
||||
* MPI2_CONFIG_PAGE_SAS_DEV_0.
|
||||
* Added EnclosureLevel field to
|
||||
* MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
|
||||
* Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
|
||||
* MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
|
||||
* 01-08-14 02.00.28 Added more defines for the BiosOptions field of
|
||||
* MPI2_CONFIG_PAGE_BIOS_1.
|
||||
* 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
|
||||
* more defines for the BiosOptions field..
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -724,6 +738,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 {
|
||||
#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
|
||||
|
||||
/*defines for the Flags field */
|
||||
#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008)
|
||||
#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
|
||||
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
|
||||
|
||||
@ -1311,7 +1326,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
|
||||
MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */
|
||||
U32 BiosOptions; /*0x04 */
|
||||
U32 IOCSettings; /*0x08 */
|
||||
U32 Reserved1; /*0x0C */
|
||||
U8 SSUTimeout; /*0x0C */
|
||||
U8 Reserved1; /*0x0D */
|
||||
U16 Reserved2; /*0x0E */
|
||||
U32 DeviceSettings; /*0x10 */
|
||||
U16 NumberOfDevices; /*0x14 */
|
||||
U16 UEFIVersion; /*0x16 */
|
||||
@ -1323,9 +1340,24 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
|
||||
*PTR_MPI2_CONFIG_PAGE_BIOS_1,
|
||||
Mpi2BiosPage1_t, *pMpi2BiosPage1_t;
|
||||
|
||||
#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
|
||||
#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
|
||||
|
||||
/*values for BIOS Page 1 BiosOptions field */
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000)
|
||||
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400)
|
||||
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300)
|
||||
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
|
||||
|
||||
@ -2633,9 +2665,9 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 {
|
||||
U8
|
||||
ControlGroup; /*0x2E */
|
||||
U8
|
||||
Reserved1; /*0x2F */
|
||||
EnclosureLevel; /*0x2F */
|
||||
U32
|
||||
Reserved2; /*0x30 */
|
||||
ConnectorName[4]; /*0x30 */
|
||||
U32
|
||||
Reserved3; /*0x34 */
|
||||
} MPI2_CONFIG_PAGE_SAS_DEV_0,
|
||||
@ -2643,7 +2675,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 {
|
||||
Mpi2SasDevicePage0_t,
|
||||
*pMpi2SasDevicePage0_t;
|
||||
|
||||
#define MPI2_SASDEVICE0_PAGEVERSION (0x08)
|
||||
#define MPI2_SASDEVICE0_PAGEVERSION (0x09)
|
||||
|
||||
/*values for SAS Device Page 0 AccessStatus field */
|
||||
#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
|
||||
@ -2683,6 +2715,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 {
|
||||
#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
|
||||
#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
|
||||
#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
|
||||
#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
|
||||
#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
|
||||
|
||||
|
||||
@ -3019,8 +3052,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 {
|
||||
NumSlots; /*0x18 */
|
||||
U16
|
||||
StartSlot; /*0x1A */
|
||||
U16
|
||||
U8
|
||||
Reserved2; /*0x1C */
|
||||
U8
|
||||
EnclosureLevel; /*0x1D */
|
||||
U16
|
||||
SEPDevHandle; /*0x1E */
|
||||
U32
|
||||
@ -3031,9 +3066,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 {
|
||||
*PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
|
||||
Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t;
|
||||
|
||||
#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03)
|
||||
#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
|
||||
|
||||
/*values for SAS Enclosure Page 0 Flags field */
|
||||
#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
|
||||
#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F)
|
||||
#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
|
||||
#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
|
||||
* Creation Date: October 11, 2006
|
||||
*
|
||||
* mpi2_ioc.h Version: 02.00.23
|
||||
* mpi2_ioc.h Version: 02.00.24
|
||||
*
|
||||
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
|
||||
* prefix are for use only on MPI v2.5 products, and must not be used
|
||||
@ -132,6 +132,7 @@
|
||||
* Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
|
||||
* Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
|
||||
* Added Encrypted Hash Extended Image.
|
||||
* 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -1598,6 +1599,7 @@ Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t;
|
||||
/* values for HashImageType */
|
||||
#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00)
|
||||
#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01)
|
||||
#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02)
|
||||
|
||||
/* values for HashAlgorithm */
|
||||
#define MPI25_HASH_ALGORITHM_UNUSED (0x00)
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Title: MPI diagnostic tool structures and definitions
|
||||
* Creation Date: March 26, 2007
|
||||
*
|
||||
* mpi2_tool.h Version: 02.00.11
|
||||
* mpi2_tool.h Version: 02.00.12
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
@ -33,6 +33,7 @@
|
||||
* 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
|
||||
* it uses MPI Chain SGE as well as MPI Simple SGE.
|
||||
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
|
||||
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -100,6 +101,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST {
|
||||
#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
|
||||
#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
|
||||
|
@ -83,10 +83,10 @@ static int msix_disable = -1;
|
||||
module_param(msix_disable, int, 0);
|
||||
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
|
||||
|
||||
static int max_msix_vectors = 8;
|
||||
static int max_msix_vectors = -1;
|
||||
module_param(max_msix_vectors, int, 0);
|
||||
MODULE_PARM_DESC(max_msix_vectors,
|
||||
" max msix vectors - (default=8)");
|
||||
" max msix vectors");
|
||||
|
||||
static int mpt3sas_fwfault_debug;
|
||||
MODULE_PARM_DESC(mpt3sas_fwfault_debug,
|
||||
@ -1009,8 +1009,30 @@ _base_interrupt(int irq, void *bus_id)
|
||||
}
|
||||
|
||||
wmb();
|
||||
writel(reply_q->reply_post_host_index | (msix_index <<
|
||||
MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex);
|
||||
|
||||
/* Update Reply Post Host Index.
|
||||
* For those HBA's which support combined reply queue feature
|
||||
* 1. Get the correct Supplemental Reply Post Host Index Register.
|
||||
* i.e. (msix_index / 8)th entry from Supplemental Reply Post Host
|
||||
* Index Register address bank i.e replyPostRegisterIndex[],
|
||||
* 2. Then update this register with new reply host index value
|
||||
* in ReplyPostIndex field and the MSIxIndex field with
|
||||
* msix_index value reduced to a value between 0 and 7,
|
||||
* using a modulo 8 operation. Since each Supplemental Reply Post
|
||||
* Host Index Register supports 8 MSI-X vectors.
|
||||
*
|
||||
* For other HBA's just update the Reply Post Host Index register with
|
||||
* new reply host index value in ReplyPostIndex Field and msix_index
|
||||
* value in MSIxIndex field.
|
||||
*/
|
||||
if (ioc->msix96_vector)
|
||||
writel(reply_q->reply_post_host_index | ((msix_index & 7) <<
|
||||
MPI2_RPHI_MSIX_INDEX_SHIFT),
|
||||
ioc->replyPostRegisterIndex[msix_index/8]);
|
||||
else
|
||||
writel(reply_q->reply_post_host_index | (msix_index <<
|
||||
MPI2_RPHI_MSIX_INDEX_SHIFT),
|
||||
&ioc->chip->ReplyPostHostIndex);
|
||||
atomic_dec(&reply_q->busy);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -1338,7 +1360,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc,
|
||||
|
||||
sg_scmd = scsi_sglist(scmd);
|
||||
sges_left = scsi_dma_map(scmd);
|
||||
if (!sges_left) {
|
||||
if (sges_left < 0) {
|
||||
sdev_printk(KERN_ERR, scmd->device,
|
||||
"pci_map_sg failed: request for %d bytes!\n",
|
||||
scsi_bufflen(scmd));
|
||||
@ -1407,7 +1429,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc,
|
||||
fill_in_last_segment:
|
||||
|
||||
/* fill the last segment */
|
||||
while (sges_left) {
|
||||
while (sges_left > 0) {
|
||||
if (sges_left == 1)
|
||||
_base_add_sg_single_ieee(sg_local,
|
||||
simple_sgl_flags_last, 0, sg_dma_len(sg_scmd),
|
||||
@ -1560,8 +1582,6 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
|
||||
pci_read_config_word(ioc->pdev, base + 2, &message_control);
|
||||
ioc->msix_vector_count = (message_control & 0x3FF) + 1;
|
||||
if (ioc->msix_vector_count > 8)
|
||||
ioc->msix_vector_count = 8;
|
||||
dinitprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"msix is supported, vector_count(%d)\n",
|
||||
ioc->name, ioc->msix_vector_count));
|
||||
@ -1792,6 +1812,36 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_base_unmap_resources - free controller resources
|
||||
* @ioc: per adapter object
|
||||
*/
|
||||
void
|
||||
mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
struct pci_dev *pdev = ioc->pdev;
|
||||
|
||||
dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n",
|
||||
ioc->name, __func__));
|
||||
|
||||
_base_free_irq(ioc);
|
||||
_base_disable_msix(ioc);
|
||||
|
||||
if (ioc->msix96_vector)
|
||||
kfree(ioc->replyPostRegisterIndex);
|
||||
|
||||
if (ioc->chip_phys) {
|
||||
iounmap(ioc->chip);
|
||||
ioc->chip_phys = 0;
|
||||
}
|
||||
|
||||
if (pci_is_enabled(pdev)) {
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_base_map_resources - map in controller resources (io/irq/memap)
|
||||
* @ioc: per adapter object
|
||||
@ -1882,6 +1932,36 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
if (r)
|
||||
goto out_fail;
|
||||
|
||||
/* Use the Combined reply queue feature only for SAS3 C0 & higher
|
||||
* revision HBAs and also only when reply queue count is greater than 8
|
||||
*/
|
||||
if (ioc->msix96_vector && ioc->reply_queue_count > 8) {
|
||||
/* Determine the Supplemental Reply Post Host Index Registers
|
||||
* Addresse. Supplemental Reply Post Host Index Registers
|
||||
* starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and
|
||||
* each register is at offset bytes of
|
||||
* MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one.
|
||||
*/
|
||||
ioc->replyPostRegisterIndex = kcalloc(
|
||||
MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT,
|
||||
sizeof(resource_size_t *), GFP_KERNEL);
|
||||
if (!ioc->replyPostRegisterIndex) {
|
||||
dfailprintk(ioc, printk(MPT3SAS_FMT
|
||||
"allocation for reply Post Register Index failed!!!\n",
|
||||
ioc->name));
|
||||
r = -ENOMEM;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT; i++) {
|
||||
ioc->replyPostRegisterIndex[i] = (resource_size_t *)
|
||||
((u8 *)&ioc->chip->Doorbell +
|
||||
MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET +
|
||||
(i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET));
|
||||
}
|
||||
} else
|
||||
ioc->msix96_vector = 0;
|
||||
|
||||
list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
|
||||
pr_info(MPT3SAS_FMT "%s: IRQ %d\n",
|
||||
reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
|
||||
@ -1897,12 +1977,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
if (ioc->chip_phys)
|
||||
iounmap(ioc->chip);
|
||||
ioc->chip_phys = 0;
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
mpt3sas_base_unmap_resources(ioc);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -2291,6 +2366,99 @@ _base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* _base_display_dell_branding - Display branding string
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* Return nothing.
|
||||
*/
|
||||
static void
|
||||
_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL)
|
||||
return;
|
||||
|
||||
switch (ioc->pdev->device) {
|
||||
case MPI25_MFGPAGE_DEVID_SAS3008:
|
||||
switch (ioc->pdev->subsystem_device) {
|
||||
case MPT3SAS_DELL_12G_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_DELL_12G_HBA_BRANDING);
|
||||
break;
|
||||
default:
|
||||
pr_info(MPT3SAS_FMT
|
||||
"Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
|
||||
ioc->pdev->subsystem_device);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_info(MPT3SAS_FMT
|
||||
"Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
|
||||
ioc->pdev->subsystem_device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_display_cisco_branding - Display branding string
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* Return nothing.
|
||||
*/
|
||||
static void
|
||||
_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO)
|
||||
return;
|
||||
|
||||
switch (ioc->pdev->device) {
|
||||
case MPI25_MFGPAGE_DEVID_SAS3008:
|
||||
switch (ioc->pdev->subsystem_device) {
|
||||
case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
|
||||
break;
|
||||
case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
|
||||
break;
|
||||
case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
|
||||
break;
|
||||
default:
|
||||
pr_info(MPT3SAS_FMT
|
||||
"Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
|
||||
ioc->name, ioc->pdev->subsystem_device);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MPI25_MFGPAGE_DEVID_SAS3108_1:
|
||||
switch (ioc->pdev->subsystem_device) {
|
||||
case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
|
||||
break;
|
||||
case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
|
||||
pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING);
|
||||
break;
|
||||
default:
|
||||
pr_info(MPT3SAS_FMT
|
||||
"Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
|
||||
ioc->name, ioc->pdev->subsystem_device);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_info(MPT3SAS_FMT
|
||||
"Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
|
||||
ioc->name, ioc->pdev->subsystem_device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_display_ioc_capabilities - Disply IOC's capabilities.
|
||||
* @ioc: per adapter object
|
||||
@ -2321,6 +2489,8 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
|
||||
bios_version & 0x000000FF);
|
||||
|
||||
_base_display_intel_branding(ioc);
|
||||
_base_display_dell_branding(ioc);
|
||||
_base_display_cisco_branding(ioc);
|
||||
|
||||
pr_info(MPT3SAS_FMT "Protocol=(", ioc->name);
|
||||
|
||||
@ -3138,6 +3308,9 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
|
||||
*
|
||||
* Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
|
||||
*/
|
||||
static int
|
||||
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag);
|
||||
|
||||
static int
|
||||
_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
|
||||
int sleep_flag)
|
||||
@ -3680,6 +3853,64 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL
|
||||
* @ioc: per adapter object
|
||||
* @timeout:
|
||||
* @sleep_flag: CAN_SLEEP or NO_SLEEP
|
||||
*
|
||||
* Returns 0 for success, non-zero for failure.
|
||||
*/
|
||||
static int
|
||||
_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout,
|
||||
int sleep_flag)
|
||||
{
|
||||
u32 ioc_state;
|
||||
int rc;
|
||||
|
||||
dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
if (ioc->pci_error_recovery) {
|
||||
dfailprintk(ioc, printk(MPT3SAS_FMT
|
||||
"%s: host in pci error recovery\n", ioc->name, __func__));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
|
||||
dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n",
|
||||
ioc->name, __func__, ioc_state));
|
||||
|
||||
if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) ||
|
||||
(ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
|
||||
return 0;
|
||||
|
||||
if (ioc_state & MPI2_DOORBELL_USED) {
|
||||
dhsprintk(ioc, printk(MPT3SAS_FMT
|
||||
"unexpected doorbell active!\n", ioc->name));
|
||||
goto issue_diag_reset;
|
||||
}
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
goto issue_diag_reset;
|
||||
}
|
||||
|
||||
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
|
||||
timeout, sleep_flag);
|
||||
if (ioc_state) {
|
||||
dfailprintk(ioc, printk(MPT3SAS_FMT
|
||||
"%s: failed going to ready state (ioc_state=0x%x)\n",
|
||||
ioc->name, __func__, ioc_state));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
issue_diag_reset:
|
||||
rc = _base_diag_reset(ioc, sleep_flag);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_get_ioc_facts - obtain ioc facts reply and save in ioc
|
||||
* @ioc: per adapter object
|
||||
@ -3698,6 +3929,13 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
|
||||
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
r = _base_wait_for_iocstate(ioc, 10, sleep_flag);
|
||||
if (r) {
|
||||
dfailprintk(ioc, printk(MPT3SAS_FMT
|
||||
"%s: failed getting to correct state\n",
|
||||
ioc->name, __func__));
|
||||
return r;
|
||||
}
|
||||
mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
|
||||
mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
|
||||
memset(&mpi_request, 0, mpi_request_sz);
|
||||
@ -3783,7 +4021,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
|
||||
mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
|
||||
mpi_request.VF_ID = 0; /* TODO */
|
||||
mpi_request.VP_ID = 0;
|
||||
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
|
||||
mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION);
|
||||
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
|
||||
|
||||
if (_base_is_controller_msix_enabled(ioc))
|
||||
@ -4524,8 +4762,15 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
|
||||
|
||||
/* initialize reply post host index */
|
||||
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
||||
writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT,
|
||||
&ioc->chip->ReplyPostHostIndex);
|
||||
if (ioc->msix96_vector)
|
||||
writel((reply_q->msix_index & 7)<<
|
||||
MPI2_RPHI_MSIX_INDEX_SHIFT,
|
||||
ioc->replyPostRegisterIndex[reply_q->msix_index/8]);
|
||||
else
|
||||
writel(reply_q->msix_index <<
|
||||
MPI2_RPHI_MSIX_INDEX_SHIFT,
|
||||
&ioc->chip->ReplyPostHostIndex);
|
||||
|
||||
if (!_base_is_controller_msix_enabled(ioc))
|
||||
goto skip_init_reply_post_host_index;
|
||||
}
|
||||
@ -4564,8 +4809,6 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
|
||||
void
|
||||
mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
struct pci_dev *pdev = ioc->pdev;
|
||||
|
||||
dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
@ -4576,18 +4819,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->shost_recovery = 0;
|
||||
}
|
||||
|
||||
_base_free_irq(ioc);
|
||||
_base_disable_msix(ioc);
|
||||
|
||||
if (ioc->chip_phys && ioc->chip)
|
||||
iounmap(ioc->chip);
|
||||
ioc->chip_phys = 0;
|
||||
|
||||
if (pci_is_enabled(pdev)) {
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
mpt3sas_base_unmap_resources(ioc);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4602,6 +4834,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
int r, i;
|
||||
int cpu_id, last_cpu_id = 0;
|
||||
u8 revision;
|
||||
|
||||
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
@ -4621,6 +4854,20 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
goto out_free_resources;
|
||||
}
|
||||
|
||||
/* Check whether the controller revision is C0 or above.
|
||||
* only C0 and above revision controllers support 96 MSI-X vectors.
|
||||
*/
|
||||
revision = ioc->pdev->revision;
|
||||
|
||||
if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 ||
|
||||
ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 ||
|
||||
ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
|
||||
ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
|
||||
ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
|
||||
ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) &&
|
||||
(revision >= 0x02))
|
||||
ioc->msix96_vector = 1;
|
||||
|
||||
ioc->rdpq_array_enable_assigned = 0;
|
||||
ioc->dma_mask = 0;
|
||||
r = mpt3sas_base_map_resources(ioc);
|
||||
@ -4643,7 +4890,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
|
||||
ioc->build_sg = &_base_build_sg_ieee;
|
||||
ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
|
||||
ioc->mpi25 = 1;
|
||||
ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
|
||||
|
||||
/*
|
||||
|
@ -71,8 +71,8 @@
|
||||
#define MPT3SAS_DRIVER_NAME "mpt3sas"
|
||||
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
|
||||
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
|
||||
#define MPT3SAS_DRIVER_VERSION "04.100.00.00"
|
||||
#define MPT3SAS_MAJOR_VERSION 4
|
||||
#define MPT3SAS_DRIVER_VERSION "09.100.00.00"
|
||||
#define MPT3SAS_MAJOR_VERSION 9
|
||||
#define MPT3SAS_MINOR_VERSION 100
|
||||
#define MPT3SAS_BUILD_VERSION 0
|
||||
#define MPT3SAS_RELEASE_VERSION 00
|
||||
@ -151,6 +151,36 @@
|
||||
#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523
|
||||
#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524
|
||||
|
||||
/*
|
||||
* Dell HBA branding
|
||||
*/
|
||||
#define MPT3SAS_DELL_12G_HBA_BRANDING \
|
||||
"Dell 12Gbps HBA"
|
||||
|
||||
/*
|
||||
* Dell HBA SSDIDs
|
||||
*/
|
||||
#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46
|
||||
|
||||
/*
|
||||
* Cisco HBA branding
|
||||
*/
|
||||
#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \
|
||||
"Cisco 9300-8E 12G SAS HBA"
|
||||
#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \
|
||||
"Cisco 9300-8i 12G SAS HBA"
|
||||
#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \
|
||||
"Cisco 12G Modular SAS Pass through Controller"
|
||||
#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \
|
||||
"UCS C3X60 12G SAS Pass through Controller"
|
||||
/*
|
||||
* Cisco HBA SSSDIDs
|
||||
*/
|
||||
#define MPT3SAS_CISCO_12G_8E_HBA_SSDID 0x14C
|
||||
#define MPT3SAS_CISCO_12G_8I_HBA_SSDID 0x154
|
||||
#define MPT3SAS_CISCO_12G_AVILA_HBA_SSDID 0x155
|
||||
#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID 0x156
|
||||
|
||||
/*
|
||||
* status bits for ioc->diag_buffer_status
|
||||
*/
|
||||
@ -158,6 +188,13 @@
|
||||
#define MPT3_DIAG_BUFFER_IS_RELEASED (0x02)
|
||||
#define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04)
|
||||
|
||||
/*
|
||||
* Combined Reply Queue constants,
|
||||
* There are twelve Supplemental Reply Post Host Index Registers
|
||||
* and each register is at offset 0x10 bytes from the previous one.
|
||||
*/
|
||||
#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT 12
|
||||
#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET (0x10)
|
||||
|
||||
/* OEM Identifiers */
|
||||
#define MFG10_OEM_ID_INVALID (0x00000000)
|
||||
@ -173,6 +210,8 @@
|
||||
#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008)
|
||||
#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010)
|
||||
|
||||
#define VIRTUAL_IO_FAILED_RETRY (0x32010081)
|
||||
|
||||
/* OEM Specific Flags will come from OEM specific header files */
|
||||
struct Mpi2ManufacturingPage10_t {
|
||||
MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
|
||||
@ -294,7 +333,8 @@ struct _internal_cmd {
|
||||
* @responding: used in _scsih_sas_device_mark_responding
|
||||
* @fast_path: fast path feature enable bit
|
||||
* @pfa_led_on: flag for PFA LED status
|
||||
*
|
||||
* @pend_sas_rphy_add: flag to check if device is in sas_rphy_add()
|
||||
* addition routine.
|
||||
*/
|
||||
struct _sas_device {
|
||||
struct list_head list;
|
||||
@ -315,6 +355,9 @@ struct _sas_device {
|
||||
u8 responding;
|
||||
u8 fast_path;
|
||||
u8 pfa_led_on;
|
||||
u8 pend_sas_rphy_add;
|
||||
u8 enclosure_level;
|
||||
u8 connector_name[4];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -728,7 +771,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
|
||||
* is assigned only ones
|
||||
* @reply_queue_count: number of reply queue's
|
||||
* @reply_queue_list: link list contaning the reply queue info
|
||||
* @reply_post_host_index: head index in the pool where FW completes IO
|
||||
* @msix96_vector: 96 MSI-X vector support
|
||||
* @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
|
||||
* @delayed_tr_list: target reset link list
|
||||
* @delayed_tr_volume_list: volume target reset link list
|
||||
* @@temp_sensors_count: flag to carry the number of temperature sensors
|
||||
@ -814,7 +858,6 @@ struct MPT3SAS_ADAPTER {
|
||||
MPT_BUILD_SG_SCMD build_sg_scmd;
|
||||
MPT_BUILD_SG build_sg;
|
||||
MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge;
|
||||
u8 mpi25;
|
||||
u16 sge_size_ieee;
|
||||
|
||||
/* function ptr for MPI sg elements only */
|
||||
@ -937,6 +980,10 @@ struct MPT3SAS_ADAPTER {
|
||||
u8 reply_queue_count;
|
||||
struct list_head reply_queue_list;
|
||||
|
||||
u8 msix96_vector;
|
||||
/* reply post register index */
|
||||
resource_size_t **replyPostRegisterIndex;
|
||||
|
||||
struct list_head delayed_tr_list;
|
||||
struct list_head delayed_tr_volume_list;
|
||||
u8 temp_sensors_count;
|
||||
|
@ -585,6 +585,22 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
|
||||
|
||||
if (!sas_device)
|
||||
return;
|
||||
pr_info(MPT3SAS_FMT
|
||||
"removing handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
ioc->name, sas_device->handle,
|
||||
(unsigned long long) sas_device->sas_address);
|
||||
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
pr_info(MPT3SAS_FMT
|
||||
"removing enclosure logical id(0x%016llx), slot(%d)\n",
|
||||
ioc->name, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot);
|
||||
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
pr_info(MPT3SAS_FMT
|
||||
"removing enclosure level(0x%04x), connector name( %s)\n",
|
||||
ioc->name, sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
list_del(&sas_device->list);
|
||||
@ -663,6 +679,18 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
|
||||
ioc->name, __func__, sas_device->handle,
|
||||
(unsigned long long)sas_device->sas_address));
|
||||
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enclosure logical id(0x%016llx), slot( %d)\n",
|
||||
ioc->name, __func__, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot));
|
||||
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enclosure level(0x%04x), connector name( %s)\n",
|
||||
ioc->name, __func__,
|
||||
sas_device->enclosure_level, sas_device->connector_name));
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
list_add_tail(&sas_device->list, &ioc->sas_device_list);
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
@ -704,6 +732,18 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
|
||||
__func__, sas_device->handle,
|
||||
(unsigned long long)sas_device->sas_address));
|
||||
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enclosure logical id(0x%016llx), slot( %d)\n",
|
||||
ioc->name, __func__, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot));
|
||||
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enclosure level(0x%04x), connector name( %s)\n",
|
||||
ioc->name, __func__, sas_device->enclosure_level,
|
||||
sas_device->connector_name));
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
|
||||
_scsih_determine_boot_device(ioc, sas_device, 0);
|
||||
@ -1772,10 +1812,16 @@ _scsih_slave_configure(struct scsi_device *sdev)
|
||||
"sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
|
||||
ds, handle, (unsigned long long)sas_device->sas_address,
|
||||
sas_device->phy, (unsigned long long)sas_device->device_name);
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: enclosure_logical_id(0x%016llx), slot(%d)\n",
|
||||
ds, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot);
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: enclosure_logical_id(0x%016llx), slot(%d)\n",
|
||||
ds, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot);
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: enclosure level(0x%04x), connector name( %s)\n",
|
||||
ds, sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
|
||||
@ -2189,10 +2235,17 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
|
||||
sas_device->handle,
|
||||
(unsigned long long)sas_device->sas_address,
|
||||
sas_device->phy);
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"enclosure_logical_id(0x%016llx), slot(%d)\n",
|
||||
(unsigned long long)sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"enclosure_logical_id(0x%016llx), slot(%d)\n",
|
||||
(unsigned long long)
|
||||
sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->connector_name)
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"enclosure level(0x%04x),connector name(%s)\n",
|
||||
sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
}
|
||||
@ -2551,6 +2604,75 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_internal_device_block - block the sdev device
|
||||
* @sdev: per device object
|
||||
* @sas_device_priv_data : per device driver private data
|
||||
*
|
||||
* make sure device is blocked without error, if not
|
||||
* print an error
|
||||
*/
|
||||
static void
|
||||
_scsih_internal_device_block(struct scsi_device *sdev,
|
||||
struct MPT3SAS_DEVICE *sas_device_priv_data)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle);
|
||||
sas_device_priv_data->block = 1;
|
||||
|
||||
r = scsi_internal_device_block(sdev);
|
||||
if (r == -EINVAL)
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"device_block failed with return(%d) for handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_internal_device_unblock - unblock the sdev device
|
||||
* @sdev: per device object
|
||||
* @sas_device_priv_data : per device driver private data
|
||||
* make sure device is unblocked without error, if not retry
|
||||
* by blocking and then unblocking
|
||||
*/
|
||||
|
||||
static void
|
||||
_scsih_internal_device_unblock(struct scsi_device *sdev,
|
||||
struct MPT3SAS_DEVICE *sas_device_priv_data)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, "
|
||||
"handle(0x%04x)\n", sas_device_priv_data->sas_target->handle);
|
||||
sas_device_priv_data->block = 0;
|
||||
r = scsi_internal_device_unblock(sdev, SDEV_RUNNING);
|
||||
if (r == -EINVAL) {
|
||||
/* The device has been set to SDEV_RUNNING by SD layer during
|
||||
* device addition but the request queue is still stopped by
|
||||
* our earlier block call. We need to perform a block again
|
||||
* to get the device to SDEV_BLOCK and then to SDEV_RUNNING */
|
||||
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"device_unblock failed with return(%d) for handle(0x%04x) "
|
||||
"performing a block followed by an unblock\n",
|
||||
sas_device_priv_data->sas_target->handle, r);
|
||||
sas_device_priv_data->block = 1;
|
||||
r = scsi_internal_device_block(sdev);
|
||||
if (r)
|
||||
sdev_printk(KERN_WARNING, sdev, "retried device_block "
|
||||
"failed with return(%d) for handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle, r);
|
||||
|
||||
sas_device_priv_data->block = 0;
|
||||
r = scsi_internal_device_unblock(sdev, SDEV_RUNNING);
|
||||
if (r)
|
||||
sdev_printk(KERN_WARNING, sdev, "retried device_unblock"
|
||||
" failed with return(%d) for handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle, r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_ublock_io_all_device - unblock every device
|
||||
* @ioc: per adapter object
|
||||
@ -2570,11 +2692,10 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc)
|
||||
if (!sas_device_priv_data->block)
|
||||
continue;
|
||||
|
||||
sas_device_priv_data->block = 0;
|
||||
dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
|
||||
"device_running, handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle));
|
||||
scsi_internal_device_unblock(sdev, SDEV_RUNNING);
|
||||
_scsih_internal_device_unblock(sdev, sas_device_priv_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2599,10 +2720,9 @@ _scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address)
|
||||
if (sas_device_priv_data->sas_target->sas_address
|
||||
!= sas_address)
|
||||
continue;
|
||||
if (sas_device_priv_data->block) {
|
||||
sas_device_priv_data->block = 0;
|
||||
scsi_internal_device_unblock(sdev, SDEV_RUNNING);
|
||||
}
|
||||
if (sas_device_priv_data->block)
|
||||
_scsih_internal_device_unblock(sdev,
|
||||
sas_device_priv_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2625,10 +2745,7 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
|
||||
continue;
|
||||
if (sas_device_priv_data->block)
|
||||
continue;
|
||||
sas_device_priv_data->block = 1;
|
||||
scsi_internal_device_block(sdev);
|
||||
sdev_printk(KERN_INFO, sdev, "device_blocked, handle(0x%04x)\n",
|
||||
sas_device_priv_data->sas_target->handle);
|
||||
_scsih_internal_device_block(sdev, sas_device_priv_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2644,6 +2761,11 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
{
|
||||
struct MPT3SAS_DEVICE *sas_device_priv_data;
|
||||
struct scsi_device *sdev;
|
||||
struct _sas_device *sas_device;
|
||||
|
||||
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
|
||||
if (!sas_device)
|
||||
return;
|
||||
|
||||
shost_for_each_device(sdev, ioc->shost) {
|
||||
sas_device_priv_data = sdev->hostdata;
|
||||
@ -2653,10 +2775,9 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
continue;
|
||||
if (sas_device_priv_data->block)
|
||||
continue;
|
||||
sas_device_priv_data->block = 1;
|
||||
scsi_internal_device_block(sdev);
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"device_blocked, handle(0x%04x)\n", handle);
|
||||
if (sas_device->pend_sas_rphy_add)
|
||||
continue;
|
||||
_scsih_internal_device_block(sdev, sas_device_priv_data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2806,6 +2927,18 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
"setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
ioc->name, handle,
|
||||
(unsigned long long)sas_address));
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"setting delete flag:enclosure logical id(0x%016llx),"
|
||||
" slot(%d)\n", ioc->name, (unsigned long long)
|
||||
sas_device->enclosure_logical_id,
|
||||
sas_device->slot));
|
||||
if (sas_device->connector_name)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"setting delete flag: enclosure level(0x%04x),"
|
||||
" connector name( %s)\n", ioc->name,
|
||||
sas_device->enclosure_level,
|
||||
sas_device->connector_name));
|
||||
_scsih_ublock_io_device(ioc, sas_address);
|
||||
sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE;
|
||||
}
|
||||
@ -3821,10 +3954,19 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
|
||||
"\tsas_address(0x%016llx), phy(%d)\n",
|
||||
ioc->name, (unsigned long long)
|
||||
sas_device->sas_address, sas_device->phy);
|
||||
pr_warn(MPT3SAS_FMT
|
||||
"\tenclosure_logical_id(0x%016llx), slot(%d)\n",
|
||||
ioc->name, (unsigned long long)
|
||||
sas_device->enclosure_logical_id, sas_device->slot);
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
pr_warn(MPT3SAS_FMT
|
||||
"\tenclosure_logical_id(0x%016llx),"
|
||||
"slot(%d)\n", ioc->name,
|
||||
(unsigned long long)
|
||||
sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->connector_name[0])
|
||||
pr_warn(MPT3SAS_FMT
|
||||
"\tenclosure level(0x%04x),"
|
||||
" connector name( %s)\n", ioc->name,
|
||||
sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
}
|
||||
@ -3999,7 +4141,16 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
return;
|
||||
}
|
||||
starget_printk(KERN_WARNING, starget, "predicted fault\n");
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
starget_printk(KERN_INFO, starget, "predicted fault, "
|
||||
"enclosure logical id(0x%016llx), slot(%d)\n",
|
||||
(unsigned long long)sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
starget_printk(KERN_WARNING, starget, "predicted fault, "
|
||||
"enclosure level(0x%04x), connector name( %s)\n",
|
||||
sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
|
||||
if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
|
||||
@ -4119,8 +4270,15 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
|
||||
_scsih_smart_predicted_fault(ioc,
|
||||
le16_to_cpu(mpi_reply->DevHandle));
|
||||
mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
|
||||
if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
|
||||
((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
|
||||
(scmd->sense_buffer[2] == MEDIUM_ERROR) ||
|
||||
(scmd->sense_buffer[2] == HARDWARE_ERROR)))
|
||||
_scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid);
|
||||
#endif
|
||||
}
|
||||
switch (ioc_status) {
|
||||
case MPI2_IOCSTATUS_BUSY:
|
||||
case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
|
||||
@ -4146,6 +4304,9 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
|
||||
scmd->device->expecting_cc_ua = 1;
|
||||
}
|
||||
break;
|
||||
} else if (log_info == VIRTUAL_IO_FAILED_RETRY) {
|
||||
scmd->result = DID_RESET << 16;
|
||||
break;
|
||||
}
|
||||
scmd->result = DID_SOFT_ERROR << 16;
|
||||
break;
|
||||
@ -4788,6 +4949,16 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
|
||||
sas_device->handle, handle);
|
||||
sas_target_priv_data->handle = handle;
|
||||
sas_device->handle = handle;
|
||||
if (sas_device_pg0.Flags &
|
||||
MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
|
||||
sas_device->enclosure_level =
|
||||
le16_to_cpu(sas_device_pg0.EnclosureLevel);
|
||||
memcpy(&sas_device->connector_name[0],
|
||||
&sas_device_pg0.ConnectorName[0], 4);
|
||||
} else {
|
||||
sas_device->enclosure_level = 0;
|
||||
sas_device->connector_name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* check if device is present */
|
||||
@ -4894,14 +5065,24 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
sas_device->enclosure_handle =
|
||||
le16_to_cpu(sas_device_pg0.EnclosureHandle);
|
||||
sas_device->slot =
|
||||
le16_to_cpu(sas_device_pg0.Slot);
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
sas_device->slot =
|
||||
le16_to_cpu(sas_device_pg0.Slot);
|
||||
sas_device->device_info = device_info;
|
||||
sas_device->sas_address = sas_address;
|
||||
sas_device->phy = sas_device_pg0.PhyNum;
|
||||
sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) &
|
||||
MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0;
|
||||
|
||||
if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
|
||||
sas_device->enclosure_level =
|
||||
le16_to_cpu(sas_device_pg0.EnclosureLevel);
|
||||
memcpy(&sas_device->connector_name[0],
|
||||
&sas_device_pg0.ConnectorName[0], 4);
|
||||
} else {
|
||||
sas_device->enclosure_level = 0;
|
||||
sas_device->connector_name[0] = '\0';
|
||||
}
|
||||
/* get enclosure_logical_id */
|
||||
if (sas_device->enclosure_handle && !(mpt3sas_config_get_enclosure_pg0(
|
||||
ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
|
||||
@ -4943,6 +5124,18 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
|
||||
ioc->name, __func__,
|
||||
sas_device->handle, (unsigned long long)
|
||||
sas_device->sas_address));
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enter: enclosure logical id(0x%016llx), slot(%d)\n",
|
||||
ioc->name, __func__,
|
||||
(unsigned long long)sas_device->enclosure_logical_id,
|
||||
sas_device->slot));
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: enter: enclosure level(0x%04x), connector name( %s)\n",
|
||||
ioc->name, __func__,
|
||||
sas_device->enclosure_level,
|
||||
sas_device->connector_name));
|
||||
|
||||
if (sas_device->starget && sas_device->starget->hostdata) {
|
||||
sas_target_priv_data = sas_device->starget->hostdata;
|
||||
@ -4959,12 +5152,34 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
|
||||
"removing handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
ioc->name, sas_device->handle,
|
||||
(unsigned long long) sas_device->sas_address);
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
pr_info(MPT3SAS_FMT
|
||||
"removing : enclosure logical id(0x%016llx), slot(%d)\n",
|
||||
ioc->name,
|
||||
(unsigned long long)sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
pr_info(MPT3SAS_FMT
|
||||
"removing enclosure level(0x%04x), connector name( %s)\n",
|
||||
ioc->name, sas_device->enclosure_level,
|
||||
sas_device->connector_name);
|
||||
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
ioc->name, __func__,
|
||||
sas_device->handle, (unsigned long long)
|
||||
sas_device->sas_address));
|
||||
sas_device->handle, (unsigned long long)
|
||||
sas_device->sas_address));
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: exit: enclosure logical id(0x%016llx), slot(%d)\n",
|
||||
ioc->name, __func__,
|
||||
(unsigned long long)sas_device->enclosure_logical_id,
|
||||
sas_device->slot));
|
||||
if (sas_device->connector_name[0] != '\0')
|
||||
dewtprintk(ioc, pr_info(MPT3SAS_FMT
|
||||
"%s: exit: enclosure level(0x%04x), connector name(%s)\n",
|
||||
ioc->name, __func__, sas_device->enclosure_level,
|
||||
sas_device->connector_name));
|
||||
|
||||
kfree(sas_device);
|
||||
}
|
||||
@ -6357,9 +6572,7 @@ _scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc)
|
||||
/**
|
||||
* _scsih_mark_responding_sas_device - mark a sas_devices as responding
|
||||
* @ioc: per adapter object
|
||||
* @sas_address: sas address
|
||||
* @slot: enclosure slot id
|
||||
* @handle: device handle
|
||||
* @sas_device_pg0: SAS Device page 0
|
||||
*
|
||||
* After host reset, find out whether devices are still responding.
|
||||
* Used in _scsih_remove_unresponsive_sas_devices.
|
||||
@ -6367,8 +6580,8 @@ _scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc)
|
||||
* Return nothing.
|
||||
*/
|
||||
static void
|
||||
_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
|
||||
u16 slot, u16 handle)
|
||||
_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2SasDevicePage0_t *sas_device_pg0)
|
||||
{
|
||||
struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
|
||||
struct scsi_target *starget;
|
||||
@ -6377,8 +6590,8 @@ _scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
|
||||
if (sas_device->sas_address == sas_address &&
|
||||
sas_device->slot == slot) {
|
||||
if ((sas_device->sas_address == sas_device_pg0->SASAddress) &&
|
||||
(sas_device->slot == sas_device_pg0->Slot)) {
|
||||
sas_device->responding = 1;
|
||||
starget = sas_device->starget;
|
||||
if (starget && starget->hostdata) {
|
||||
@ -6387,22 +6600,40 @@ _scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
|
||||
sas_target_priv_data->deleted = 0;
|
||||
} else
|
||||
sas_target_priv_data = NULL;
|
||||
if (starget)
|
||||
if (starget) {
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"handle(0x%04x), sas_addr(0x%016llx), "
|
||||
"enclosure logical id(0x%016llx), "
|
||||
"slot(%d)\n", handle,
|
||||
(unsigned long long)sas_device->sas_address,
|
||||
"handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
sas_device_pg0->DevHandle,
|
||||
(unsigned long long)
|
||||
sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
if (sas_device->handle == handle)
|
||||
sas_device->sas_address);
|
||||
|
||||
if (sas_device->enclosure_handle != 0)
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"enclosure logical id(0x%016llx),"
|
||||
" slot(%d)\n",
|
||||
(unsigned long long)
|
||||
sas_device->enclosure_logical_id,
|
||||
sas_device->slot);
|
||||
}
|
||||
if (sas_device_pg0->Flags &
|
||||
MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
|
||||
sas_device->enclosure_level =
|
||||
le16_to_cpu(sas_device_pg0->EnclosureLevel);
|
||||
memcpy(&sas_device->connector_name[0],
|
||||
&sas_device_pg0->ConnectorName[0], 4);
|
||||
} else {
|
||||
sas_device->enclosure_level = 0;
|
||||
sas_device->connector_name[0] = '\0';
|
||||
}
|
||||
|
||||
if (sas_device->handle == sas_device_pg0->DevHandle)
|
||||
goto out;
|
||||
pr_info("\thandle changed from(0x%04x)!!!\n",
|
||||
sas_device->handle);
|
||||
sas_device->handle = handle;
|
||||
sas_device->handle = sas_device_pg0->DevHandle;
|
||||
if (sas_target_priv_data)
|
||||
sas_target_priv_data->handle = handle;
|
||||
sas_target_priv_data->handle =
|
||||
sas_device_pg0->DevHandle;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -6441,13 +6672,15 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
break;
|
||||
handle = le16_to_cpu(sas_device_pg0.DevHandle);
|
||||
handle = sas_device_pg0.DevHandle =
|
||||
le16_to_cpu(sas_device_pg0.DevHandle);
|
||||
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
|
||||
if (!(_scsih_is_end_device(device_info)))
|
||||
continue;
|
||||
_scsih_mark_responding_sas_device(ioc,
|
||||
le64_to_cpu(sas_device_pg0.SASAddress),
|
||||
le16_to_cpu(sas_device_pg0.Slot), handle);
|
||||
sas_device_pg0.SASAddress =
|
||||
le64_to_cpu(sas_device_pg0.SASAddress);
|
||||
sas_device_pg0.Slot = le16_to_cpu(sas_device_pg0.Slot);
|
||||
_scsih_mark_responding_sas_device(ioc, &sas_device_pg0);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -7854,8 +8087,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
/* event thread */
|
||||
snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
|
||||
"fw_event%d", ioc->id);
|
||||
ioc->firmware_event_thread = create_singlethread_workqueue(
|
||||
ioc->firmware_event_name);
|
||||
ioc->firmware_event_thread = alloc_ordered_workqueue(
|
||||
ioc->firmware_event_name, WQ_MEM_RECLAIM);
|
||||
if (!ioc->firmware_event_thread) {
|
||||
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
|
@ -649,6 +649,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
|
||||
unsigned long flags;
|
||||
struct _sas_node *sas_node;
|
||||
struct sas_rphy *rphy;
|
||||
struct _sas_device *sas_device = NULL;
|
||||
int i;
|
||||
struct sas_port *port;
|
||||
|
||||
@ -731,10 +732,27 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
|
||||
mpt3sas_port->remote_identify.device_type);
|
||||
|
||||
rphy->identify = mpt3sas_port->remote_identify;
|
||||
|
||||
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
|
||||
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
mpt3sas_port->remote_identify.sas_address);
|
||||
if (!sas_device) {
|
||||
dfailprintk(ioc, printk(MPT3SAS_FMT
|
||||
"failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__));
|
||||
goto out_fail;
|
||||
}
|
||||
sas_device->pend_sas_rphy_add = 1;
|
||||
}
|
||||
|
||||
if ((sas_rphy_add(rphy))) {
|
||||
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
}
|
||||
|
||||
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE)
|
||||
sas_device->pend_sas_rphy_add = 0;
|
||||
|
||||
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
|
||||
dev_printk(KERN_INFO, &rphy->dev,
|
||||
"add: handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
@ -1946,7 +1964,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
} else {
|
||||
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
|
||||
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
|
||||
if (!dma_addr_out) {
|
||||
if (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) {
|
||||
pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n",
|
||||
ioc->name, __func__);
|
||||
rc = -ENOMEM;
|
||||
@ -1968,7 +1986,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||
} else {
|
||||
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
|
||||
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
|
||||
if (!dma_addr_in) {
|
||||
if (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) {
|
||||
pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n",
|
||||
ioc->name, __func__);
|
||||
rc = -ENOMEM;
|
||||
|
@ -2642,6 +2642,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
ts->stat = SAS_OPEN_REJECT;
|
||||
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
|
||||
break;
|
||||
default:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("Unknown status 0x%x\n", status));
|
||||
|
@ -2337,6 +2337,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
ts->stat = SAS_OPEN_REJECT;
|
||||
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
|
||||
break;
|
||||
default:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("Unknown status 0x%x\n", status));
|
||||
|
@ -25,6 +25,9 @@
|
||||
* module options to "modprobe scsi_debug num_tgts=2" [20021221]
|
||||
*/
|
||||
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -201,7 +204,6 @@ static const char *scsi_debug_version_date = "20141022";
|
||||
/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
|
||||
* or "peripheral device" addressing (value 0) */
|
||||
#define SAM2_LUN_ADDRESS_METHOD 0
|
||||
#define SAM2_WLUN_REPORT_LUNS 0xc101
|
||||
|
||||
/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
|
||||
* (for response) at one time. Can be reduced by max_queue option. Command
|
||||
@ -698,7 +700,7 @@ static void sdebug_max_tgts_luns(void)
|
||||
else
|
||||
hpnt->max_id = scsi_debug_num_tgts;
|
||||
/* scsi_debug_max_luns; */
|
||||
hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
|
||||
hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
|
||||
}
|
||||
spin_unlock(&sdebug_host_list_lock);
|
||||
}
|
||||
@ -1288,7 +1290,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
|
||||
arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
|
||||
if (! arr)
|
||||
return DID_REQUEUE << 16;
|
||||
have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS);
|
||||
have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
|
||||
if (have_wlun)
|
||||
pq_pdt = 0x1e; /* present, wlun */
|
||||
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
|
||||
@ -1427,12 +1429,11 @@ static int resp_requests(struct scsi_cmnd * scp,
|
||||
unsigned char * sbuff;
|
||||
unsigned char *cmd = scp->cmnd;
|
||||
unsigned char arr[SCSI_SENSE_BUFFERSIZE];
|
||||
bool dsense, want_dsense;
|
||||
bool dsense;
|
||||
int len = 18;
|
||||
|
||||
memset(arr, 0, sizeof(arr));
|
||||
dsense = !!(cmd[1] & 1);
|
||||
want_dsense = dsense || scsi_debug_dsense;
|
||||
sbuff = scp->sense_buffer;
|
||||
if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
|
||||
if (dsense) {
|
||||
@ -2446,8 +2447,7 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
|
||||
__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
|
||||
|
||||
if (sdt->guard_tag != csum) {
|
||||
pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
|
||||
__func__,
|
||||
pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
|
||||
(unsigned long)sector,
|
||||
be16_to_cpu(sdt->guard_tag),
|
||||
be16_to_cpu(csum));
|
||||
@ -2455,14 +2455,14 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
|
||||
}
|
||||
if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
|
||||
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
|
||||
pr_err("%s: REF check failed on sector %lu\n",
|
||||
__func__, (unsigned long)sector);
|
||||
pr_err("REF check failed on sector %lu\n",
|
||||
(unsigned long)sector);
|
||||
return 0x03;
|
||||
}
|
||||
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
|
||||
be32_to_cpu(sdt->ref_tag) != ei_lba) {
|
||||
pr_err("%s: REF check failed on sector %lu\n",
|
||||
__func__, (unsigned long)sector);
|
||||
pr_err("REF check failed on sector %lu\n",
|
||||
(unsigned long)sector);
|
||||
return 0x03;
|
||||
}
|
||||
return 0;
|
||||
@ -2680,7 +2680,7 @@ resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_sector(unsigned char *buf, int len)
|
||||
static void dump_sector(unsigned char *buf, int len)
|
||||
{
|
||||
int i, j, n;
|
||||
|
||||
@ -3365,8 +3365,8 @@ static int resp_report_luns(struct scsi_cmnd * scp,
|
||||
one_lun[i].scsi_lun[1] = lun & 0xff;
|
||||
}
|
||||
if (want_wlun) {
|
||||
one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
|
||||
one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
|
||||
one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
|
||||
one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
|
||||
i++;
|
||||
}
|
||||
alloc_len = (unsigned char *)(one_lun + i) - arr;
|
||||
@ -3449,7 +3449,7 @@ static void sdebug_q_cmd_complete(unsigned long indx)
|
||||
atomic_inc(&sdebug_completions);
|
||||
qa_indx = indx;
|
||||
if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
|
||||
pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
|
||||
pr_err("wild qa_indx=%d\n", qa_indx);
|
||||
return;
|
||||
}
|
||||
spin_lock_irqsave(&queued_arr_lock, iflags);
|
||||
@ -3457,21 +3457,21 @@ static void sdebug_q_cmd_complete(unsigned long indx)
|
||||
scp = sqcp->a_cmnd;
|
||||
if (NULL == scp) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: scp is NULL\n", __func__);
|
||||
pr_err("scp is NULL\n");
|
||||
return;
|
||||
}
|
||||
devip = (struct sdebug_dev_info *)scp->device->hostdata;
|
||||
if (devip)
|
||||
atomic_dec(&devip->num_in_q);
|
||||
else
|
||||
pr_err("%s: devip=NULL\n", __func__);
|
||||
pr_err("devip=NULL\n");
|
||||
if (atomic_read(&retired_max_queue) > 0)
|
||||
retiring = 1;
|
||||
|
||||
sqcp->a_cmnd = NULL;
|
||||
if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: Unexpected completion\n", __func__);
|
||||
pr_err("Unexpected completion\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3481,7 +3481,7 @@ static void sdebug_q_cmd_complete(unsigned long indx)
|
||||
retval = atomic_read(&retired_max_queue);
|
||||
if (qa_indx >= retval) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: index %d too large\n", __func__, retval);
|
||||
pr_err("index %d too large\n", retval);
|
||||
return;
|
||||
}
|
||||
k = find_last_bit(queued_in_use_bm, retval);
|
||||
@ -3509,7 +3509,7 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
|
||||
atomic_inc(&sdebug_completions);
|
||||
qa_indx = sd_hrtp->qa_indx;
|
||||
if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
|
||||
pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
|
||||
pr_err("wild qa_indx=%d\n", qa_indx);
|
||||
goto the_end;
|
||||
}
|
||||
spin_lock_irqsave(&queued_arr_lock, iflags);
|
||||
@ -3517,21 +3517,21 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
|
||||
scp = sqcp->a_cmnd;
|
||||
if (NULL == scp) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: scp is NULL\n", __func__);
|
||||
pr_err("scp is NULL\n");
|
||||
goto the_end;
|
||||
}
|
||||
devip = (struct sdebug_dev_info *)scp->device->hostdata;
|
||||
if (devip)
|
||||
atomic_dec(&devip->num_in_q);
|
||||
else
|
||||
pr_err("%s: devip=NULL\n", __func__);
|
||||
pr_err("devip=NULL\n");
|
||||
if (atomic_read(&retired_max_queue) > 0)
|
||||
retiring = 1;
|
||||
|
||||
sqcp->a_cmnd = NULL;
|
||||
if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: Unexpected completion\n", __func__);
|
||||
pr_err("Unexpected completion\n");
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
@ -3541,7 +3541,7 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
|
||||
retval = atomic_read(&retired_max_queue);
|
||||
if (qa_indx >= retval) {
|
||||
spin_unlock_irqrestore(&queued_arr_lock, iflags);
|
||||
pr_err("%s: index %d too large\n", __func__, retval);
|
||||
pr_err("index %d too large\n", retval);
|
||||
goto the_end;
|
||||
}
|
||||
k = find_last_bit(queued_in_use_bm, retval);
|
||||
@ -3580,7 +3580,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
|
||||
return devip;
|
||||
sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
|
||||
if (!sdbg_host) {
|
||||
pr_err("%s: Host info NULL\n", __func__);
|
||||
pr_err("Host info NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
|
||||
@ -3596,8 +3596,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
|
||||
if (!open_devip) { /* try and make a new one */
|
||||
open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
|
||||
if (!open_devip) {
|
||||
printk(KERN_ERR "%s: out of memory at line %d\n",
|
||||
__func__, __LINE__);
|
||||
pr_err("out of memory at line %d\n", __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -3615,7 +3614,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
|
||||
static int scsi_debug_slave_alloc(struct scsi_device *sdp)
|
||||
{
|
||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
||||
printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
|
||||
pr_info("slave_alloc <%u %u %u %llu>\n",
|
||||
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
|
||||
return 0;
|
||||
@ -3626,7 +3625,7 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
|
||||
struct sdebug_dev_info *devip;
|
||||
|
||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
||||
printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
|
||||
pr_info("slave_configure <%u %u %u %llu>\n",
|
||||
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
|
||||
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
|
||||
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
|
||||
@ -3646,7 +3645,7 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp)
|
||||
(struct sdebug_dev_info *)sdp->hostdata;
|
||||
|
||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
||||
printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
|
||||
pr_info("slave_destroy <%u %u %u %llu>\n",
|
||||
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
|
||||
if (devip) {
|
||||
/* make this slot available for re-use */
|
||||
@ -3897,8 +3896,7 @@ static void __init sdebug_build_parts(unsigned char *ramp,
|
||||
return;
|
||||
if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
|
||||
scsi_debug_num_parts = SDEBUG_MAX_PARTS;
|
||||
pr_warn("%s: reducing partitions to %d\n", __func__,
|
||||
SDEBUG_MAX_PARTS);
|
||||
pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
|
||||
}
|
||||
num_sectors = (int)sdebug_store_sectors;
|
||||
sectors_per_part = (num_sectors - sdebug_sectors_per)
|
||||
@ -3942,14 +3940,20 @@ schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
|
||||
unsigned long iflags;
|
||||
int k, num_in_q, qdepth, inject;
|
||||
struct sdebug_queued_cmd *sqcp = NULL;
|
||||
struct scsi_device *sdp = cmnd->device;
|
||||
struct scsi_device *sdp;
|
||||
|
||||
if (NULL == cmnd || NULL == devip) {
|
||||
pr_warn("%s: called with NULL cmnd or devip pointer\n",
|
||||
__func__);
|
||||
/* this should never happen */
|
||||
if (WARN_ON(!cmnd))
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
if (NULL == devip) {
|
||||
pr_warn("called devip == NULL\n");
|
||||
/* no particularly good error to report back */
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
}
|
||||
|
||||
sdp = cmnd->device;
|
||||
|
||||
if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
|
||||
sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
|
||||
__func__, scsi_result);
|
||||
@ -4383,8 +4387,7 @@ static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
|
||||
|
||||
fake_storep = vmalloc(sz);
|
||||
if (NULL == fake_storep) {
|
||||
pr_err("%s: out of memory, 9\n",
|
||||
__func__);
|
||||
pr_err("out of memory, 9\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(fake_storep, 0, sz);
|
||||
@ -4784,8 +4787,7 @@ static int __init scsi_debug_init(void)
|
||||
atomic_set(&retired_max_queue, 0);
|
||||
|
||||
if (scsi_debug_ndelay >= 1000000000) {
|
||||
pr_warn("%s: ndelay must be less than 1 second, ignored\n",
|
||||
__func__);
|
||||
pr_warn("ndelay must be less than 1 second, ignored\n");
|
||||
scsi_debug_ndelay = 0;
|
||||
} else if (scsi_debug_ndelay > 0)
|
||||
scsi_debug_delay = DELAY_OVERRIDDEN;
|
||||
@ -4797,8 +4799,7 @@ static int __init scsi_debug_init(void)
|
||||
case 4096:
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: invalid sector_size %d\n", __func__,
|
||||
scsi_debug_sector_size);
|
||||
pr_err("invalid sector_size %d\n", scsi_debug_sector_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -4811,29 +4812,28 @@ static int __init scsi_debug_init(void)
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
|
||||
pr_err("dif must be 0, 1, 2 or 3\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_guard > 1) {
|
||||
pr_err("%s: guard must be 0 or 1\n", __func__);
|
||||
pr_err("guard must be 0 or 1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_ato > 1) {
|
||||
pr_err("%s: ato must be 0 or 1\n", __func__);
|
||||
pr_err("ato must be 0 or 1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_physblk_exp > 15) {
|
||||
pr_err("%s: invalid physblk_exp %u\n", __func__,
|
||||
scsi_debug_physblk_exp);
|
||||
pr_err("invalid physblk_exp %u\n", scsi_debug_physblk_exp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (scsi_debug_lowest_aligned > 0x3fff) {
|
||||
pr_err("%s: lowest_aligned too big: %u\n", __func__,
|
||||
scsi_debug_lowest_aligned);
|
||||
pr_err("lowest_aligned too big: %u\n",
|
||||
scsi_debug_lowest_aligned);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -4863,7 +4863,7 @@ static int __init scsi_debug_init(void)
|
||||
if (0 == scsi_debug_fake_rw) {
|
||||
fake_storep = vmalloc(sz);
|
||||
if (NULL == fake_storep) {
|
||||
pr_err("%s: out of memory, 1\n", __func__);
|
||||
pr_err("out of memory, 1\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(fake_storep, 0, sz);
|
||||
@ -4877,11 +4877,10 @@ static int __init scsi_debug_init(void)
|
||||
dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
|
||||
dif_storep = vmalloc(dif_size);
|
||||
|
||||
pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
|
||||
dif_storep);
|
||||
pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
|
||||
|
||||
if (dif_storep == NULL) {
|
||||
pr_err("%s: out of mem. (DIX)\n", __func__);
|
||||
pr_err("out of mem. (DIX)\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_vm;
|
||||
}
|
||||
@ -4903,18 +4902,17 @@ static int __init scsi_debug_init(void)
|
||||
if (scsi_debug_unmap_alignment &&
|
||||
scsi_debug_unmap_granularity <=
|
||||
scsi_debug_unmap_alignment) {
|
||||
pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
|
||||
__func__);
|
||||
pr_err("ERR: unmap_granularity <= unmap_alignment\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
|
||||
map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
|
||||
|
||||
pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
|
||||
pr_info("%lu provisioning blocks\n", map_size);
|
||||
|
||||
if (map_storep == NULL) {
|
||||
pr_err("%s: out of mem. (MAP)\n", __func__);
|
||||
pr_err("out of mem. (MAP)\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_vm;
|
||||
}
|
||||
@ -4928,18 +4926,18 @@ static int __init scsi_debug_init(void)
|
||||
|
||||
pseudo_primary = root_device_register("pseudo_0");
|
||||
if (IS_ERR(pseudo_primary)) {
|
||||
pr_warn("%s: root_device_register() error\n", __func__);
|
||||
pr_warn("root_device_register() error\n");
|
||||
ret = PTR_ERR(pseudo_primary);
|
||||
goto free_vm;
|
||||
}
|
||||
ret = bus_register(&pseudo_lld_bus);
|
||||
if (ret < 0) {
|
||||
pr_warn("%s: bus_register error: %d\n", __func__, ret);
|
||||
pr_warn("bus_register error: %d\n", ret);
|
||||
goto dev_unreg;
|
||||
}
|
||||
ret = driver_register(&sdebug_driverfs_driver);
|
||||
if (ret < 0) {
|
||||
pr_warn("%s: driver_register error: %d\n", __func__, ret);
|
||||
pr_warn("driver_register error: %d\n", ret);
|
||||
goto bus_unreg;
|
||||
}
|
||||
|
||||
@ -4948,16 +4946,14 @@ static int __init scsi_debug_init(void)
|
||||
|
||||
for (k = 0; k < host_to_add; k++) {
|
||||
if (sdebug_add_adapter()) {
|
||||
pr_err("%s: sdebug_add_adapter failed k=%d\n",
|
||||
__func__, k);
|
||||
pr_err("sdebug_add_adapter failed k=%d\n", k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
|
||||
pr_info("%s: built %d host(s)\n", __func__,
|
||||
scsi_debug_add_host);
|
||||
}
|
||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
||||
pr_info("built %d host(s)\n", scsi_debug_add_host);
|
||||
|
||||
return 0;
|
||||
|
||||
bus_unreg:
|
||||
@ -4965,10 +4961,8 @@ bus_unreg:
|
||||
dev_unreg:
|
||||
root_device_unregister(pseudo_primary);
|
||||
free_vm:
|
||||
if (map_storep)
|
||||
vfree(map_storep);
|
||||
if (dif_storep)
|
||||
vfree(dif_storep);
|
||||
vfree(map_storep);
|
||||
vfree(dif_storep);
|
||||
vfree(fake_storep);
|
||||
|
||||
return ret;
|
||||
@ -4986,9 +4980,7 @@ static void __exit scsi_debug_exit(void)
|
||||
bus_unregister(&pseudo_lld_bus);
|
||||
root_device_unregister(pseudo_primary);
|
||||
|
||||
if (dif_storep)
|
||||
vfree(dif_storep);
|
||||
|
||||
vfree(dif_storep);
|
||||
vfree(fake_storep);
|
||||
}
|
||||
|
||||
@ -5012,8 +5004,7 @@ static int sdebug_add_adapter(void)
|
||||
|
||||
sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
|
||||
if (NULL == sdbg_host) {
|
||||
printk(KERN_ERR "%s: out of memory at line %d\n",
|
||||
__func__, __LINE__);
|
||||
pr_err("out of memory at line %d\n", __LINE__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -5023,8 +5014,7 @@ static int sdebug_add_adapter(void)
|
||||
for (k = 0; k < devs_per_host; k++) {
|
||||
sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
|
||||
if (!sdbg_devinfo) {
|
||||
printk(KERN_ERR "%s: out of memory at line %d\n",
|
||||
__func__, __LINE__);
|
||||
pr_err("out of memory at line %d\n", __LINE__);
|
||||
error = -ENOMEM;
|
||||
goto clean;
|
||||
}
|
||||
@ -5178,7 +5168,7 @@ scsi_debug_queuecommand(struct scsi_cmnd *scp)
|
||||
}
|
||||
sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
|
||||
}
|
||||
has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS);
|
||||
has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
|
||||
if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl)
|
||||
return schedule_resp(scp, NULL, errsts_no_connect, 0);
|
||||
|
||||
@ -5338,7 +5328,7 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
|
||||
hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
|
||||
if (NULL == hpnt) {
|
||||
pr_err("%s: scsi_host_alloc failed\n", __func__);
|
||||
pr_err("scsi_host_alloc failed\n");
|
||||
error = -ENODEV;
|
||||
return error;
|
||||
}
|
||||
@ -5349,7 +5339,8 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
hpnt->max_id = scsi_debug_num_tgts + 1;
|
||||
else
|
||||
hpnt->max_id = scsi_debug_num_tgts;
|
||||
hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
|
||||
/* = scsi_debug_max_luns; */
|
||||
hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
|
||||
|
||||
host_prot = 0;
|
||||
|
||||
@ -5381,7 +5372,7 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
|
||||
scsi_host_set_prot(hpnt, host_prot);
|
||||
|
||||
printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
|
||||
pr_info("host protection%s%s%s%s%s%s%s\n",
|
||||
(host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
|
||||
(host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
|
||||
(host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
|
||||
@ -5409,7 +5400,7 @@ static int sdebug_driver_probe(struct device * dev)
|
||||
|
||||
error = scsi_add_host(hpnt, &sdbg_host->dev);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
|
||||
pr_err("scsi_add_host failed\n");
|
||||
error = -ENODEV;
|
||||
scsi_host_put(hpnt);
|
||||
} else
|
||||
@ -5426,8 +5417,7 @@ static int sdebug_driver_remove(struct device * dev)
|
||||
sdbg_host = to_sdebug_host(dev);
|
||||
|
||||
if (!sdbg_host) {
|
||||
printk(KERN_ERR "%s: Unable to locate host info\n",
|
||||
__func__);
|
||||
pr_err("Unable to locate host info\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
437
drivers/scsi/scsi_dh.c
Normal file
437
drivers/scsi/scsi_dh.c
Normal file
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* SCSI device handler infrastruture.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright IBM Corporation, 2007
|
||||
* Authors:
|
||||
* Chandra Seetharaman <sekharan@us.ibm.com>
|
||||
* Mike Anderson <andmike@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
#include "scsi_priv.h"
|
||||
|
||||
static DEFINE_SPINLOCK(list_lock);
|
||||
static LIST_HEAD(scsi_dh_list);
|
||||
|
||||
struct scsi_dh_blist {
|
||||
const char *vendor;
|
||||
const char *model;
|
||||
const char *driver;
|
||||
};
|
||||
|
||||
static const struct scsi_dh_blist scsi_dh_blist[] = {
|
||||
{"DGC", "RAID", "clariion" },
|
||||
{"DGC", "DISK", "clariion" },
|
||||
{"DGC", "VRAID", "clariion" },
|
||||
|
||||
{"COMPAQ", "MSA1000 VOLUME", "hp_sw" },
|
||||
{"COMPAQ", "HSV110", "hp_sw" },
|
||||
{"HP", "HSV100", "hp_sw"},
|
||||
{"DEC", "HSG80", "hp_sw"},
|
||||
|
||||
{"IBM", "1722", "rdac", },
|
||||
{"IBM", "1724", "rdac", },
|
||||
{"IBM", "1726", "rdac", },
|
||||
{"IBM", "1742", "rdac", },
|
||||
{"IBM", "1745", "rdac", },
|
||||
{"IBM", "1746", "rdac", },
|
||||
{"IBM", "1813", "rdac", },
|
||||
{"IBM", "1814", "rdac", },
|
||||
{"IBM", "1815", "rdac", },
|
||||
{"IBM", "1818", "rdac", },
|
||||
{"IBM", "3526", "rdac", },
|
||||
{"SGI", "TP9", "rdac", },
|
||||
{"SGI", "IS", "rdac", },
|
||||
{"STK", "OPENstorage D280", "rdac", },
|
||||
{"STK", "FLEXLINE 380", "rdac", },
|
||||
{"SUN", "CSM", "rdac", },
|
||||
{"SUN", "LCSM100", "rdac", },
|
||||
{"SUN", "STK6580_6780", "rdac", },
|
||||
{"SUN", "SUN_6180", "rdac", },
|
||||
{"SUN", "ArrayStorage", "rdac", },
|
||||
{"DELL", "MD3", "rdac", },
|
||||
{"NETAPP", "INF-01-00", "rdac", },
|
||||
{"LSI", "INF-01-00", "rdac", },
|
||||
{"ENGENIO", "INF-01-00", "rdac", },
|
||||
{NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static const char *
|
||||
scsi_dh_find_driver(struct scsi_device *sdev)
|
||||
{
|
||||
const struct scsi_dh_blist *b;
|
||||
|
||||
if (scsi_device_tpgs(sdev))
|
||||
return "alua";
|
||||
|
||||
for (b = scsi_dh_blist; b->vendor; b++) {
|
||||
if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) &&
|
||||
!strncmp(sdev->model, b->model, strlen(b->model))) {
|
||||
return b->driver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
|
||||
{
|
||||
struct scsi_device_handler *tmp, *found = NULL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
||||
if (!strncmp(tmp->name, name, strlen(tmp->name))) {
|
||||
found = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&list_lock);
|
||||
return found;
|
||||
}
|
||||
|
||||
static struct scsi_device_handler *scsi_dh_lookup(const char *name)
|
||||
{
|
||||
struct scsi_device_handler *dh;
|
||||
|
||||
dh = __scsi_dh_lookup(name);
|
||||
if (!dh) {
|
||||
request_module(name);
|
||||
dh = __scsi_dh_lookup(name);
|
||||
}
|
||||
|
||||
return dh;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_attach - Attach a device handler to a device
|
||||
* @sdev - SCSI device the device handler should attach to
|
||||
* @scsi_dh - The device handler to attach
|
||||
*/
|
||||
static int scsi_dh_handler_attach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!try_module_get(scsi_dh->module))
|
||||
return -EINVAL;
|
||||
|
||||
error = scsi_dh->attach(sdev);
|
||||
if (error) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n",
|
||||
scsi_dh->name, error);
|
||||
module_put(scsi_dh->module);
|
||||
} else
|
||||
sdev->handler = scsi_dh;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_handler_detach - Detach a device handler from a device
|
||||
* @sdev - SCSI device the device handler should be detached from
|
||||
*/
|
||||
static void scsi_dh_handler_detach(struct scsi_device *sdev)
|
||||
{
|
||||
sdev->handler->detach(sdev);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name);
|
||||
module_put(sdev->handler->module);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for sysfs attribute 'dh_state'
|
||||
*/
|
||||
static ssize_t
|
||||
store_dh_state(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (sdev->sdev_state == SDEV_CANCEL ||
|
||||
sdev->sdev_state == SDEV_DEL)
|
||||
return -ENODEV;
|
||||
|
||||
if (!sdev->handler) {
|
||||
/*
|
||||
* Attach to a device handler
|
||||
*/
|
||||
scsi_dh = scsi_dh_lookup(buf);
|
||||
if (!scsi_dh)
|
||||
return err;
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
} else {
|
||||
if (!strncmp(buf, "detach", 6)) {
|
||||
/*
|
||||
* Detach from a device handler
|
||||
*/
|
||||
sdev_printk(KERN_WARNING, sdev,
|
||||
"can't detach handler %s.\n",
|
||||
sdev->handler->name);
|
||||
err = -EINVAL;
|
||||
} else if (!strncmp(buf, "activate", 8)) {
|
||||
/*
|
||||
* Activate a device handler
|
||||
*/
|
||||
if (sdev->handler->activate)
|
||||
err = sdev->handler->activate(sdev, NULL, NULL);
|
||||
else
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err<0?err:count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
|
||||
if (!sdev->handler)
|
||||
return snprintf(buf, 20, "detached\n");
|
||||
|
||||
return snprintf(buf, 20, "%s\n", sdev->handler->name);
|
||||
}
|
||||
|
||||
static struct device_attribute scsi_dh_state_attr =
|
||||
__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
|
||||
store_dh_state);
|
||||
|
||||
int scsi_dh_add_device(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_device_handler *devinfo = NULL;
|
||||
const char *drv;
|
||||
int err;
|
||||
|
||||
err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
drv = scsi_dh_find_driver(sdev);
|
||||
if (drv)
|
||||
devinfo = scsi_dh_lookup(drv);
|
||||
if (devinfo)
|
||||
err = scsi_dh_handler_attach(sdev, devinfo);
|
||||
return err;
|
||||
}
|
||||
|
||||
void scsi_dh_remove_device(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->handler)
|
||||
scsi_dh_handler_detach(sdev);
|
||||
device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_register_device_handler - register a device handler personality
|
||||
* module.
|
||||
* @scsi_dh - device handler to be registered.
|
||||
*
|
||||
* Returns 0 on success, -EBUSY if handler already registered.
|
||||
*/
|
||||
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
if (__scsi_dh_lookup(scsi_dh->name))
|
||||
return -EBUSY;
|
||||
|
||||
if (!scsi_dh->attach || !scsi_dh->detach)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_add(&scsi_dh->list, &scsi_dh_list);
|
||||
spin_unlock(&list_lock);
|
||||
|
||||
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
|
||||
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_register_device_handler);
|
||||
|
||||
/*
|
||||
* scsi_unregister_device_handler - register a device handler personality
|
||||
* module.
|
||||
* @scsi_dh - device handler to be unregistered.
|
||||
*
|
||||
* Returns 0 on success, -ENODEV if handler not registered.
|
||||
*/
|
||||
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
if (!__scsi_dh_lookup(scsi_dh->name))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_del(&scsi_dh->list);
|
||||
spin_unlock(&list_lock);
|
||||
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
|
||||
|
||||
return SCSI_DH_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
|
||||
|
||||
static struct scsi_device *get_sdev_from_queue(struct request_queue *q)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
sdev = q->queuedata;
|
||||
if (!sdev || !get_device(&sdev->sdev_gendev))
|
||||
sdev = NULL;
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
return sdev;
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_dh_activate - activate the path associated with the scsi_device
|
||||
* corresponding to the given request queue.
|
||||
* Returns immediately without waiting for activation to be completed.
|
||||
* @q - Request queue that is associated with the scsi_device to be
|
||||
* activated.
|
||||
* @fn - Function to be called upon completion of the activation.
|
||||
* Function fn is called with data (below) and the error code.
|
||||
* Function fn may be called from the same calling context. So,
|
||||
* do not hold the lock in the caller which may be needed in fn.
|
||||
* @data - data passed to the function fn upon completion.
|
||||
*
|
||||
*/
|
||||
int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
int err = SCSI_DH_NOSYS;
|
||||
|
||||
sdev = get_sdev_from_queue(q);
|
||||
if (!sdev) {
|
||||
if (fn)
|
||||
fn(data, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!sdev->handler)
|
||||
goto out_fn;
|
||||
err = SCSI_DH_NOTCONN;
|
||||
if (sdev->sdev_state == SDEV_CANCEL ||
|
||||
sdev->sdev_state == SDEV_DEL)
|
||||
goto out_fn;
|
||||
|
||||
err = SCSI_DH_DEV_OFFLINED;
|
||||
if (sdev->sdev_state == SDEV_OFFLINE)
|
||||
goto out_fn;
|
||||
|
||||
if (sdev->handler->activate)
|
||||
err = sdev->handler->activate(sdev, fn, data);
|
||||
|
||||
out_put_device:
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return err;
|
||||
|
||||
out_fn:
|
||||
if (fn)
|
||||
fn(data, err);
|
||||
goto out_put_device;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_activate);
|
||||
|
||||
/*
|
||||
* scsi_dh_set_params - set the parameters for the device as per the
|
||||
* string specified in params.
|
||||
* @q - Request queue that is associated with the scsi_device for
|
||||
* which the parameters to be set.
|
||||
* @params - parameters in the following format
|
||||
* "no_of_params\0param1\0param2\0param3\0...\0"
|
||||
* for example, string for 2 parameters with value 10 and 21
|
||||
* is specified as "2\010\021\0".
|
||||
*/
|
||||
int scsi_dh_set_params(struct request_queue *q, const char *params)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
int err = -SCSI_DH_NOSYS;
|
||||
|
||||
sdev = get_sdev_from_queue(q);
|
||||
if (!sdev)
|
||||
return err;
|
||||
|
||||
if (sdev->handler && sdev->handler->set_params)
|
||||
err = sdev->handler->set_params(sdev, params);
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_set_params);
|
||||
|
||||
/*
|
||||
* scsi_dh_attach - Attach device handler
|
||||
* @q - Request queue that is associated with the scsi_device
|
||||
* the handler should be attached to
|
||||
* @name - name of the handler to attach
|
||||
*/
|
||||
int scsi_dh_attach(struct request_queue *q, const char *name)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
int err = 0;
|
||||
|
||||
sdev = get_sdev_from_queue(q);
|
||||
if (!sdev)
|
||||
return -ENODEV;
|
||||
|
||||
scsi_dh = scsi_dh_lookup(name);
|
||||
if (!scsi_dh) {
|
||||
err = -EINVAL;
|
||||
goto out_put_device;
|
||||
}
|
||||
|
||||
if (sdev->handler) {
|
||||
if (sdev->handler != scsi_dh)
|
||||
err = -EBUSY;
|
||||
goto out_put_device;
|
||||
}
|
||||
|
||||
err = scsi_dh_handler_attach(sdev, scsi_dh);
|
||||
|
||||
out_put_device:
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_attach);
|
||||
|
||||
/*
|
||||
* scsi_dh_attached_handler_name - Get attached device handler's name
|
||||
* @q - Request queue that is associated with the scsi_device
|
||||
* that may have a device handler attached
|
||||
* @gfp - the GFP mask used in the kmalloc() call when allocating memory
|
||||
*
|
||||
* Returns name of attached handler, NULL if no handler is attached.
|
||||
* Caller must take care to free the returned string.
|
||||
*/
|
||||
const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
const char *handler_name = NULL;
|
||||
|
||||
sdev = get_sdev_from_queue(q);
|
||||
if (!sdev)
|
||||
return NULL;
|
||||
|
||||
if (sdev->handler)
|
||||
handler_name = kstrdup(sdev->handler->name, gfp);
|
||||
put_device(&sdev->sdev_gendev);
|
||||
return handler_name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
|
@ -36,6 +36,7 @@
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
#include <scsi/sg.h>
|
||||
|
||||
#include "scsi_priv.h"
|
||||
@ -463,11 +464,10 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
|
||||
if (scsi_sense_is_deferred(&sshdr))
|
||||
return NEEDS_RETRY;
|
||||
|
||||
if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh &&
|
||||
sdev->scsi_dh_data->scsi_dh->check_sense) {
|
||||
if (sdev->handler && sdev->handler->check_sense) {
|
||||
int rc;
|
||||
|
||||
rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr);
|
||||
rc = sdev->handler->check_sense(sdev, &sshdr);
|
||||
if (rc != SCSI_RETURN_NOT_HANDLED)
|
||||
return rc;
|
||||
/* handler does not care. Drop down to default handling */
|
||||
@ -2178,8 +2178,17 @@ int scsi_error_handler(void *data)
|
||||
* We never actually get interrupted because kthread_run
|
||||
* disables signal delivery for the created thread.
|
||||
*/
|
||||
while (!kthread_should_stop()) {
|
||||
while (true) {
|
||||
/*
|
||||
* The sequence in kthread_stop() sets the stop flag first
|
||||
* then wakes the process. To avoid missed wakeups, the task
|
||||
* should always be in a non running state before the stop
|
||||
* flag is checked
|
||||
*/
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
|
||||
shost->host_failed != atomic_read(&shost->host_busy)) {
|
||||
SCSI_LOG_ERROR_RECOVERY(1,
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <scsi/scsi_driver.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_dh.h>
|
||||
|
||||
#include <trace/events/scsi.h>
|
||||
|
||||
@ -1248,9 +1249,8 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
|
||||
{
|
||||
struct scsi_cmnd *cmd = req->special;
|
||||
|
||||
if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh
|
||||
&& sdev->scsi_dh_data->scsi_dh->prep_fn)) {
|
||||
int ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req);
|
||||
if (unlikely(sdev->handler && sdev->handler->prep_fn)) {
|
||||
int ret = sdev->handler->prep_fn(sdev, req);
|
||||
if (ret != BLKPREP_OK)
|
||||
return ret;
|
||||
}
|
||||
|
@ -170,6 +170,15 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
|
||||
extern struct async_domain scsi_sd_pm_domain;
|
||||
extern struct async_domain scsi_sd_probe_domain;
|
||||
|
||||
/* scsi_dh.c */
|
||||
#ifdef CONFIG_SCSI_DH
|
||||
int scsi_dh_add_device(struct scsi_device *sdev);
|
||||
void scsi_dh_remove_device(struct scsi_device *sdev);
|
||||
#else
|
||||
static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
|
||||
static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* internal scsi timeout functions: for use by mid-layer and transport
|
||||
* classes.
|
||||
|
@ -1030,11 +1030,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
|
||||
"failed to add device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = scsi_dh_add_device(sdev);
|
||||
if (error) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"failed to add device handler: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
device_enable_async_suspend(&sdev->sdev_dev);
|
||||
error = device_add(&sdev->sdev_dev);
|
||||
if (error) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"failed to add class device: %d\n", error);
|
||||
scsi_dh_remove_device(sdev);
|
||||
device_del(&sdev->sdev_gendev);
|
||||
return error;
|
||||
}
|
||||
@ -1074,6 +1083,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
|
||||
bsg_unregister_queue(sdev->request_queue);
|
||||
device_unregister(&sdev->sdev_dev);
|
||||
transport_remove_device(dev);
|
||||
scsi_dh_remove_device(sdev);
|
||||
device_del(dev);
|
||||
} else
|
||||
put_device(&sdev->sdev_dev);
|
||||
|
@ -1222,13 +1222,6 @@ show_sas_rphy_enclosure_identifier(struct device *dev,
|
||||
u64 identifier;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Only devices behind an expander are supported, because the
|
||||
* enclosure identifier is a SMP feature.
|
||||
*/
|
||||
if (scsi_is_sas_phy_local(phy))
|
||||
return -EINVAL;
|
||||
|
||||
error = i->f->get_enclosure_identifier(rphy, &identifier);
|
||||
if (error)
|
||||
return error;
|
||||
@ -1248,9 +1241,6 @@ show_sas_rphy_bay_identifier(struct device *dev,
|
||||
struct sas_internal *i = to_sas_internal(shost->transportt);
|
||||
int val;
|
||||
|
||||
if (scsi_is_sas_phy_local(phy))
|
||||
return -EINVAL;
|
||||
|
||||
val = i->f->get_bay_identifier(rphy);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
@ -196,34 +196,13 @@ struct scsi_device {
|
||||
struct execute_work ew; /* used to get process context on put */
|
||||
struct work_struct requeue_work;
|
||||
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct scsi_device_handler *handler;
|
||||
void *handler_data;
|
||||
|
||||
enum scsi_device_state sdev_state;
|
||||
unsigned long sdev_data[0];
|
||||
} __attribute__((aligned(sizeof(unsigned long))));
|
||||
|
||||
typedef void (*activate_complete)(void *, int);
|
||||
struct scsi_device_handler {
|
||||
/* Used by the infrastructure */
|
||||
struct list_head list; /* list of scsi_device_handlers */
|
||||
|
||||
/* Filled by the hardware handler */
|
||||
struct module *module;
|
||||
const char *name;
|
||||
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
|
||||
struct scsi_dh_data *(*attach)(struct scsi_device *);
|
||||
void (*detach)(struct scsi_device *);
|
||||
int (*activate)(struct scsi_device *, activate_complete, void *);
|
||||
int (*prep_fn)(struct scsi_device *, struct request *);
|
||||
int (*set_params)(struct scsi_device *, const char *);
|
||||
bool (*match)(struct scsi_device *);
|
||||
};
|
||||
|
||||
struct scsi_dh_data {
|
||||
struct scsi_device_handler *scsi_dh;
|
||||
struct scsi_device *sdev;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
#define to_scsi_device(d) \
|
||||
container_of(d, struct scsi_device, sdev_gendev)
|
||||
#define class_to_sdev(d) \
|
||||
|
@ -55,11 +55,26 @@ enum {
|
||||
SCSI_DH_NOSYS,
|
||||
SCSI_DH_DRIVER_MAX,
|
||||
};
|
||||
#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
|
||||
|
||||
typedef void (*activate_complete)(void *, int);
|
||||
struct scsi_device_handler {
|
||||
/* Used by the infrastructure */
|
||||
struct list_head list; /* list of scsi_device_handlers */
|
||||
|
||||
/* Filled by the hardware handler */
|
||||
struct module *module;
|
||||
const char *name;
|
||||
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
|
||||
int (*attach)(struct scsi_device *);
|
||||
void (*detach)(struct scsi_device *);
|
||||
int (*activate)(struct scsi_device *, activate_complete, void *);
|
||||
int (*prep_fn)(struct scsi_device *, struct request *);
|
||||
int (*set_params)(struct scsi_device *, const char *);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SCSI_DH
|
||||
extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
|
||||
extern int scsi_dh_handler_exist(const char *);
|
||||
extern int scsi_dh_attach(struct request_queue *, const char *);
|
||||
extern void scsi_dh_detach(struct request_queue *);
|
||||
extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t);
|
||||
extern int scsi_dh_set_params(struct request_queue *, const char *);
|
||||
#else
|
||||
@ -69,18 +84,10 @@ static inline int scsi_dh_activate(struct request_queue *req,
|
||||
fn(data, 0);
|
||||
return 0;
|
||||
}
|
||||
static inline int scsi_dh_handler_exist(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int scsi_dh_attach(struct request_queue *req, const char *name)
|
||||
{
|
||||
return SCSI_DH_NOSYS;
|
||||
}
|
||||
static inline void scsi_dh_detach(struct request_queue *q)
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline const char *scsi_dh_attached_handler_name(struct request_queue *q,
|
||||
gfp_t gfp)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user