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:
Linus Torvalds 2015-09-11 18:15:18 -07:00
commit 8e78b7dc93
39 changed files with 1860 additions and 1271 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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);
}
/*

View File

@ -3,7 +3,7 @@
#
menuconfig SCSI_DH
tristate "SCSI Device Handlers"
bool "SCSI Device Handlers"
depends on SCSI
default n
help

View File

@ -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

View File

@ -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");

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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();
/* 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);
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,
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);
/*

View File

@ -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;

View File

@ -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);
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);
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,
(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);
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);
"\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,6 +5065,7 @@ _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);
if (sas_device->enclosure_handle != 0)
sas_device->slot =
le16_to_cpu(sas_device_pg0.Slot);
sas_device->device_info = device_info;
@ -4902,6 +5074,15 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
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));
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)\n",
sas_device_pg0->DevHandle,
(unsigned long long)
sas_device->sas_address);
if (sas_device->enclosure_handle != 0)
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,
" slot(%d)\n",
(unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot);
if (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';
}
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__);

View File

@ -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;

View File

@ -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));

View File

@ -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));

View File

@ -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,28 +4812,27 @@ 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__,
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,9 +4961,7 @@ bus_unreg:
dev_unreg:
root_device_unregister(pseudo_primary);
free_vm:
if (map_storep)
vfree(map_storep);
if (dif_storep)
vfree(dif_storep);
vfree(fake_storep);
@ -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(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
View 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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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) \

View File

@ -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)
{