Skip to content

Commit

Permalink
isci: refactor initialization for S3/S4
Browse files Browse the repository at this point in the history
Based on an original implementation by Ed Nadolski and Artur Wojcik

In preparation for S3/S4 support refactor initialization so that
driver-load and resume-from-suspend can share the common init path of
isci_host_init().  Organize the initialization into objects that are
self-contained to the driver (initialized by isci_host_init) versus
those that have some upward registration (initialized at allocation time
asd_sas_phy, asd_sas_port, dma allocations).  The largest change is
moving the the validation of the oem and module parameters from
isci_host_init() to isci_host_alloc().

The S3/S4 approach being taken is that libsas will be tasked with
remembering the state of the domain and the lldd is free to be
forgetful.  In the case of isci we'll just re-init using a subset of the
normal driver load path.

[clean up some unused / mis-indented function definitions in host.h]

Signed-off-by: Ed Nadolski <edmund.nadolski@intel.com>
Signed-off-by: Artur Wojcik <artur.wojcik@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
  • Loading branch information
Dan Williams committed May 17, 2012
1 parent ae904d1 commit abec912
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 360 deletions.
313 changes: 61 additions & 252 deletions drivers/scsi/isci/host.c

Large diffs are not rendered by default.

71 changes: 19 additions & 52 deletions drivers/scsi/isci/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,17 @@ struct isci_host {
struct sci_power_control power_control;
u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
struct scu_task_context *task_context_table;
dma_addr_t task_context_dma;
dma_addr_t tc_dma;
union scu_remote_node_context *remote_node_context_table;
dma_addr_t rnc_dma;
u32 *completion_queue;
dma_addr_t cq_dma;
u32 completion_queue_get;
u32 logical_port_entries;
u32 remote_node_entries;
u32 task_context_entries;
void *ufi_buf;
dma_addr_t ufi_dma;
struct sci_unsolicited_frame_control uf_control;

/* phy startup */
Expand Down Expand Up @@ -452,36 +456,17 @@ void sci_controller_free_remote_node_context(
struct isci_remote_device *idev,
u16 node_id);

struct isci_request *sci_request_by_tag(struct isci_host *ihost,
u16 io_tag);

void sci_controller_power_control_queue_insert(
struct isci_host *ihost,
struct isci_phy *iphy);

void sci_controller_power_control_queue_remove(
struct isci_host *ihost,
struct isci_phy *iphy);

void sci_controller_link_up(
struct isci_host *ihost,
struct isci_port *iport,
struct isci_phy *iphy);

void sci_controller_link_down(
struct isci_host *ihost,
struct isci_port *iport,
struct isci_phy *iphy);

void sci_controller_remote_device_stopped(
struct isci_host *ihost,
struct isci_remote_device *idev);

void sci_controller_copy_task_context(
struct isci_host *ihost,
struct isci_request *ireq);

void sci_controller_register_setup(struct isci_host *ihost);
struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag);
void sci_controller_power_control_queue_insert(struct isci_host *ihost,
struct isci_phy *iphy);
void sci_controller_power_control_queue_remove(struct isci_host *ihost,
struct isci_phy *iphy);
void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport,
struct isci_phy *iphy);
void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
struct isci_phy *iphy);
void sci_controller_remote_device_stopped(struct isci_host *ihost,
struct isci_remote_device *idev);

enum sci_status sci_controller_continue_io(struct isci_request *ireq);
int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
Expand All @@ -491,27 +476,9 @@ enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
void isci_tci_free(struct isci_host *ihost, u16 tci);

int isci_host_init(struct isci_host *);

void isci_host_init_controller_names(
struct isci_host *isci_host,
unsigned int controller_idx);

void isci_host_deinit(
struct isci_host *);

void isci_host_port_link_up(
struct isci_host *,
struct isci_port *,
struct isci_phy *);
int isci_host_dev_found(struct domain_device *);

