summaryrefslogtreecommitdiff
path: root/drivers/scsi/isci/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/isci/host.c')
-rw-r--r--drivers/scsi/isci/host.c313
1 files changed, 61 insertions, 252 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index bbec1982d07f..0fe372f93289 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1074,7 +1074,7 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
* @data: This parameter specifies the ISCI host object
*
*/
-static void isci_host_completion_routine(unsigned long data)
+void isci_host_completion_routine(unsigned long data)
{
struct isci_host *ihost = (struct isci_host *)data;
struct list_head completed_request_list;
@@ -1317,29 +1317,6 @@ static void __iomem *smu_base(struct isci_host *isci_host)
return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
}
-static void isci_user_parameters_get(struct sci_user_parameters *u)
-{
- int i;
-
- for (i = 0; i < SCI_MAX_PHYS; i++) {
- struct sci_phy_user_params *u_phy = &u->phys[i];
-
- u_phy->max_speed_generation = phy_gen;
-
- /* we are not exporting these for now */
- u_phy->align_insertion_frequency = 0x7f;
- u_phy->in_connection_align_insertion_frequency = 0xff;
- u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
- }
-
- u->stp_inactivity_timeout = stp_inactive_to;
- u->ssp_inactivity_timeout = ssp_inactive_to;
- u->stp_max_occupancy_timeout = stp_max_occ_to;
- u->ssp_max_occupancy_timeout = ssp_max_occ_to;
- u->no_outbound_task_timeout = no_outbound_task_to;
- u->max_concurr_spinup = max_concurr_spinup;
-}
-
static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm)
{
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
@@ -1648,55 +1625,6 @@ static const struct sci_base_state sci_controller_state_table[] = {
[SCIC_FAILED] = {}
};
-static void sci_controller_set_default_config_parameters(struct isci_host *ihost)
-{
- /* these defaults are overridden by the platform / firmware */
- u16 index;
-
- /* Default to APC mode. */
- ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
-
- /* Default to APC mode. */
- ihost->oem_parameters.controller.max_concurr_spin_up = 1;
-
- /* Default to no SSC operation. */
- ihost->oem_parameters.controller.do_enable_ssc = false;
-
- /* Default to short cables on all phys. */
- ihost->oem_parameters.controller.cable_selection_mask = 0;
-
- /* Initialize all of the port parameter information to narrow ports. */
- for (index = 0; index < SCI_MAX_PORTS; index++) {
- ihost->oem_parameters.ports[index].phy_mask = 0;
- }
-
- /* Initialize all of the phy parameter information. */
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- /* Default to 3G (i.e. Gen 2). */
- ihost->user_parameters.phys[index].max_speed_generation =
- SCIC_SDS_PARM_GEN2_SPEED;
-
- /* the frequencies cannot be 0 */
- ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f;
- ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff;
- ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
-
- /*
- * Previous Vitesse based expanders had a arbitration issue that
- * is worked around by having the upper 32-bits of SAS address
- * with a value greater then the Vitesse company identifier.
- * Hence, usage of 0x5FCFFFFF. */
- ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id;
- ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF;
- }
-
- ihost->user_parameters.stp_inactivity_timeout = 5;
- ihost->user_parameters.ssp_inactivity_timeout = 5;
- ihost->user_parameters.stp_max_occupancy_timeout = 5;
- ihost->user_parameters.ssp_max_occupancy_timeout = 20;
- ihost->user_parameters.no_outbound_task_timeout = 2;
-}
-
static void controller_timeout(unsigned long data)
{
struct sci_timer *tmr = (struct sci_timer *)data;
@@ -1753,9 +1681,6 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost,
sci_init_timer(&ihost->timer, controller_timeout);
- /* Initialize the User and OEM parameters to default values. */
- sci_controller_set_default_config_parameters(ihost);
-
return sci_controller_reset(ihost);
}
@@ -1835,27 +1760,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version)
return 0;
}
-static enum sci_status sci_oem_parameters_set(struct isci_host *ihost)
-{
- u32 state = ihost->sm.current_state_id;
- struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
- if (state == SCIC_RESET ||
- state == SCIC_INITIALIZING ||
- state == SCIC_INITIALIZED) {
- u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version :
- ISCI_ROM_VER_1_0;
-
- if (sci_oem_parameters_validate(&ihost->oem_parameters,
- oem_version))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- return SCI_SUCCESS;
- }
-
- return SCI_FAILURE_INVALID_STATE;
-}
-
static u8 max_spin_up(struct isci_host *ihost)
{
if (ihost->user_parameters.max_concurr_spinup)
@@ -2372,96 +2276,77 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost)
return result;
}
-static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
- struct sci_user_parameters *sci_parms)
-{
- u32 state = ihost->sm.current_state_id;
-
- if (state == SCIC_RESET ||
- state == SCIC_INITIALIZING ||
- state == SCIC_INITIALIZED) {
- u16 index;
-
- /*
- * Validate the user parameters. If they are not legal, then
- * return a failure.
- */
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- struct sci_phy_user_params *user_phy;
-
- user_phy = &sci_parms->phys[index];
-
- if (!((user_phy->max_speed_generation <=
- SCIC_SDS_PARM_MAX_SPEED) &&
- (user_phy->max_speed_generation >
- SCIC_SDS_PARM_NO_SPEED)))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- if (user_phy->in_connection_align_insertion_frequency <
- 3)
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- if ((user_phy->in_connection_align_insertion_frequency <
- 3) ||
- (user_phy->align_insertion_frequency == 0) ||
- (user_phy->
- notify_enable_spin_up_insertion_frequency ==
- 0))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
- }
-
- if ((sci_parms->stp_inactivity_timeout == 0) ||
- (sci_parms->ssp_inactivity_timeout == 0) ||
- (sci_parms->stp_max_occupancy_timeout == 0) ||
- (sci_parms->ssp_max_occupancy_timeout == 0) ||
- (sci_parms->no_outbound_task_timeout == 0))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
-
- return SCI_SUCCESS;
- }
-
- return SCI_FAILURE_INVALID_STATE;
-}
-
-static int sci_controller_mem_init(struct isci_host *ihost)
+static int sci_controller_dma_alloc(struct isci_host *ihost)
{
struct device *dev = &ihost->pdev->dev;
- dma_addr_t dma;
size_t size;
- int err;
+ int i;
+
+ /* detect re-initialization */
+ if (ihost->completion_queue)
+ return 0;
size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32);
- ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ ihost->completion_queue = dmam_alloc_coherent(dev, size, &ihost->cq_dma,
+ GFP_KERNEL);
if (!ihost->completion_queue)
return -ENOMEM;
- writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper);
-
size = ihost->remote_node_entries * sizeof(union scu_remote_node_context);
- ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma,
+ ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &ihost->rnc_dma,
GFP_KERNEL);
+
if (!ihost->remote_node_context_table)
return -ENOMEM;
- writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper);
-
size = ihost->task_context_entries * sizeof(struct scu_task_context),
- ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ ihost->task_context_table = dmam_alloc_coherent(dev, size, &ihost->tc_dma,
+ GFP_KERNEL);
if (!ihost->task_context_table)
return -ENOMEM;
- ihost->task_context_dma = dma;
- writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper);
+ size = SCI_UFI_TOTAL_SIZE;
+ ihost->ufi_buf = dmam_alloc_coherent(dev, size, &ihost->ufi_dma, GFP_KERNEL);
+ if (!ihost->ufi_buf)
+ return -ENOMEM;
+
+ for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+ struct isci_request *ireq;
+ dma_addr_t dma;
+
+ ireq = dmam_alloc_coherent(dev, sizeof(*ireq), &dma, GFP_KERNEL);
+ if (!ireq)
+ return -ENOMEM;
+
+ ireq->tc = &ihost->task_context_table[i];
+ ireq->owning_controller = ihost;
+ spin_lock_init(&ireq->state_lock);
+ ireq->request_daddr = dma;
+ ireq->isci_host = ihost;
+ ihost->reqs[i] = ireq;
+ }
+
+ return 0;
+}
+
+static int sci_controller_mem_init(struct isci_host *ihost)
+{
+ int err = sci_controller_dma_alloc(ihost);
- err = sci_unsolicited_frame_control_construct(ihost);
if (err)
return err;
+ writel(lower_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_lower);
+ writel(upper_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_upper);
+
+ writel(lower_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_lower);
+ writel(upper_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_upper);
+
+ writel(lower_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_lower);
+ writel(upper_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_upper);
+
+ sci_unsolicited_frame_control_construct(ihost);
+
/*
* Inform the silicon as to the location of the UF headers and
* address table.
@@ -2479,19 +2364,20 @@ static int sci_controller_mem_init(struct isci_host *ihost)
return 0;
}
+/**
+ * isci_host_init - (re-)initialize hardware and internal (private) state
+ * @ihost: host to init
+ *
+ * Any public facing objects (like asd_sas_port, and asd_sas_phys), or
+ * one-time initialization objects like locks and waitqueues, are
+ * not touched (they are initialized in isci_host_alloc)
+ */
int isci_host_init(struct isci_host *ihost)
{
- int err = 0, i;
+ int i, err;
enum sci_status status;
- struct sci_user_parameters sci_user_params;
- struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
- spin_lock_init(&ihost->scic_lock);
- init_waitqueue_head(&ihost->eventq);
-
- status = sci_controller_construct(ihost, scu_base(ihost),
- smu_base(ihost));
+ status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost));
if (status != SCI_SUCCESS) {
dev_err(&ihost->pdev->dev,
"%s: sci_controller_construct failed - status = %x\n",
@@ -2500,48 +2386,6 @@ int isci_host_init(struct isci_host *ihost)
return -ENODEV;
}
- ihost->sas_ha.dev = &ihost->pdev->dev;
- ihost->sas_ha.lldd_ha = ihost;
-
- /*
- * grab initial values stored in the controller object for OEM and USER
- * parameters
- */
- isci_user_parameters_get(&sci_user_params);
- status = sci_user_parameters_set(ihost, &sci_user_params);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "%s: sci_user_parameters_set failed\n",
- __func__);
- return -ENODEV;
- }
-
- /* grab any OEM parameters specified in orom */
- if (pci_info->orom) {
- status = isci_parse_oem_parameters(&ihost->oem_parameters,
- pci_info->orom,
- ihost->id);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "parsing firmware oem parameters failed\n");
- return -EINVAL;
- }
- }
-
- status = sci_oem_parameters_set(ihost);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "%s: sci_oem_parameters_set failed\n",
- __func__);
- return -ENODEV;
- }
-
- tasklet_init(&ihost->completion_tasklet,
- isci_host_completion_routine, (unsigned long)ihost);
-
- INIT_LIST_HEAD(&ihost->requests_to_complete);
- INIT_LIST_HEAD(&ihost->requests_to_errorback);
-
spin_lock_irq(&ihost->scic_lock);
status = sci_controller_initialize(ihost);
spin_unlock_irq(&ihost->scic_lock);
@@ -2557,47 +2401,12 @@ int isci_host_init(struct isci_host *ihost)
if (err)
return err;
- for (i = 0; i < SCI_MAX_PORTS; i++) {
- struct isci_port *iport = &ihost->ports[i];
-
- INIT_LIST_HEAD(&iport->remote_dev_list);
- iport->isci_host = ihost;
- }
-
- for (i = 0; i < SCI_MAX_PHYS; i++)
- isci_phy_init(&ihost->phys[i], ihost, i);
-
/* enable sgpio */
writel(1, &ihost->scu_registers->peg0.sgpio.interface_control);
for (i = 0; i < isci_gpio_count(ihost); i++)
writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code);
- for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
- struct isci_remote_device *idev = &ihost->devices[i];
-
- INIT_LIST_HEAD(&idev->reqs_in_process);
- INIT_LIST_HEAD(&idev->node);
- }
-
- for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
- struct isci_request *ireq;
- dma_addr_t dma;
-
- ireq = dmam_alloc_coherent(&ihost->pdev->dev,
- sizeof(struct isci_request), &dma,
- GFP_KERNEL);
- if (!ireq)
- return -ENOMEM;
-
- ireq->tc = &ihost->task_context_table[i];
- ireq->owning_controller = ihost;
- spin_lock_init(&ireq->state_lock);
- ireq->request_daddr = dma;
- ireq->isci_host = ihost;
- ihost->reqs[i] = ireq;
- }
-
return 0;
}