isci: preallocate remote devices
[deliverable/linux.git] / drivers / scsi / isci / host.c
index dbdc3bab9ca3d73bb32078ea4964535c77888a5e..ae5d4602207354cabb124e85409197f3bdf60871 100644 (file)
@@ -78,18 +78,35 @@ irqreturn_t isci_intx_isr(int vec, void *data)
        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,
@@ -113,32 +130,18 @@ int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
        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;
 
 }
@@ -150,8 +153,11 @@ void isci_host_scan_start(struct Scsi_Host *shost)
        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)
@@ -339,75 +345,19 @@ void isci_host_deinit(struct isci_host *ihost)
 
                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)
@@ -426,32 +376,24 @@ static void __iomem *smu_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;
@@ -471,8 +413,7 @@ int isci_host_init(struct isci_host *isci_host)
                        "%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;
@@ -482,118 +423,77 @@ int isci_host_init(struct isci_host *isci_host)
         * 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
@@ -605,40 +505,22 @@ int isci_host_init(struct isci_host *isci_host)
                                               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;
 }
This page took 0.029918 seconds and 5 git commands to generate.