struct pci_dev *pdev = data;
struct isci_host *ihost;
irqreturn_t ret = IRQ_NONE;
+ int i;
- for_each_isci_host(ihost, pdev) {
+ for_each_isci_host(i, ihost, pdev) {
struct scic_sds_controller *scic = ihost->core_controller;
if (scic_sds_controller_isr(scic)) {
tasklet_schedule(&ihost->completion_tasklet);
ret = IRQ_HANDLED;
+ } else if (scic_sds_controller_error_isr(scic)) {
+ spin_lock(&ihost->scic_lock);
+ scic_sds_controller_error_handler(scic);
+ spin_unlock(&ihost->scic_lock);
+ ret = IRQ_HANDLED;
}
}
+
return ret;
}
+irqreturn_t isci_error_isr(int vec, void *data)
+{
+ struct isci_host *ihost = data;
+ struct scic_sds_controller *scic = ihost->core_controller;
+
+ if (scic_sds_controller_error_isr(scic))
+ scic_sds_controller_error_handler(scic);
+
+ return IRQ_HANDLED;
+}
/**
* isci_host_start_complete() - This function is called by the core library,
{
struct isci_host *ihost = isci_host_from_sas_ha(SHOST_TO_SAS_HA(shost));
- /**
- * check interrupt_handler's status and call completion_handler if true,
- * link_up events should be coming from the scu core lib, as phy's come
- * online. for each link_up from the core, call
- * get_received_identify_address_frame, copy the frame into the
- * sas_phy object and call libsas notify_port_event(PORTE_BYTES_DMAED).
- * continue to return zero from thee scan_finished routine until
- * the scic_cb_controller_start_complete() call comes from the core.
- **/
- if (scic_sds_controller_isr(ihost->core_controller))
- scic_sds_controller_completion_handler(ihost->core_controller);
-
- if (test_bit(IHOST_START_PENDING, &ihost->flags) && time < HZ*10) {
- dev_dbg(&ihost->pdev->dev,
- "%s: ihost->status = %d, time = %ld\n",
- __func__, isci_host_get_state(ihost), time);
+ if (test_bit(IHOST_START_PENDING, &ihost->flags))
return 0;
- }
+ /* todo: use sas_flush_discovery once it is upstream */
+ scsi_flush_work(shost);
+
+ scsi_flush_work(shost);
dev_dbg(&ihost->pdev->dev,
"%s: ihost->status = %d, time = %ld\n",
__func__, isci_host_get_state(ihost), time);
- scic_controller_enable_interrupts(ihost->core_controller);
-
return 1;
}
unsigned long tmo = scic_controller_get_suggested_start_timeout(scic);
set_bit(IHOST_START_PENDING, &ihost->flags);
- scic_controller_disable_interrupts(ihost->core_controller);
+
+ spin_lock_irq(&ihost->scic_lock);
scic_controller_start(scic, tmo);
+ scic_controller_enable_interrupts(scic);
+ spin_unlock_irq(&ihost->scic_lock);
}
void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status)
list_for_each_entry_safe(idev, d, &port->remote_dev_list, node) {
isci_remote_device_change_state(idev, isci_stopping);
- isci_remote_device_stop(idev);
+ isci_remote_device_stop(ihost, idev);
}
}
set_bit(IHOST_STOP_PENDING, &ihost->flags);
+
+ spin_lock_irq(&ihost->scic_lock);
scic_controller_stop(scic, SCIC_CONTROLLER_STOP_TIMEOUT);
+ spin_unlock_irq(&ihost->scic_lock);
+
wait_for_stop(ihost);
scic_controller_reset(scic);
-}
-
-static int isci_verify_firmware(const struct firmware *fw,
- struct isci_firmware *isci_fw)
-{
- const u8 *tmp;
-
- if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
- return -EINVAL;
-
- tmp = fw->data;
-
- /* 12th char should be the NULL terminate for the ID string */
- if (tmp[11] != '\0')
- return -EINVAL;
-
- if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
- return -EINVAL;
-
- isci_fw->id = tmp;
- isci_fw->version = fw->data[ISCI_FW_VER_OFS];
- isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
-
- tmp = fw->data + ISCI_FW_DATA_OFS;
-
- while (*tmp != ISCI_FW_HDR_EOF) {
- switch (*tmp) {
- case ISCI_FW_HDR_PHYMASK:
- tmp++;
- isci_fw->phy_masks_size = *tmp;
- tmp++;
- isci_fw->phy_masks = (const u32 *)tmp;
- tmp += sizeof(u32) * isci_fw->phy_masks_size;
- break;
-
- case ISCI_FW_HDR_PHYGEN:
- tmp++;
- isci_fw->phy_gens_size = *tmp;
- tmp++;
- isci_fw->phy_gens = (const u32 *)tmp;
- tmp += sizeof(u32) * isci_fw->phy_gens_size;
- break;
-
- case ISCI_FW_HDR_SASADDR:
- tmp++;
- isci_fw->sas_addrs_size = *tmp;
- tmp++;
- isci_fw->sas_addrs = (const u64 *)tmp;
- tmp += sizeof(u64) * isci_fw->sas_addrs_size;
- break;
-
- default:
- pr_err("bad field in firmware binary blob\n");
- return -EINVAL;
- }
- }
-
- pr_info("isci firmware v%u.%u loaded.\n",
- isci_fw->version, isci_fw->subversion);
-
- return SCI_SUCCESS;
+ isci_timer_list_destroy(ihost);
}
static void __iomem *scu_base(struct isci_host *isci_host)
return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
}
-#define SCI_MAX_TIMER_COUNT 25
-
int isci_host_init(struct isci_host *isci_host)
{
- int err = 0;
- int index = 0;
+ int err = 0, i;
enum sci_status status;
struct scic_sds_controller *controller;
- struct scic_sds_port *scic_port;
union scic_oem_parameters scic_oem_params;
union scic_user_parameters scic_user_params;
- const struct firmware *fw = NULL;
- struct isci_firmware *isci_fw = NULL;
- INIT_LIST_HEAD(&isci_host->timer_list_struct.timers);
- isci_timer_list_construct(
- &isci_host->timer_list_struct,
- SCI_MAX_TIMER_COUNT
- );
+ isci_timer_list_construct(isci_host);
controller = scic_controller_alloc(&isci_host->pdev->dev);
if (!controller) {
- err = -ENOMEM;
- dev_err(&isci_host->pdev->dev, "%s: failed (%d)\n", __func__, err);
- goto out;
+ dev_err(&isci_host->pdev->dev,
+ "%s: failed (%d)\n",
+ __func__,
+ err);
+ return -ENOMEM;
}
isci_host->core_controller = controller;
"%s: scic_controller_construct failed - status = %x\n",
__func__,
status);
- err = -ENODEV;
- goto out;
+ return -ENODEV;
}
isci_host->sas_ha.dev = &isci_host->pdev->dev;
* set association host adapter struct in core controller.
*/
sci_object_set_association(isci_host->core_controller,
- (void *)isci_host
- );
+ (void *)isci_host);
/* grab initial values stored in the controller object for OEM and USER
* parameters */
scic_oem_parameters_get(controller, &scic_oem_params);
scic_user_parameters_get(controller, &scic_user_params);
- isci_fw = devm_kzalloc(&isci_host->pdev->dev,
- sizeof(struct isci_firmware),
- GFP_KERNEL);
- if (!isci_fw) {
- dev_warn(&isci_host->pdev->dev,
- "allocating firmware struct failed\n");
- dev_warn(&isci_host->pdev->dev,
- "Default OEM configuration being used:"
- " 4 narrow ports, and default SAS Addresses\n");
- goto set_default_params;
- }
-
- status = request_firmware(&fw, ISCI_FW_NAME, &isci_host->pdev->dev);
- if (status) {
- dev_warn(&isci_host->pdev->dev,
- "Loading firmware failed, using default values\n");
- dev_warn(&isci_host->pdev->dev,
- "Default OEM configuration being used:"
- " 4 narrow ports, and default SAS Addresses\n");
- goto set_default_params;
- }
- else {
- status = isci_verify_firmware(fw, isci_fw);
- if (status != SCI_SUCCESS) {
- dev_warn(&isci_host->pdev->dev,
- "firmware verification failed\n");
- dev_warn(&isci_host->pdev->dev,
- "Default OEM configuration being used:"
- " 4 narrow ports, and default SAS "
- "Addresses\n");
- goto set_default_params;
- }
-
- /* grab any OEM and USER parameters specified at module load */
+ if (isci_firmware) {
+ /* grab any OEM and USER parameters specified in binary blob */
status = isci_parse_oem_parameters(&scic_oem_params,
- isci_host->id, isci_fw);
+ isci_host->id,
+ isci_firmware);
if (status != SCI_SUCCESS) {
dev_warn(&isci_host->pdev->dev,
"parsing firmware oem parameters failed\n");
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
status = isci_parse_user_parameters(&scic_user_params,
- isci_host->id, isci_fw);
+ isci_host->id,
+ isci_firmware);
if (status != SCI_SUCCESS) {
dev_warn(&isci_host->pdev->dev,
"%s: isci_parse_user_parameters"
" failed\n", __func__);
- err = -EINVAL;
- goto out;
+ return -EINVAL;
+ }
+ } else {
+ status = scic_oem_parameters_set(isci_host->core_controller,
+ &scic_oem_params);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_oem_parameters_set failed\n",
+ __func__);
+ return -ENODEV;
}
- }
-
- set_default_params:
- status = scic_oem_parameters_set(isci_host->core_controller,
- &scic_oem_params
- );
- if (status != SCI_SUCCESS) {
- dev_warn(&isci_host->pdev->dev,
- "%s: scic_oem_parameters_set failed\n",
- __func__);
- err = -ENODEV;
- goto out;
+ status = scic_user_parameters_set(isci_host->core_controller,
+ &scic_user_params);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&isci_host->pdev->dev,
+ "%s: scic_user_parameters_set failed\n",
+ __func__);
+ return -ENODEV;
+ }
}
+ tasklet_init(&isci_host->completion_tasklet,
+ isci_host_completion_routine, (unsigned long)isci_host);
- status = scic_user_parameters_set(isci_host->core_controller,
- &scic_user_params
- );
+ INIT_LIST_HEAD(&(isci_host->mdl_struct_list));
- if (status != SCI_SUCCESS) {
- dev_warn(&isci_host->pdev->dev,
- "%s: scic_user_parameters_set failed\n",
- __func__);
- err = -ENODEV;
- goto out;
- }
+ INIT_LIST_HEAD(&isci_host->requests_to_complete);
+ INIT_LIST_HEAD(&isci_host->requests_to_abort);
+ spin_lock_irq(&isci_host->scic_lock);
status = scic_controller_initialize(isci_host->core_controller);
+ spin_unlock_irq(&isci_host->scic_lock);
if (status != SCI_SUCCESS) {
dev_warn(&isci_host->pdev->dev,
"%s: scic_controller_initialize failed -"
" status = 0x%x\n",
__func__, status);
- err = -ENODEV;
- goto out;
+ return -ENODEV;
}
- tasklet_init(&isci_host->completion_tasklet,
- isci_host_completion_routine, (unsigned long)isci_host);
-
- INIT_LIST_HEAD(&(isci_host->mdl_struct_list));
-
- INIT_LIST_HEAD(&isci_host->requests_to_complete);
- INIT_LIST_HEAD(&isci_host->requests_to_abort);
-
/* populate mdl with dma memory. scu_mdl_allocate_coherent() */
err = isci_host_mdl_allocate_coherent(isci_host);
-
if (err)
- goto err_out;
+ return err;
/*
* keep the pool alloc size around, will use it for a bounds checking
isci_host->dma_pool_alloc_size,
SLAB_HWCACHE_ALIGN, 0);
- if (!isci_host->dma_pool) {
- err = -ENOMEM;
- goto req_obj_err_out;
- }
-
- for (index = 0; index < SCI_MAX_PORTS; index++) {
- isci_port_init(&isci_host->isci_ports[index],
- isci_host, index);
- }
+ if (!isci_host->dma_pool)
+ return -ENOMEM;
- for (index = 0; index < SCI_MAX_PHYS; index++)
- isci_phy_init(&isci_host->phys[index], isci_host, index);
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ isci_port_init(&isci_host->isci_ports[i], isci_host, i);
- /* Why are we doing this? Is this even necessary? */
- memcpy(&isci_host->sas_addr[0], &isci_host->phys[0].sas_addr[0],
- SAS_ADDR_SIZE);
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ isci_phy_init(&isci_host->phys[i], isci_host, i);
- /* Start the ports */
- for (index = 0; index < SCI_MAX_PORTS; index++) {
+ for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
+ struct isci_remote_device *idev = idev_by_id(isci_host, i);
- scic_controller_get_port_handle(controller, index, &scic_port);
- scic_port_start(scic_port);
+ INIT_LIST_HEAD(&idev->reqs_in_process);
+ INIT_LIST_HEAD(&idev->node);
+ spin_lock_init(&idev->state_lock);
}
- goto out;
-
-/* SPB_Debug: destroy request object cache */
- req_obj_err_out:
-/* SPB_Debug: destroy remote object cache */
- err_out:
-/* SPB_Debug: undo controller init, construct and alloc, remove from parent
- * controller list. */
- out:
- if (fw)
- release_firmware(fw);
- return err;
+ return 0;
}