From: Dan Williams Date: Fri, 13 Apr 2012 18:04:17 +0000 (-0700) Subject: merge: libsas devel rnc-devel fixes X-Git-Tag: next-20120417~47^2 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=475448adcd1e66ce3af1dc97c9c6a25f2d4b9662;p=karo-tx-linux.git merge: libsas devel rnc-devel fixes --- 475448adcd1e66ce3af1dc97c9c6a25f2d4b9662 diff --cc drivers/scsi/isci/host.c index e3cf3832c5b6,2bafb5513cf4,f26ff0f5327d,d4bf9c12ecd4..bc8981ed02b3 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@@@@ -1083,107 -1085,107 -1100,15 -1082,107 +1111,15 @@@@@ void ireq_done(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; -- - struct list_head errored_request_list; -- - struct list_head *current_position; -- - struct list_head *next_position; -- - struct isci_request *request; -- - struct isci_request *next_request; -- - struct sas_task *task; u16 active; -- - INIT_LIST_HEAD(&completed_request_list); -- - INIT_LIST_HEAD(&errored_request_list); -- - spin_lock_irq(&ihost->scic_lock); -- - sci_controller_completion_handler(ihost); -- - -- - /* Take the lists of completed I/Os from the host. */ -- - -- - list_splice_init(&ihost->requests_to_complete, -- - &completed_request_list); -- - -- - /* Take the list of errored I/Os from the host. */ -- - list_splice_init(&ihost->requests_to_errorback, -- - &errored_request_list); -- - spin_unlock_irq(&ihost->scic_lock); -- - /* Process any completions in the lists. */ -- - list_for_each_safe(current_position, next_position, -- - &completed_request_list) { -- - -- - request = list_entry(current_position, struct isci_request, -- - completed_node); -- - task = isci_request_access_task(request); -- - -- - /* Normal notification (task_done) */ -- - dev_dbg(&ihost->pdev->dev, -- - "%s: Normal - request/task = %p/%p\n", -- - __func__, -- - request, -- - task); -- - -- - /* Return the task to libsas */ -- - if (task != NULL) { -- - -- - task->lldd_task = NULL; -- - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { -- - -- - /* If the task is already in the abort path, -- - * the task_done callback cannot be called. -- - */ -- - task->task_done(task); -- - } -- - } -- - -- - spin_lock_irq(&ihost->scic_lock); -- - isci_free_tag(ihost, request->io_tag); -- - spin_unlock_irq(&ihost->scic_lock); -- - } -- - list_for_each_entry_safe(request, next_request, &errored_request_list, -- - completed_node) { -- - -- - task = isci_request_access_task(request); -- - -- - /* Use sas_task_abort */ -- - dev_warn(&ihost->pdev->dev, -- - "%s: Error - request/task = %p/%p\n", -- - __func__, -- - request, -- - task); -- - -- - if (task != NULL) { -- - -- - /* Put the task into the abort path if it's not there -- - * already. -- - */ -- - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) -- - sas_task_abort(task); -- - -- - } else { -- - /* This is a case where the request has completed with a -- - * status such that it needed further target servicing, -- - * but the sas_task reference has already been removed -- - * from the request. Since it was errored, it was not -- - * being aborted, so there is nothing to do except free -- - * it. -- - */ -- - -- - spin_lock_irq(&ihost->scic_lock); -- - /* Remove the request from the remote device's list -- - * of pending requests. -- - */ -- - list_del_init(&request->dev_node); -- - isci_free_tag(ihost, request->io_tag); -- - spin_unlock_irq(&ihost->scic_lock); -- - } -- - } -- - /* the coalesence timeout doubles at each encoding step, so * update it based on the ilog2 value of the outstanding requests */ @@@@@ -2467,11 -2330,34 -2248,33 -2466,11 +2264,33 @@@@@ static int sci_controller_dma_alloc(str 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; @@@@@ -2492,22 -2389,22 -2306,20 -2491,22 +2322,22 @@@@@ 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->state_lock); - - spin_lock_init(&ihost->scic_lock); - - init_waitqueue_head(&ihost->eventq); - - - - isci_host_change_state(ihost, isci_starting); - - - - status = sci_controller_construct(ihost, scu_base(ihost), - - smu_base(ihost)); + ++ spin_lock_irq(&ihost->scic_lock); + + status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost)); + ++ spin_unlock_irq(&ihost->scic_lock); if (status != SCI_SUCCESS) { dev_err(&ihost->pdev->dev, "%s: sci_controller_construct failed - status = %x\n", @@@@@ -2867,22 -2692,22 -2607,26 -2866,22 +2625,26 @@@@@ enum sci_status sci_controller_terminat enum sci_status status; if (ihost->sm.current_state_id != SCIC_READY) { - - dev_warn(&ihost->pdev->dev, - - "invalid state to terminate request\n"); + + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } -- - status = sci_io_request_terminate(ireq); -- - if (status != SCI_SUCCESS) -- - return status; -- - /* -- - * Utilize the original post context command and or in the POST_TC_ABORT -- - * request sub-type. -- - */ -- - sci_controller_post_request(ihost, -- - ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); -- - return SCI_SUCCESS; ++ + dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n", ++ + __func__, status, ireq, ireq->flags); ++ + ++ + if ((status == SCI_SUCCESS) && ++ + !test_bit(IREQ_PENDING_ABORT, &ireq->flags) && ++ + !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) { ++ + /* Utilize the original post context command and or in the ++ + * POST_TC_ABORT request sub-type. ++ + */ ++ + sci_controller_post_request( ++ + ihost, ireq->post_context | ++ + SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); ++ + } ++ + return status; } /** diff --cc drivers/scsi/isci/host.h index adbad69d1069,bcd556f2c368,a8cc280815e0,adbad69d1069..4911310a38f5 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@@@@ -190,17 -197,15 -195,13 -190,17 +197,13 @@@@@ struct isci_host struct asd_sas_port sas_ports[SCI_MAX_PORTS]; struct sas_ha_struct sas_ha; - - spinlock_t state_lock; struct pci_dev *pdev; - - enum isci_status status; #define IHOST_START_PENDING 0 #define IHOST_STOP_PENDING 1 + ++ #define IHOST_IRQ_ENABLED 2 unsigned long flags; wait_queue_head_t eventq; - -- struct Scsi_Host *shost; struct tasklet_struct completion_tasklet; -- - struct list_head requests_to_complete; -- - struct list_head requests_to_errorback; spinlock_t scic_lock; struct isci_request *reqs[SCI_MAX_IO_REQUESTS]; struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES]; @@@@@ -512,29 -474,13 -470,13 -512,29 +477,14 @@@@@ void isci_host_start(struct Scsi_Host * u16 isci_alloc_tag(struct isci_host *ihost); enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag); void isci_tci_free(struct isci_host *ihost, u16 tci); ++ +void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task); 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); + +bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost); + ++void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status); enum sci_status sci_controller_start_io( struct isci_host *ihost, diff --cc drivers/scsi/isci/init.c index a98280d03e96,2c9d6eaab32f,5ae27fb0693f,bc6cf8886312..8e562c7dc9fa --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@@@@ -400,23 -399,187 -400,185 -397,23 +399,184 @@@@@ static int isci_setup_interrupts(struc 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; - - isci_host->pdev = pdev; - - isci_host->id = id; + + 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; + + } + + + + 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", diff --cc drivers/scsi/isci/request.c index ab18ee0fe246,3384ead4be86,d5c80ad87b53,2def1e3960f6..7a0431c73493 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@@@@ -3215,10 -3215,9 -3125,15 -3215,10 +3125,15 @@@@@ enum sci_status sci_task_request_constr /* Build the common part of the request */ sci_general_request_construct(ihost, idev, ireq); - - if (dev->dev_type == SAS_END_DEV || - - dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { + + if (dev->dev_type == SAS_END_DEV || dev_is_sata(dev)) { set_bit(IREQ_TMF, &ireq->flags); memset(ireq->tc, 0, sizeof(struct scu_task_context)); ++ + ++ + /* Set the protocol indicator. */ ++ + if (dev_is_sata(dev)) ++ + ireq->protocol = SAS_PROTOCOL_STP; ++ + else ++ + ireq->protocol = SAS_PROTOCOL_SSP; } else status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;