void isci_host_remote_device_start_complete(
struct isci_host *,
struct isci_remote_device *,
enum sci_status);

void sci_controller_disable_interrupts(
struct isci_host *ihost);
void isci_host_completion_routine(unsigned long data);
void isci_host_deinit(struct isci_host *);
void sci_controller_disable_interrupts(struct isci_host *ihost);

enum sci_status sci_controller_start_io(
struct isci_host *ihost,
Expand Down
199 changes: 182 additions & 17 deletions drivers/scsi/isci/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,38 +397,203 @@ static int isci_setup_interrupts(struct pci_dev *pdev)
return err;
}

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 enum sci_status sci_user_parameters_set(struct isci_host *ihost,
struct sci_user_parameters *sci_parms)
{
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 *u;

u = &sci_parms->phys[index];

if (!((u->max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED) &&
(u->max_speed_generation > SCIC_SDS_PARM_NO_SPEED)))
return SCI_FAILURE_INVALID_PARAMETER_VALUE;

if (u->in_connection_align_insertion_frequency < 3)
return SCI_FAILURE_INVALID_PARAMETER_VALUE;

if ((u->in_connection_align_insertion_frequency < 3) ||
(u->align_insertion_frequency == 0) ||
(u->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;
}

static void sci_oem_defaults(struct isci_host *ihost)
{
/* these defaults are overridden by the platform / firmware */
struct sci_user_parameters *user = &ihost->user_parameters;
struct sci_oem_params *oem = &ihost->oem_parameters;
int i;

/* Default to APC mode. */
oem->controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;

/* Default to APC mode. */
oem->controller.max_concurr_spin_up = 1;

/* Default to no SSC operation. */
oem->controller.do_enable_ssc = false;

/* Default to short cables on all phys. */
oem->controller.cable_selection_mask = 0;

/* Initialize all of the port parameter information to narrow ports. */
for (i = 0; i < SCI_MAX_PORTS; i++)
oem->ports[i].phy_mask = 0;

/* Initialize all of the phy parameter information. */
for (i = 0; i < SCI_MAX_PHYS; i++) {
/* Default to 3G (i.e. Gen 2). */
user->phys[i].max_speed_generation = SCIC_SDS_PARM_GEN2_SPEED;

/* the frequencies cannot be 0 */
user->phys[i].align_insertion_frequency = 0x7f;
user->phys[i].in_connection_align_insertion_frequency = 0xff;
user->phys[i].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.
*/
oem->phys[i].sas_address.low = 0x1 + ihost->id;
oem->phys[i].sas_address.high = 0x5FCFFFFF;
}

user->stp_inactivity_timeout = 5;
user->ssp_inactivity_timeout = 5;
user->stp_max_occupancy_timeout = 5;
user->ssp_max_occupancy_timeout = 20;
user->no_outbound_task_timeout = 2;
}

static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
{
struct isci_host *isci_host;
struct isci_orom *orom = to_pci_info(pdev)->orom;
struct sci_user_parameters sci_user_params;
u8 oem_version = ISCI_ROM_VER_1_0;
struct isci_host *ihost;
struct Scsi_Host *shost;
int err;
int err, i;

isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
if (!isci_host)
ihost = devm_kzalloc(&pdev->dev, sizeof(*ihost), GFP_KERNEL);
if (!ihost)
return NULL;

ihost->pdev = pdev;
ihost->id = id;
spin_lock_init(&ihost->scic_lock);
init_waitqueue_head(&ihost->eventq);
ihost->sas_ha.dev = &ihost->pdev->dev;
ihost->sas_ha.lldd_ha = ihost;
tasklet_init(&ihost->completion_tasklet,
isci_host_completion_routine, (unsigned long)ihost);

/* validate module parameters */
/* TODO: kill struct sci_user_parameters and reference directly */
sci_oem_defaults(ihost);
isci_user_parameters_get(&sci_user_params);
if (sci_user_parameters_set(ihost, &sci_user_params)) {
dev_warn(&pdev->dev,
"%s: sci_user_parameters_set failed\n", __func__);
return NULL;
}

/* sanity check platform (or 'firmware') oem parameters */
if (orom) {
if (id < 0 || id >= SCI_MAX_CONTROLLERS || id > orom->hdr.num_elements) {
dev_warn(&pdev->dev, "parsing firmware oem parameters failed\n");
return NULL;
}
ihost->oem_parameters = orom->ctrl[id];
oem_version = orom->hdr.version;
}

/* validate oem parameters (platform, firmware, or built-in defaults) */
if (sci_oem_parameters_validate(&ihost->oem_parameters, oem_version)) {
dev_warn(&pdev->dev, "oem parameter validation failed\n");
return NULL;
}

INIT_LIST_HEAD(&ihost->requests_to_complete);
INIT_LIST_HEAD(&ihost->requests_to_errorback);
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;
}

isci_host->pdev = pdev;
isci_host->id = id;
for (i = 0; i < SCI_MAX_PHYS; i++)
isci_phy_init(&ihost->phys[i], ihost, i);

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);
}

shost = scsi_host_alloc(&isci_sht, sizeof(void *));
if (!shost)
return NULL;
isci_host->shost = shost;
ihost->shost = shost;

dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
"{%s, %s, %s, %s}\n",
(is_cable_select_overridden() ? "* " : ""), isci_host->id,
lookup_cable_names(decode_cable_selection(isci_host, 3)),
lookup_cable_names(decode_cable_selection(isci_host, 2)),
lookup_cable_names(decode_cable_selection(isci_host, 1)),
lookup_cable_names(decode_cable_selection(isci_host, 0)));
(is_cable_select_overridden() ? "* " : ""), ihost->id,
lookup_cable_names(decode_cable_selection(ihost, 3)),
lookup_cable_names(decode_cable_selection(ihost, 2)),
lookup_cable_names(decode_cable_selection(ihost, 1)),
lookup_cable_names(decode_cable_selection(ihost, 0)));

err = isci_host_init(isci_host);
err = isci_host_init(ihost);
if (err)
goto err_shost;

SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
isci_host->sas_ha.core.shost = shost;
SHOST_TO_SAS_HA(shost) = &ihost->sas_ha;
ihost->sas_ha.core.shost = shost;
shost->transportt = isci_transport_template;

shost->max_id = ~0;
Expand All @@ -439,11 +604,11 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
if (err)
goto err_shost;

err = isci_register_sas_ha(isci_host);
err = isci_register_sas_ha(ihost);
if (err)
goto err_shost_remove;

return isci_host;
return ihost;

err_shost_remove:
scsi_remove_host(shost);
Expand Down
12 changes: 0 additions & 12 deletions drivers/scsi/isci/probe_roms.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
return rom;
}

enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
struct isci_orom *orom, int scu_index)
{
/* check for valid inputs */
if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS ||
scu_index > orom->hdr.num_elements || !oem)
return -EINVAL;

*oem = orom->ctrl[scu_index];
return 0;
}

struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
{
struct isci_orom *orom = NULL, *data;
Expand Down
2 changes: 0 additions & 2 deletions drivers/scsi/isci/probe_roms.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version);

struct isci_orom;
struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
struct isci_orom *orom, int scu_index);
struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
struct isci_orom *isci_get_efi_var(struct pci_dev *pdev);

Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/isci/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost,
if (idx == 0) {
offset = (void *) &ireq->tc->sgl_pair_ab -
(void *) &ihost->task_context_table[0];
return ihost->task_context_dma + offset;
return ihost->tc_dma + offset;
} else if (idx == 1) {
offset = (void *) &ireq->tc->sgl_pair_cd -
(void *) &ihost->task_context_table[0];
return ihost->task_context_dma + offset;
return ihost->tc_dma + offset;
}

return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]);
Expand Down
Loading

0 comments on commit abec912

Please sign in to comment.