mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-06 22:44:40 +00:00
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
3 changed files with 133 additions and 9 deletions
|
@ -148,6 +148,7 @@ enclosure_register(struct device *dev, const char *name, int components,
|
||||||
for (i = 0; i < components; i++) {
|
for (i = 0; i < components; i++) {
|
||||||
edev->component[i].number = -1;
|
edev->component[i].number = -1;
|
||||||
edev->component[i].slot = -1;
|
edev->component[i].slot = -1;
|
||||||
|
edev->component[i].power_status = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&container_list_lock);
|
mutex_lock(&container_list_lock);
|
||||||
|
@ -583,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev,
|
||||||
return count;
|
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,
|
static ssize_t get_component_type(struct device *cdev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -614,6 +649,8 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
|
||||||
set_component_active);
|
set_component_active);
|
||||||
static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
|
static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
|
||||||
set_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(type, S_IRUGO, get_component_type, NULL);
|
||||||
static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, 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_status.attr,
|
||||||
&dev_attr_active.attr,
|
&dev_attr_active.attr,
|
||||||
&dev_attr_locate.attr,
|
&dev_attr_locate.attr,
|
||||||
|
&dev_attr_power_status.attr,
|
||||||
&dev_attr_type.attr,
|
&dev_attr_type.attr,
|
||||||
&dev_attr_slot.attr,
|
&dev_attr_slot.attr,
|
||||||
NULL
|
NULL
|
||||||
|
|
|
@ -67,6 +67,20 @@ static int ses_probe(struct device *dev)
|
||||||
#define SES_TIMEOUT (30 * HZ)
|
#define SES_TIMEOUT (30 * HZ)
|
||||||
#define SES_RETRIES 3
|
#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,
|
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
|
||||||
void *buf, int bufflen)
|
void *buf, int bufflen)
|
||||||
{
|
{
|
||||||
|
@ -178,14 +192,22 @@ static int ses_set_fault(struct enclosure_device *edev,
|
||||||
struct enclosure_component *ecomp,
|
struct enclosure_component *ecomp,
|
||||||
enum enclosure_component_setting val)
|
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) {
|
switch (val) {
|
||||||
case ENCLOSURE_SETTING_DISABLED:
|
case ENCLOSURE_SETTING_DISABLED:
|
||||||
/* zero is disabled */
|
desc[3] &= 0xdf;
|
||||||
break;
|
break;
|
||||||
case ENCLOSURE_SETTING_ENABLED:
|
case ENCLOSURE_SETTING_ENABLED:
|
||||||
desc[3] = 0x20;
|
desc[3] |= 0x20;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* SES doesn't do the SGPIO blink settings */
|
/* 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,
|
struct enclosure_component *ecomp,
|
||||||
enum enclosure_component_setting val)
|
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) {
|
switch (val) {
|
||||||
case ENCLOSURE_SETTING_DISABLED:
|
case ENCLOSURE_SETTING_DISABLED:
|
||||||
/* zero is disabled */
|
desc[2] &= 0xfd;
|
||||||
break;
|
break;
|
||||||
case ENCLOSURE_SETTING_ENABLED:
|
case ENCLOSURE_SETTING_ENABLED:
|
||||||
desc[2] = 0x02;
|
desc[2] |= 0x02;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* SES doesn't do the SGPIO blink settings */
|
/* 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,
|
struct enclosure_component *ecomp,
|
||||||
enum enclosure_component_setting val)
|
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) {
|
switch (val) {
|
||||||
case ENCLOSURE_SETTING_DISABLED:
|
case ENCLOSURE_SETTING_DISABLED:
|
||||||
/* zero is disabled */
|
desc[2] &= 0x7f;
|
||||||
ecomp->active = 0;
|
ecomp->active = 0;
|
||||||
break;
|
break;
|
||||||
case ENCLOSURE_SETTING_ENABLED:
|
case ENCLOSURE_SETTING_ENABLED:
|
||||||
desc[2] = 0x80;
|
desc[2] |= 0x80;
|
||||||
ecomp->active = 1;
|
ecomp->active = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -265,12 +303,53 @@ static int ses_show_id(struct enclosure_device *edev, char *buf)
|
||||||
return sprintf(buf, "%#llx\n", id);
|
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 = {
|
static struct enclosure_component_callbacks ses_enclosure_callbacks = {
|
||||||
.get_fault = ses_get_fault,
|
.get_fault = ses_get_fault,
|
||||||
.set_fault = ses_set_fault,
|
.set_fault = ses_set_fault,
|
||||||
.get_status = ses_get_status,
|
.get_status = ses_get_status,
|
||||||
.get_locate = ses_get_locate,
|
.get_locate = ses_get_locate,
|
||||||
.set_locate = ses_set_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,
|
.set_active = ses_set_active,
|
||||||
.show_id = ses_show_id,
|
.show_id = ses_show_id,
|
||||||
};
|
};
|
||||||
|
@ -449,6 +528,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
|
||||||
ecomp = &edev->component[components++];
|
ecomp = &edev->component[components++];
|
||||||
|
|
||||||
if (!IS_ERR(ecomp)) {
|
if (!IS_ERR(ecomp)) {
|
||||||
|
ses_get_power_status(edev, ecomp);
|
||||||
if (addl_desc_ptr)
|
if (addl_desc_ptr)
|
||||||
ses_process_descriptor(
|
ses_process_descriptor(
|
||||||
ecomp,
|
ecomp,
|
||||||
|
|
|
@ -79,6 +79,11 @@ struct enclosure_component_callbacks {
|
||||||
int (*set_locate)(struct enclosure_device *,
|
int (*set_locate)(struct enclosure_device *,
|
||||||
struct enclosure_component *,
|
struct enclosure_component *,
|
||||||
enum enclosure_component_setting);
|
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);
|
int (*show_id)(struct enclosure_device *, char *buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +99,7 @@ struct enclosure_component {
|
||||||
int locate;
|
int locate;
|
||||||
int slot;
|
int slot;
|
||||||
enum enclosure_status status;
|
enum enclosure_status status;
|
||||||
|
int power_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct enclosure_device {
|
struct enclosure_device {
|
||||||
|
|
Loading…
Add table
Reference in a new issue