[SCSI] transport_sas: add SAS management protocol support
The sas transport class attaches one bsg device to every SAS object (host, device, expander, etc). LLDs can define a function to handle SMP requests via sas_function_template::smp_handler. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
Родитель
3ac709c113
Коммит
7aa68e80bd
|
@ -282,7 +282,7 @@ config SCSI_ISCSI_ATTRS
|
||||||
|
|
||||||
config SCSI_SAS_ATTRS
|
config SCSI_SAS_ATTRS
|
||||||
tristate "SAS Transport Attributes"
|
tristate "SAS Transport Attributes"
|
||||||
depends on SCSI
|
depends on SCSI && BLK_DEV_BSG
|
||||||
help
|
help
|
||||||
If you wish to export transport-specific information about
|
If you wish to export transport-specific information about
|
||||||
each attached SAS device to sysfs, say Y.
|
each attached SAS device to sysfs, say Y.
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/bsg.h>
|
||||||
|
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/scsi_device.h>
|
#include <scsi/scsi_device.h>
|
||||||
|
@ -152,6 +154,76 @@ static struct {
|
||||||
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
|
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
|
||||||
sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
|
sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
|
||||||
|
|
||||||
|
static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
|
||||||
|
struct sas_rphy *rphy)
|
||||||
|
{
|
||||||
|
struct request *req;
|
||||||
|
int ret;
|
||||||
|
int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
|
||||||
|
|
||||||
|
while (!blk_queue_plugged(q)) {
|
||||||
|
req = elv_next_request(q);
|
||||||
|
if (!req)
|
||||||
|
break;
|
||||||
|
|
||||||
|
blkdev_dequeue_request(req);
|
||||||
|
|
||||||
|
spin_unlock_irq(q->queue_lock);
|
||||||
|
|
||||||
|
handler = to_sas_internal(shost->transportt)->f->smp_handler;
|
||||||
|
ret = handler(shost, rphy, req);
|
||||||
|
|
||||||
|
spin_lock_irq(q->queue_lock);
|
||||||
|
|
||||||
|
req->end_io(req, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sas_host_smp_request(struct request_queue *q)
|
||||||
|
{
|
||||||
|
sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sas_non_host_smp_request(struct request_queue *q)
|
||||||
|
{
|
||||||
|
struct sas_rphy *rphy = q->queuedata;
|
||||||
|
sas_smp_request(q, rphy_to_shost(rphy), rphy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
||||||
|
char *name)
|
||||||
|
{
|
||||||
|
struct request_queue *q;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!to_sas_internal(shost->transportt)->f->smp_handler) {
|
||||||
|
printk("%s can't handle SMP requests\n", shost->hostt->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rphy)
|
||||||
|
q = blk_init_queue(sas_non_host_smp_request, NULL);
|
||||||
|
else
|
||||||
|
q = blk_init_queue(sas_host_smp_request, NULL);
|
||||||
|
if (!q)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
error = bsg_register_queue(q, name);
|
||||||
|
if (error) {
|
||||||
|
blk_cleanup_queue(q);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rphy)
|
||||||
|
q->queuedata = rphy;
|
||||||
|
else
|
||||||
|
q->queuedata = shost;
|
||||||
|
|
||||||
|
set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SAS host attributes
|
* SAS host attributes
|
||||||
*/
|
*/
|
||||||
|
@ -161,12 +233,19 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
|
||||||
{
|
{
|
||||||
struct Scsi_Host *shost = dev_to_shost(dev);
|
struct Scsi_Host *shost = dev_to_shost(dev);
|
||||||
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
|
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
|
||||||
|
char name[BUS_ID_SIZE];
|
||||||
|
|
||||||
INIT_LIST_HEAD(&sas_host->rphy_list);
|
INIT_LIST_HEAD(&sas_host->rphy_list);
|
||||||
mutex_init(&sas_host->lock);
|
mutex_init(&sas_host->lock);
|
||||||
sas_host->next_target_id = 0;
|
sas_host->next_target_id = 0;
|
||||||
sas_host->next_expander_id = 0;
|
sas_host->next_expander_id = 0;
|
||||||
sas_host->next_port_id = 0;
|
sas_host->next_port_id = 0;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
|
||||||
|
if (sas_bsg_initialize(shost, NULL, name))
|
||||||
|
dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
|
||||||
|
shost->host_no);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,6 +1300,9 @@ struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
|
||||||
sas_rphy_initialize(&rdev->rphy);
|
sas_rphy_initialize(&rdev->rphy);
|
||||||
transport_setup_device(&rdev->rphy.dev);
|
transport_setup_device(&rdev->rphy.dev);
|
||||||
|
|
||||||
|
if (sas_bsg_initialize(shost, &rdev->rphy, rdev->rphy.dev.bus_id))
|
||||||
|
printk("fail to a bsg device %s\n", rdev->rphy.dev.bus_id);
|
||||||
|
|
||||||
return &rdev->rphy;
|
return &rdev->rphy;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sas_end_device_alloc);
|
EXPORT_SYMBOL(sas_end_device_alloc);
|
||||||
|
@ -1260,6 +1342,9 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
|
||||||
sas_rphy_initialize(&rdev->rphy);
|
sas_rphy_initialize(&rdev->rphy);
|
||||||
transport_setup_device(&rdev->rphy.dev);
|
transport_setup_device(&rdev->rphy.dev);
|
||||||
|
|
||||||
|
if (sas_bsg_initialize(shost, &rdev->rphy, rdev->rphy.dev.bus_id))
|
||||||
|
printk("fail to a bsg device %s\n", rdev->rphy.dev.bus_id);
|
||||||
|
|
||||||
return &rdev->rphy;
|
return &rdev->rphy;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sas_expander_alloc);
|
EXPORT_SYMBOL(sas_expander_alloc);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
struct scsi_transport_template;
|
struct scsi_transport_template;
|
||||||
struct sas_rphy;
|
struct sas_rphy;
|
||||||
|
struct request;
|
||||||
|
|
||||||
enum sas_device_type {
|
enum sas_device_type {
|
||||||
SAS_PHY_UNUSED,
|
SAS_PHY_UNUSED,
|
||||||
|
@ -172,6 +172,7 @@ struct sas_function_template {
|
||||||
int (*phy_reset)(struct sas_phy *, int);
|
int (*phy_reset)(struct sas_phy *, int);
|
||||||
int (*phy_enable)(struct sas_phy *, int);
|
int (*phy_enable)(struct sas_phy *, int);
|
||||||
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
|
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
|
||||||
|
int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче