Skip to content

Commit

Permalink
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/jejb/scsi

Pull first round of SCSI updates from James Bottomley:
 "This is the usual grab bag of driver updates (hpsa, storvsc, mp2sas,
  megaraid_sas, ses) plus an assortment of minor updates.

  There's also an update to ufs which adds new phy drivers and finally a
  new logging infrastructure for SCSI"

* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (114 commits)
  scsi_logging: return void for dev_printk() functions
  scsi: print single-character strings with seq_putc
  scsi: merge consecutive seq_puts calls
  scsi: replace seq_printf with seq_puts
  aha152x: replace seq_printf with seq_puts
  advansys: replace seq_printf with seq_puts
  scsi: remove SPRINTF macro
  sg: remove an unused variable
  hpsa: Use local workqueues instead of system workqueues
  hpsa: add in P840ar controller model name
  hpsa: add in gen9 controller model names
  hpsa: detect and report failures changing controller transport modes
  hpsa: shorten the wait for the CISS doorbell mode change ack
  hpsa: refactor duplicated scan completion code into a new routine
  hpsa: move SG descriptor set-up out of hpsa_scatter_gather()
  hpsa: do not use function pointers in fast path command submission
  hpsa: print CDBs instead of kernel virtual addresses for uncommon errors
  hpsa: do not use a void pointer for scsi_cmd field of struct CommandList
  hpsa: return failed from device reset/abort handlers
  hpsa: check for ctlr lockup after command allocation in main io path
  ...
  • Loading branch information
Linus Torvalds committed Feb 11, 2015
2 parents 718749d + 9c4a6b1 commit 540a7c5
Show file tree
Hide file tree
Showing 92 changed files with 6,325 additions and 2,265 deletions.
20 changes: 9 additions & 11 deletions drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -2481,7 +2481,6 @@ static void ata_eh_link_report(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
const u8 *cdb = qc->cdb;
char data_buf[20] = "";
char cdb_buf[70] = "";

Expand Down Expand Up @@ -2509,16 +2508,15 @@ static void ata_eh_link_report(struct ata_link *link)
}

if (ata_is_atapi(qc->tf.protocol)) {
if (qc->scsicmd)
scsi_print_command(qc->scsicmd);
else
snprintf(cdb_buf, sizeof(cdb_buf),
"cdb %02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n ",
cdb[0], cdb[1], cdb[2], cdb[3],
cdb[4], cdb[5], cdb[6], cdb[7],
cdb[8], cdb[9], cdb[10], cdb[11],
cdb[12], cdb[13], cdb[14], cdb[15]);
const u8 *cdb = qc->cdb;
size_t cdb_len = qc->dev->cdb_len;

if (qc->scsicmd) {
cdb = qc->scsicmd->cmnd;
cdb_len = qc->scsicmd->cmd_len;
}
__scsi_format_command(cdb_buf, sizeof(cdb_buf),
cdb, cdb_len);
} else {
const char *descr = ata_get_cmd_descript(cmd->command);
if (descr)
Expand Down
108 changes: 96 additions & 12 deletions drivers/misc/enclosure.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ enclosure_register(struct device *dev, const char *name, int components,
if (err)
goto err;

for (i = 0; i < components; i++)
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);
list_add_tail(&edev->node, &container_list);
Expand Down Expand Up @@ -273,27 +276,26 @@ enclosure_component_find_by_name(struct enclosure_device *edev,
static const struct attribute_group *enclosure_component_groups[];

/**
* enclosure_component_register - add a particular component to an enclosure
* enclosure_component_alloc - prepare a new enclosure component
* @edev: the enclosure to add the component
* @num: the device number
* @type: the type of component being added
* @name: an optional name to appear in sysfs (leave NULL if none)
*
* Registers the component. The name is optional for enclosures that
* give their components a unique name. If not, leave the field NULL
* and a name will be assigned.
* The name is optional for enclosures that give their components a unique
* name. If not, leave the field NULL and a name will be assigned.
*
* Returns a pointer to the enclosure component or an error.
*/
struct enclosure_component *
enclosure_component_register(struct enclosure_device *edev,
unsigned int number,
enum enclosure_component_type type,
const char *name)
enclosure_component_alloc(struct enclosure_device *edev,
unsigned int number,
enum enclosure_component_type type,
const char *name)
{
struct enclosure_component *ecomp;
struct device *cdev;
int err, i;
int i;
char newname[COMPONENT_NAME_SIZE];

if (number >= edev->components)
Expand Down Expand Up @@ -327,14 +329,30 @@ enclosure_component_register(struct enclosure_device *edev,
cdev->release = enclosure_component_release;
cdev->groups = enclosure_component_groups;

return ecomp;
}
EXPORT_SYMBOL_GPL(enclosure_component_alloc);

/**
* enclosure_component_register - publishes an initialized enclosure component
* @ecomp: component to add
*
* Returns 0 on successful registration, releases the component otherwise
*/
int enclosure_component_register(struct enclosure_component *ecomp)
{
struct device *cdev;
int err;

cdev = &ecomp->cdev;
err = device_register(cdev);
if (err) {
ecomp->number = -1;
put_device(cdev);
return ERR_PTR(err);
return err;
}

return ecomp;
return 0;
}
EXPORT_SYMBOL_GPL(enclosure_component_register);

Expand Down Expand Up @@ -417,8 +435,21 @@ static ssize_t components_show(struct device *cdev,
}
static DEVICE_ATTR_RO(components);

static ssize_t id_show(struct device *cdev,
struct device_attribute *attr,
char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev);

if (edev->cb->show_id)
return edev->cb->show_id(edev, buf);
return -EINVAL;
}
static DEVICE_ATTR_RO(id);

static struct attribute *enclosure_class_attrs[] = {
&dev_attr_components.attr,
&dev_attr_id.attr,
NULL,
};
ATTRIBUTE_GROUPS(enclosure_class);
Expand Down Expand Up @@ -553,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)
{
Expand All @@ -561,6 +626,20 @@ static ssize_t get_component_type(struct device *cdev,
return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]);
}

static ssize_t get_component_slot(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct enclosure_component *ecomp = to_enclosure_component(cdev);
int slot;

/* if the enclosure does not override then use 'number' as a stand-in */
if (ecomp->slot >= 0)
slot = ecomp->slot;
else
slot = ecomp->number;

return snprintf(buf, 40, "%d\n", slot);
}

static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
set_component_fault);
Expand All @@ -570,14 +649,19 @@ 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);

static struct attribute *enclosure_component_attrs[] = {
&dev_attr_fault.attr,
&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
};
ATTRIBUTE_GROUPS(enclosure_component);
Expand Down
7 changes: 7 additions & 0 deletions drivers/phy/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,11 @@ config PHY_STIH41X_USB
Enable this to support the USB transceiver that is part of
STMicroelectronics STiH41x SoC series.

config PHY_QCOM_UFS
tristate "Qualcomm UFS PHY driver"
depends on OF && ARCH_MSM
select GENERIC_PHY
help
Support for UFS PHY on QCOM chipsets.

endmenu
3 changes: 3 additions & 0 deletions drivers/phy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
159 changes: 159 additions & 0 deletions drivers/phy/phy-qcom-ufs-i.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/

#ifndef UFS_QCOM_PHY_I_H_
#define UFS_QCOM_PHY_I_H_

#include <linux/module.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/phy/phy-qcom-ufs.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>

#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
({ \
ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
might_sleep_if(timeout_us); \
for (;;) { \
(val) = readl(addr); \
if (cond) \
break; \
if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
(val) = readl(addr); \
break; \
} \
if (sleep_us) \
usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
} \
(cond) ? 0 : -ETIMEDOUT; \
})

#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \
{ \
.reg_offset = reg, \
.cfg_value = val, \
}

#define UFS_QCOM_PHY_NAME_LEN 30

enum {
MASK_SERDES_START = 0x1,
MASK_PCS_READY = 0x1,
};

enum {
OFFSET_SERDES_START = 0x0,
};

struct ufs_qcom_phy_stored_attributes {
u32 att;
u32 value;
};


struct ufs_qcom_phy_calibration {
u32 reg_offset;
u32 cfg_value;
};

struct ufs_qcom_phy_vreg {
const char *name;
struct regulator *reg;
int max_uA;
int min_uV;
int max_uV;
bool enabled;
bool is_always_on;
};

struct ufs_qcom_phy {
struct list_head list;
struct device *dev;
void __iomem *mmio;
void __iomem *dev_ref_clk_ctrl_mmio;
struct clk *tx_iface_clk;
struct clk *rx_iface_clk;
bool is_iface_clk_enabled;
struct clk *ref_clk_src;
struct clk *ref_clk_parent;
struct clk *ref_clk;
bool is_ref_clk_enabled;
bool is_dev_ref_clk_enabled;
struct ufs_qcom_phy_vreg vdda_pll;
struct ufs_qcom_phy_vreg vdda_phy;
struct ufs_qcom_phy_vreg vddp_ref_clk;
unsigned int quirks;

/*
* If UFS link is put into Hibern8 and if UFS PHY analog hardware is
* power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8
* exit might fail even after powering on UFS PHY analog hardware.
* Enabling this quirk will help to solve above issue by doing
* custom PHY settings just before PHY analog power collapse.
*/
#define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE BIT(0)

u8 host_ctrl_rev_major;
u16 host_ctrl_rev_minor;
u16 host_ctrl_rev_step;

char name[UFS_QCOM_PHY_NAME_LEN];
struct ufs_qcom_phy_calibration *cached_regs;
int cached_regs_table_size;
bool is_powered_on;
struct ufs_qcom_phy_specific_ops *phy_spec_ops;
};

/**
* struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a
* specific implementation per phy. Each UFS phy, should implement
* those functions according to its spec and requirements
* @calibrate_phy: pointer to a function that calibrate the phy
* @start_serdes: pointer to a function that starts the serdes
* @is_physical_coding_sublayer_ready: pointer to a function that
* checks pcs readiness. returns 0 for success and non-zero for error.
* @set_tx_lane_enable: pointer to a function that enable tx lanes
* @power_control: pointer to a function that controls analog rail of phy
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
*/
struct ufs_qcom_phy_specific_ops {
int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
void (*start_serdes)(struct ufs_qcom_phy *phy);
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
void (*power_control)(struct ufs_qcom_phy *phy, bool val);
};

struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
int ufs_qcom_phy_power_on(struct phy *generic_phy);
int ufs_qcom_phy_power_off(struct phy *generic_phy);
int ufs_qcom_phy_exit(struct phy *generic_phy);
int ufs_qcom_phy_init_clks(struct phy *generic_phy,
struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_remove(struct phy *generic_phy,
struct ufs_qcom_phy *ufs_qcom_phy);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg,
struct phy_ops *ufs_qcom_phy_gen_ops,
struct ufs_qcom_phy_specific_ops *phy_spec_ops);
int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
bool is_rate_B);
#endif
Loading

0 comments on commit 540a7c5

Please sign in to comment.