mirror of https://gitee.com/openkylin/linux.git
ses: Add power_status to SES device slot
Add power_status to SES device slot, so we can power on/off the HDDs behind the enclosure. Check firmware status in ses_set_* before sending control pages to firmware. Signed-off-by: Song Liu <songliubraving@fb.com> Acked-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Jens Axboe <axboe@fb.com> Cc: Hannes Reinecke <hare@suse.de> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
921ce7f578
commit
08024885a2
|
@ -148,6 +148,7 @@ enclosure_register(struct device *dev, const char *name, int components,
|
|||
for (i = 0; i < components; i++) {
|
||||
edev->component[i].number = -1;
|
||||
edev->component[i].slot = -1;
|
||||
edev->component[i].power_status = 1;
|
||||
}
|
||||
|
||||
mutex_lock(&container_list_lock);
|
||||
|
@ -583,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t get_component_power_status(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
|
||||
struct enclosure_component *ecomp = to_enclosure_component(cdev);
|
||||
|
||||
if (edev->cb->get_power_status)
|
||||
edev->cb->get_power_status(edev, ecomp);
|
||||
return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t set_component_power_status(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
|
||||
struct enclosure_component *ecomp = to_enclosure_component(cdev);
|
||||
int val;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0 &&
|
||||
(buf[2] == '\n' || buf[2] == '\0'))
|
||||
val = 1;
|
||||
else if (strncmp(buf, "off", 3) == 0 &&
|
||||
(buf[3] == '\n' || buf[3] == '\0'))
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (edev->cb->set_power_status)
|
||||
edev->cb->set_power_status(edev, ecomp, val);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t get_component_type(struct device *cdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -614,6 +649,8 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
|
|||
set_component_active);
|
||||
static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
|
||||
set_component_locate);
|
||||
static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status,
|
||||
set_component_power_status);
|
||||
static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
|
||||
static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL);
|
||||
|
||||
|
@ -622,6 +659,7 @@ static struct attribute *enclosure_component_attrs[] = {
|
|||
&dev_attr_status.attr,
|
||||
&dev_attr_active.attr,
|
||||
&dev_attr_locate.attr,
|
||||
&dev_attr_power_status.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_slot.attr,
|
||||
NULL
|
||||
|
|
|
@ -67,6 +67,20 @@ static int ses_probe(struct device *dev)
|
|||
#define SES_TIMEOUT (30 * HZ)
|
||||
#define SES_RETRIES 3
|
||||
|
||||
static void init_device_slot_control(unsigned char *dest_desc,
|
||||
struct enclosure_component *ecomp,
|
||||
unsigned char *status)
|
||||
{
|
||||
memcpy(dest_desc, status, 4);
|
||||
dest_desc[0] = 0;
|
||||
/* only clear byte 1 for ENCLOSURE_COMPONENT_DEVICE */
|
||||
if (ecomp->type == ENCLOSURE_COMPONENT_DEVICE)
|
||||
dest_desc[1] = 0;
|
||||
dest_desc[2] &= 0xde;
|
||||
dest_desc[3] &= 0x3c;
|
||||
}
|
||||
|
||||
|
||||
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
|
||||
void *buf, int bufflen)
|
||||
{
|
||||
|
@ -178,14 +192,22 @@ static int ses_set_fault(struct enclosure_device *edev,
|
|||
struct enclosure_component *ecomp,
|
||||
enum enclosure_component_setting val)
|
||||
{
|
||||
unsigned char desc[4] = {0 };
|
||||
unsigned char desc[4];
|
||||
unsigned char *desc_ptr;
|
||||
|
||||
desc_ptr = ses_get_page2_descriptor(edev, ecomp);
|
||||
|
||||
if (!desc_ptr)
|
||||
return -EIO;
|
||||
|
||||
init_device_slot_control(desc, ecomp, desc_ptr);
|
||||
|
||||
switch (val) {
|
||||
case ENCLOSURE_SETTING_DISABLED:
|
||||
/* zero is disabled */
|
||||
desc[3] &= 0xdf;
|
||||
break;
|
||||
case ENCLOSURE_SETTING_ENABLED:
|
||||
desc[3] = 0x20;
|
||||
desc[3] |= 0x20;
|
||||
break;
|
||||
default:
|
||||
/* SES doesn't do the SGPIO blink settings */
|
||||
|
@ -219,14 +241,22 @@ static int ses_set_locate(struct enclosure_device *edev,
|
|||
struct enclosure_component *ecomp,
|
||||
enum enclosure_component_setting val)
|
||||
{
|
||||
unsigned char desc[4] = {0 };
|
||||
unsigned char desc[4];
|
||||
unsigned char *desc_ptr;
|
||||
|
||||
desc_ptr = ses_get_page2_descriptor(edev, ecomp);
|
||||
|
||||
if (!desc_ptr)
|
||||
return -EIO;
|
||||
|
||||
init_device_slot_control(desc, ecomp, desc_ptr);
|
||||
|
||||
switch (val) {
|
||||
case ENCLOSURE_SETTING_DISABLED:
|
||||
/* zero is disabled */
|
||||
desc[2] &= 0xfd;
|
||||
break;
|
||||
case ENCLOSURE_SETTING_ENABLED:
|
||||
desc[2] = 0x02;
|
||||
desc[2] |= 0x02;
|
||||
break;
|
||||
default:
|
||||
/* SES doesn't do the SGPIO blink settings */
|
||||
|
@ -239,15 +269,23 @@ static int ses_set_active(struct enclosure_device *edev,
|
|||
struct enclosure_component *ecomp,
|
||||
enum enclosure_component_setting val)
|
||||
{
|
||||
unsigned char desc[4] = {0 };
|
||||
unsigned char desc[4];
|
||||
unsigned char *desc_ptr;
|
||||
|
||||
desc_ptr = ses_get_page2_descriptor(edev, ecomp);
|
||||
|
||||
if (!desc_ptr)
|
||||
return -EIO;
|
||||
|
||||
init_device_slot_control(desc, ecomp, desc_ptr);
|
||||
|
||||
switch (val) {
|
||||
case ENCLOSURE_SETTING_DISABLED:
|
||||
/* zero is disabled */
|
||||
desc[2] &= 0x7f;
|
||||
ecomp->active = 0;
|
||||
break;
|
||||
case ENCLOSURE_SETTING_ENABLED:
|
||||
desc[2] = 0x80;
|
||||
desc[2] |= 0x80;
|
||||
ecomp->active = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -265,12 +303,53 @@ static int ses_show_id(struct enclosure_device *edev, char *buf)
|
|||
return sprintf(buf, "%#llx\n", id);
|
||||
}
|
||||
|
||||
static void ses_get_power_status(struct enclosure_device *edev,
|
||||
struct enclosure_component *ecomp)
|
||||
{
|
||||
unsigned char *desc;
|
||||
|
||||
desc = ses_get_page2_descriptor(edev, ecomp);
|
||||
if (desc)
|
||||
ecomp->power_status = (desc[3] & 0x10) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int ses_set_power_status(struct enclosure_device *edev,
|
||||
struct enclosure_component *ecomp,
|
||||
int val)
|
||||
{
|
||||
unsigned char desc[4];
|
||||
unsigned char *desc_ptr;
|
||||
|
||||
desc_ptr = ses_get_page2_descriptor(edev, ecomp);
|
||||
|
||||
if (!desc_ptr)
|
||||
return -EIO;
|
||||
|
||||
init_device_slot_control(desc, ecomp, desc_ptr);
|
||||
|
||||
switch (val) {
|
||||
/* power = 1 is device_off = 0 and vice versa */
|
||||
case 0:
|
||||
desc[3] |= 0x10;
|
||||
break;
|
||||
case 1:
|
||||
desc[3] &= 0xef;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ecomp->power_status = val;
|
||||
return ses_set_page2_descriptor(edev, ecomp, desc);
|
||||
}
|
||||
|
||||
static struct enclosure_component_callbacks ses_enclosure_callbacks = {
|
||||
.get_fault = ses_get_fault,
|
||||
.set_fault = ses_set_fault,
|
||||
.get_status = ses_get_status,
|
||||
.get_locate = ses_get_locate,
|
||||
.set_locate = ses_set_locate,
|
||||
.get_power_status = ses_get_power_status,
|
||||
.set_power_status = ses_set_power_status,
|
||||
.set_active = ses_set_active,
|
||||
.show_id = ses_show_id,
|
||||
};
|
||||
|
@ -449,6 +528,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
|
|||
ecomp = &edev->component[components++];
|
||||
|
||||
if (!IS_ERR(ecomp)) {
|
||||
ses_get_power_status(edev, ecomp);
|
||||
if (addl_desc_ptr)
|
||||
ses_process_descriptor(
|
||||
ecomp,
|
||||
|
|
|
@ -79,6 +79,11 @@ struct enclosure_component_callbacks {
|
|||
int (*set_locate)(struct enclosure_device *,
|
||||
struct enclosure_component *,
|
||||
enum enclosure_component_setting);
|
||||
void (*get_power_status)(struct enclosure_device *,
|
||||
struct enclosure_component *);
|
||||
int (*set_power_status)(struct enclosure_device *,
|
||||
struct enclosure_component *,
|
||||
int);
|
||||
int (*show_id)(struct enclosure_device *, char *buf);
|
||||
};
|
||||
|
||||
|
@ -94,6 +99,7 @@ struct enclosure_component {
|
|||
int locate;
|
||||
int slot;
|
||||
enum enclosure_status status;
|
||||
int power_status;
|
||||
};
|
||||
|
||||
struct enclosure_device {
|
||||
|
|
Loading…
Reference in New Issue