Adaptec SAS/SATA device driver [03/27]
This is the SAS domain discovery code. Part 1/3.
drivers/scsi/adp94xx/adp94xx_discover.c new file +2452 -0
@@ -0,0 +1,2460 @@ +#define NO_VPD_WORKAROUND +#define SMP_OVERRUN_WORKAROUND +#define SMP_UNDERRUN_WORKAROUND +/* +* Adaptec ADP94xx SAS HBA device driver for Linux. +* +* Copyright (c) 2004 Adaptec Inc. +* All rights reserved. +* +* Adapted by : Robert Tarte <[email protected]> +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions, and the following disclaimer, +* without modification. +* 2. Redistributions in binary form must reproduce at minimum a disclaimer +* substantially similar to the "NO WARRANTY" disclaimer below +* ("Disclaimer") and any redistribution must be conditioned upon +* including a substantially similar Disclaimer requirement for further +* binary redistribution. +* 3. Neither the names of the above-listed copyright holders nor the names +* of any contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* Alternatively, this software may be distributed under the terms of the +* GNU General Public License ("GPL") version 2 as published by the Free +* Software Foundation. +* +* NO WARRANTY +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGES. +* +* The source in this file is adapted from: SASDiscoverSimulation.cpp, +* from the SAS-1.1 draft, sas1r07.pdf, project T10/1601-D, +* ISO/IEC 14776-151:200x. +* +* This is an implementation of the initiator based expander discovery +* and configuration. Structure names used are equivalent to those +* referenced in the SAS document. +* Basic assumptions: +* +* 1. Change primitives will initiate a rediscovery/configuration sequence. +* 2. Table locations for SASAddresses are deterministic for a specific +* topology only, when the topology changes, the location of a SASAddress +* in an ASIC table cannot be assumed. +* 3. A complete discovery level occurs before the configuration of the +* level begins, multiple passes are required as the levels of expanders +* encountered between the initiator and the end devices is increased. +* 4. Configuration of a single expander occurs before proceeding to +* subsequent expanders attached. +* 5. The Attached structure is filled in following OOB and is available +* from the initialization routines. +* +* $Id: //depot/razor/linux/src/adp94xx_discover.c#65 $ +* + */ +#define KDB_ENABLE 0 +#define DISCOVER_DEBUG 0 + +#include "adp94xx_osm.h" +#include "adp94xx_inline.h" +#include "adp94xx_sata.h" +#if KDB_ENABLE +#include "linux/kdb.h" +#endif + +/* +* this defines the type of algorithm used for discover +*/ +#if 0 +int DiscoverAlgorithm =SAS_SIMPLE_LEVEL_DESCENT ; +#else +int DiscoverAlgorithm =SAS_UNIQUE_LEVEL_DESCENT ; +#endif + +#define ROUTE_ENTRY (expander, i, j) \ + (expander->RouteTable + \ + ((expander->num_phys * (i) * SAS_ADDR_LEN) + \ + (j) * SAS_ADDR_LEN)) + +#define DUMP_EXPANDER (s, expander) \ + asd_dump_expander((uint8_t *)__FUNCTION__, __LINE__, (s), expander) + +#define NEW_STATE (new_state) new_state(sm_contextp, new_state) + +struct state_machine asd_DiscoverySM = { + asd_DiscoverySM_Initialize, + asd_DiscoverySM_StateMachine, + asd_DiscoverySM_Finish, + asd_DiscoverySM_Abort, +ASD_STATE_DISCOVER_START +}; + +struct state_machine asd_DiscoverExpanderSM = { + asd_DiscoverExpanderSM_Initialize, + asd_DiscoverExpanderSM_StateMachine, + asd_DiscoverExpanderSM_Finish, + asd_DiscoverExpanderSM_Abort, +ASD_STATE_REPORT_AND_DISCOVER_START +}; + +struct state_machine asd_DiscoverFindBoundarySM = { + asd_DiscoverFindBoundarySM_Initialize, + asd_DiscoverFindBoundarySM_StateMachine, + asd_DiscoverFindBoundarySM_Finish, + asd_DiscoverFindBoundarySM_Abort, +ASD_STATE_FIND_BOUNDARY_START +}; + +struct state_machine asd_DiscoverConfigSetSM = { + asd_DiscoverConfigSetSM_Initialize, + asd_DiscoverConfigSetSM_StateMachine, + asd_DiscoverConfigSetSM_Finish, + asd_DiscoverConfigSetSM_Abort, +ASD_STATE_CONFIG_SET_START +}; + +struct state_machine asd_ConfigureExpanderSM = { + asd_ConfigureExpanderSM_Initialize, + asd_ConfigureExpanderSM_StateMachine, + asd_ConfigureExpanderSM_Finish, + asd_ConfigureExpanderSM_Abort, +ASD_STATE_CONFIG_EXPANDER_START +}; + +struct state_machine asd_ConfigureATA_SM = { + asd_ConfigureATA_SM_Initialize, + asd_ConfigureATA_SM_StateMachine, + asd_ConfigureATA_SM_Finish, + asd_ConfigureATA_SM_Abort, +ASD_STATE_CONFIGURE_ATA_START +}; + +struct state_machine asd_InitSATA_SM = { + asd_InitSATA_SM_Initialize, + asd_InitSATA_SM_StateMachine, + asd_InitSATA_SM_Finish, + asd_InitSATA_SM_Abort, +ASD_STATE_INIT_SATA_START +}; + +struct state_machine asd_SATA_SpinHoldSM = { + asd_SATA_SpinHoldSM_Initialize, + asd_SATA_SpinHoldSM_StateMachine, + asd_SATA_SpinHoldSM_Finish, + asd_SATA_SpinHoldSM_Abort, +ASD_STATE_SATA_SPINHOLD_START +}; + +struct state_machine asd_InitSAS_SM = { + asd_InitSAS_SM_Initialize, + asd_InitSAS_SM_StateMachine, + asd_InitSAS_SM_Finish, + asd_InitSAS_SM_Abort, +ASD_STATE_INIT_SAS_START +}; + +struct state_machine asd_InitSMP_SM = { + asd_InitSMP_SM_Initialize, + asd_InitSMP_SM_StateMachine, + asd_InitSMP_SM_Finish, + asd_InitSMP_SM_Abort, +ASD_STATE_INIT_SMP_START +}; + +extern void +asd_scb_internal_done (struct asd_softc *asd,struct scb *scb, +struct asd_done_list *dl); +extern void asd_run_device_queues (struct asd_softc *asd); + +struct asd_target *asd_discover_get_target (struct state_machine_context + *sm_contextp, +uint8_t * dest_sas_address, +struct list_head *old_discover_listp, +struct list_head *found_listp, +unsigned conn_rate, +TRANSPORT_TYPE transport_type); + +struct asd_DiscoverySM_Context ; + +static void asd_invalidate_targets (struct asd_softc *asd, +struct asd_port *port); +static void asd_validate_targets_hotplug (struct asd_softc *asd, +struct asd_port *port, +struct asd_DiscoverySM_Context *ctx); +static void asd_validate_targets_init (struct asd_softc *asd); +static void asd_apply_conn_mask (struct asd_softc *asd, +struct list_head *discover_list); +static int asd_discovery_queue_cmd (struct asd_softc *asd, +struct scb *scb,struct asd_target *targ, +struct asd_device *dev); + +#if DISCOVER_DEBUG +static void asd_dump_tree (struct asd_softc *asd,struct asd_port *port); +#endif + +void asd_print_conn_rate (unsigned conn_rate,char *s) +{ +switch (conn_rate) { +case SAS_RATE_30GBPS : +printk (" 3.0-GBPS" ); +break ; +case SAS_RATE_15GBPS : +printk (" 1.5-GBPS" ); +break ; +default : +printk (" \?\?-GBPS" ); +break ; + } +printk ("%s" , s); +} + +void asd_print_state (unsigned state,char *s) +{ +switch (state) { +case ASD_STATE_DISCOVER_START : +printk ("ASD_STATE_DISCOVER_START" ); +break ; + +case ASD_STATE_DISCOVER_ATTACHED : +printk ("ASD_STATE_DISCOVER_ATTACHED" ); +break ; + +case ASD_STATE_FIND_BOUNDARY : +printk ("ASD_STATE_FIND_BOUNDARY" ); +break ; + +case ASD_STATE_CONFIG_BOUNDARY_SET : +printk ("ASD_STATE_CONFIG_BOUNDARY_SET" ); +break ; + +case ASD_STATE_CONFIG_ATTACHED_SET : +printk ("ASD_STATE_CONFIG_ATTACHED_SET" ); +break ; + +case ASD_STATE_FINISHED : +printk ("ASD_STATE_FINISHED" ); +break ; + +case ASD_STATE_SATA_SPINHOLD : +printk ("ASD_STATE_SATA_SPINHOLD" ); +break ; + +case ASD_STATE_INIT_SATA : +printk ("ASD_STATE_INIT_SATA" ); +break ; + +case ASD_STATE_INIT_SAS : +printk ("ASD_STATE_INIT_SAS" ); +break ; + +case ASD_STATE_INIT_SMP : +printk ("ASD_STATE_INIT_SMP" ); +break ; + +case ASD_STATE_FAILED : +printk ("ASD_STATE_FAILED" ); +break ; + +case ASD_STATE_REPORT_AND_DISCOVER_START : +printk ("ASD_STATE_REPORT_AND_DISCOVER_START" ); +break ; + +case ASD_STATE_ISSUE_REPORT_GENERAL : +printk ("ASD_STATE_ISSUE_REPORT_GENERAL" ); +break ; + +case ASD_STATE_ISSUE_DISCOVER_LOOP : +printk ("ASD_STATE_ISSUE_DISCOVER_LOOP" ); +break ; + +case ASD_STATE_REPORT_AND_DISCOVER_FINISHED : +printk ("ASD_STATE_REPORT_AND_DISCOVER_FINISHED" ); +break ; + +case ASD_STATE_REPORT_AND_DISCOVER_FAILED : +printk ("ASD_STATE_REPORT_AND_DISCOVER_FAILED" ); +break ; + +case ASD_STATE_FIND_BOUNDARY_START : +printk ("ASD_STATE_FIND_BOUNDARY_START" ); +break ; + +case ASD_STATE_FIND_BOUNDARY_LOOP : +printk ("ASD_STATE_FIND_BOUNDARY_LOOP" ); +break ; + +case ASD_STATE_FIND_BOUNDARY_FINISHED : +printk ("ASD_STATE_FIND_BOUNDARY_FINISHED" ); +break ; + +case ASD_STATE_FIND_BOUNDARY_FAILED : +printk ("ASD_STATE_FIND_BOUNDARY_FAILED" ); +break ; + +case ASD_STATE_CONFIG_SET_START : +printk ("ASD_STATE_CONFIG_SET_START" ); +break ; + +case ASD_STATE_CONFIG_SET_ISSUE_DISCOVER : +printk ("ASD_STATE_CONFIG_SET_ISSUE_DISCOVER" ); +break ; + +case ASD_STATE_CONFIG_SET_CONFIGURE_EXPANDER : +printk ("ASD_STATE_CONFIG_SET_CONFIGURE_EXPANDER" ); +break ; + +case ASD_STATE_CONFIG_SET_FINISHED : +printk ("ASD_STATE_CONFIG_SET_FINISHED" ); +break ; + +case ASD_STATE_CONFIG_SET_FAILED : +printk ("ASD_STATE_CONFIG_SET_FAILED" ); +break ; + +case ASD_STATE_CONFIG_EXPANDER_START : +printk ("ASD_STATE_CONFIG_EXPANDER_START" ); +break ; + +case ASD_STATE_CONFIG_EXPANDER_ROUTE : +printk ("ASD_STATE_CONFIG_EXPANDER_ROUTE" ); +break ; + +case ASD_STATE_CONFIG_EXPANDER_ROUTE_LOOP : +printk ("ASD_STATE_CONFIG_EXPANDER_ROUTE_LOOP" ); +break ; + +case ASD_STATE_CONFIG_EXPANDER_FINISHED : +printk ("ASD_STATE_CONFIG_EXPANDER_FINISHED" ); +break ; + +case ASD_STATE_CONFIG_EXPANDER_FAILED : +printk ("ASD_STATE_CONFIG_EXPANDER_FAILED" ); +break ; + +case ASD_STATE_INIT_SATA_START : +printk ("ASD_STATE_INIT_SATA_START" ); +break ; + +case ASD_STATE_INIT_SATA_REPORT_PHY : +printk ("ASD_STATE_INIT_SATA_REPORT_PHY" ); +break ; + +case ASD_STATE_INIT_SATA_IDENTIFY : +printk ("ASD_STATE_INIT_SATA_IDENTIFY" ); +break ; + +case ASD_STATE_INIT_SATA_CONFIGURE_FEATURES : +printk ("ASD_STATE_INIT_SATA_CONFIGURE_FEATURES" ); +break ; + +case ASD_STATE_INIT_SATA_FINISHED : +printk ("ASD_STATE_INIT_SATA_FINISHED" ); +break ; + +case ASD_STATE_INIT_SATA_FAILED : +printk ("ASD_STATE_INIT_SATA_FAILED" ); +break ; + +case ASD_STATE_SATA_SPINHOLD_START : +printk ("ASD_STATE_SATA_SPINHOLD_START" ); +break ; + +case ASD_STATE_SATA_SPINHOLD_PHY_CONTROL : +printk ("ASD_STATE_SATA_SPINHOLD_PHY_CONTROL" ); +break ; + +case ASD_STATE_SATA_SPINHOLD_DISCOVER : +printk ("ASD_STATE_SATA_SPINHOLD_DISCOVER" ); +break ; + +case ASD_STATE_SATA_SPINHOLD_FINISHED : +printk ("ASD_STATE_SATA_SPINHOLD_FINISHED" ); +break ; + +case ASD_STATE_SATA_SPINHOLD_FAILED : +printk ("ASD_STATE_SATA_SPINHOLD_FAILED" ); +break ; + +case ASD_STATE_INIT_SAS_START : +printk ("ASD_STATE_INIT_SAS_START" ); +break ; + +case ASD_STATE_INIT_SAS_INQUIRY : +printk ("ASD_STATE_INIT_SAS_INQUIRY" ); +break ; + +case ASD_STATE_INIT_SAS_GET_DEVICE_ID : +printk ("ASD_STATE_INIT_SAS_GET_DEVICE_ID" ); +break ; + +case ASD_STATE_INIT_SAS_GET_SERIAL_NUMBER : +printk ("ASD_STATE_INIT_SAS_GET_SERIAL_NUMBER" ); +break ; + +case ASD_STATE_INIT_SAS_ISSUE_REPORT_LUNS : +printk ("ASD_STATE_INIT_SAS_ISSUE_REPORT_LUNS" ); +break ; + +case ASD_STATE_INIT_SAS_GET_PORT_CONTROL : +printk ("ASD_STATE_INIT_SAS_GET_PORT_CONTROL" ); +break ; + +case ASD_STATE_INIT_SAS_FINISHED : +printk ("ASD_STATE_INIT_SAS_FINISHED" ); +break ; + +case ASD_STATE_INIT_SAS_FAILED : +printk ("ASD_STATE_INIT_SAS_FAILED" ); +break ; + +case ASD_STATE_INIT_SMP_START : +printk ("ASD_STATE_INIT_SMP_START" ); +break ; + +case ASD_STATE_INIT_SMP_REPORT_MANUFACTURER_INFO : +printk ("ASD_STATE_INIT_SMP_REPORT_MANUFACTURER_INFO" ); +break ; + +case ASD_STATE_INIT_SMP_FINISHED : +printk ("ASD_STATE_INIT_SMP_FINISHED" ); +break ; + +case ASD_STATE_INIT_SMP_FAILED : +printk ("ASD_STATE_INIT_SMP_FAILED" ); +break ; + +case ASD_STATE_CONFIGURE_ATA_START : +printk ("ASD_STATE_CONFIGURE_ATA_START" ); +break ; + +case ASD_STATE_CONFIGURE_ATA_FEATURES : +printk ("ASD_STATE_CONFIGURE_ATA_FEATURES" ); +break ; + +case ASD_STATE_CONFIGURE_ATA_FINISHED : +printk ("ASD_STATE_CONFIGURE_ATA_FINISHED" ); +break ; + +case ASD_STATE_CONFIGURE_ATA_FAILED : +printk ("ASD_STATE_CONFIGURE_ATA_FAILED" ); +break ; + +default : +printk ("[0x%04x]" , state); +break ; + } + +printk ("%s" , s); +} + +void SM_new_state (struct state_machine_context *sm_contextp,unsigned new_state) +{ +struct state_information *state_infop; + +SETUP_STATE (sm_contextp); + +//printk("[%d]===== ", sm_contextp->state_stack_top); +//asd_print_state(state_infop->current_state, " -> "); +//asd_print_state(new_state, "\n"); + +if ((new_state & state_infop->state_machine_p->first_state) != + state_infop->state_machine_p->first_state) { + +printk ("illegal state 0x%x\n" , new_state); +printk ("[%d]===== " , sm_contextp->state_stack_top); +asd_print_state (state_infop->current_state," -> " ); +asd_print_state (new_state,"\n" ); + } + + state_infop->current_state = new_state; +} + +DISCOVER_RESULTS +asd_run_state_machine (struct state_machine_context *sm_contextp) +{ +struct state_information *state_infop; +DISCOVER_RESULTS results; + +SETUP_STATE (sm_contextp); + + results = state_infop->state_machine_p->state_machine (sm_contextp); + +while (results !=DISCOVER_OK ) { + + state_infop = + &sm_contextp->state_stack[sm_contextp->state_stack_top]; + +if (results ==DISCOVER_FAILED ) { +printk ("State Machine Failure: " ); +asd_print_state (state_infop->current_state,"\n" ); + } + +if ((results ==DISCOVER_FINISHED ) || + (results ==DISCOVER_FAILED )) { + + state_infop->state_machine_p->finish (sm_contextp, + results); + +if (sm_contextp->state_stack_top ==0 ) { + +//printk("nothing on stack\n"); + +return DISCOVER_OK ; + } + +POP_STATE (sm_contextp); + } + + results = + state_infop->state_machine_p->state_machine (sm_contextp); + } + +return results; +} + +#define ASD_PUSH_STATE_MACHINE (sm_contextp, state_machine_p, arg) \ + asd_push_state_machine(sm_contextp, #state_machine_p, \ + state_machine_p, arg) + +DISCOVER_RESULTS +asd_push_state_machine (struct state_machine_context * sm_contextp, +char *s, +struct state_machine * state_machine_p,void *arg) +{ +struct state_information *state_infop; +DISCOVER_RESULTS results; + +#if 0 +printk ("\n\n%s:=====================================================\n" , + __FUNCTION__); +printk ("%s: %s ============================\n" , __FUNCTION__, s); +printk ("%s:=====================================================\n\n\n" , + __FUNCTION__); +#endif + + sm_contextp->state_stack_top++; + +SETUP_STATE (sm_contextp); + + state_infop->current_state = state_machine_p->first_state; + state_infop->stack_top =0 ; + state_infop->state_machine_p = state_machine_p; + + results = state_machine_p->initialize (sm_contextp, arg); + +if (results !=DISCOVER_CONTINUE ) { + + state_infop->state_machine_p->finish (sm_contextp, results); + +if (sm_contextp->state_stack_top ==0 ) { + +//printk("nothing on stack\n"); + +return results; + } + +POP_STATE (sm_contextp); + } + +return results; +} + +void asd_abort_state_machine (struct state_machine_context *sm_contextp) +{ +struct state_information *state_infop; + +SETUP_STATE (sm_contextp); + +while (sm_contextp->state_stack_top !=-1 ) { + + state_infop = + &sm_contextp->state_stack[sm_contextp->state_stack_top]; + + state_infop->state_machine_p->abort (sm_contextp); + +POP_STATE (sm_contextp); + } +} + +void +asd_dump_expander (char *function, +unsigned line,char *string,struct asd_target *expander) +{ +unsigned i; +struct Discover *discover; + +printk ("||||||||||| - %s - %s:%d:\n" , string, function, line); +printk ("||||||||||| - %0llx - " , + *((uint64_t *) expander->ddb_profile.sas_addr)); + +if (expander->management_type ==ASD_DEVICE_END ) { +printk ("\n" ); +return ; + } + +printk ("num_phys %d\n" , expander->num_phys); + +for (i =0 ; i < expander->num_phys; i++) { + + discover = &(expander->Phy[i].Result); + +printk ("||||||||||| - phy %d attached to %0llx\n" , i, + *((uint64_t *) discover->AttachedSASAddress)); + } +} + +void asd_dump_expander_list (char *s,struct list_head *discover_listp) +{ +struct asd_target *target; +struct asd_target *parent; + +printk ("----- %s\n" , s); + +list_for_each_entry (target, discover_listp, all_domain_targets) { + +DUMP_EXPANDER ("target:" , target); + +printk (" %0llx" , *((uint64_t *) target->ddb_profile.sas_addr)); + +asd_print_conn_rate (target->ddb_profile.conn_rate,"\n" ); + +for (parent = target->parent; parent !=NULL ; + parent = parent->parent) { + +printk ("\t:%0llx\n" , + *((uint64_t *) parent->ddb_profile.sas_addr)); + } + } + +printk ("-----\n" ); +} + +void +asd_discover_wakeup_state_machine (struct state_machine_context *sm_contextp) +{ +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + discover_contextp->port->events |=ASD_DISCOVERY_EVENT ; + +asd_wakeup_sem (&discover_contextp->asd->platform_data->discovery_sem); +} + +DISCOVER_RESULTS +asd_ssp_request (struct state_machine_context *sm_contextp, +struct asd_target *target, +uint8_t * command, +unsigned command_len, +dma_addr_t buf_busaddr,unsigned buffer_len,unsigned direction) +{ +struct asd_ssp_task_hscb *ssp_hscb; +unsigned long flags; +struct scb *scb; +struct sg_element *sg; +int error; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_lock (discover_contextp->asd, &flags); + +/* +* Get an scb to use. +*/ +if ((scb =asd_hwi_get_scb (discover_contextp->asd,1 )) ==NULL ) { +// TODO - fix this + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + + scb->flags |=SCB_INTERNAL ; + + scb->platform_data->targ = target; + + scb->platform_data->dev =NULL ; + +list_add_tail (&scb->owner_links, + &discover_contextp->asd->platform_data->pending_os_scbs); + + ssp_hscb = &scb->hscb->ssp_task; + + ssp_hscb->header.opcode =SCB_INITIATE_SSP_TASK ; + +asd_build_sas_header (target, ssp_hscb); + + ssp_hscb->protocol_conn_rate |=PROTOCOL_TYPE_SSP ; + + ssp_hscb->data_dir_flags |= direction; + + ssp_hscb->xfer_len =asd_htole32 (buffer_len); + +memcpy (ssp_hscb->cdb, command, command_len); + +memset (&ssp_hscb->cdb[command_len],0 , +SCB_EMBEDDED_CDB_SIZE - command_len); + + sg = scb->sg_list; + + scb->platform_data->buf_busaddr = buf_busaddr; + + error =asd_sg_setup (sg, buf_busaddr, buffer_len,/*last */ 1 ); + +if (error !=0 ) { +return DISCOVER_FAILED ; + } + +memcpy (ssp_hscb->sg_elements, scb->sg_list,sizeof (*sg)); + + scb->sg_count =1 ; + +asd_push_post_stack (discover_contextp->asd, scb, (void *)sm_contextp, + asd_ssp_request_done); + + scb->flags |=SCB_ACTIVE ; + +asd_hwi_post_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_OK ; +} + +void +asd_ssp_request_done (struct asd_softc *asd, +struct scb *scb,struct asd_done_list *done_listp) +{ +struct state_machine_context *sm_contextp; +struct discover_context *discover_contextp; + + sm_contextp = (struct state_machine_context *)scb->io_ctx; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_scb_internal_done (asd, scb, done_listp); + + discover_contextp->resid_len =0 ; + +/* +* TODO: need better return value here +*/ +switch (done_listp->opcode) { +case TASK_COMP_WO_ERR : + discover_contextp->openStatus =OPEN_ACCEPT ; +break ; + +case TASK_COMP_W_UNDERRUN : + discover_contextp->openStatus =OPEN_ACCEPT ; + discover_contextp->resid_len = +asd_le32toh (done_listp->stat_blk.data.res_len); +break ; + +case TASK_F_W_OPEN_REJECT : +printk ("%s:%d: reject abandon_open %x reason %x\n" , + __FUNCTION__, __LINE__, + done_listp->stat_blk.open_reject.abandon_open, + done_listp->stat_blk.open_reject.reason); +break ; + +case SSP_TASK_COMP_W_RESP : +default : +#if 0 +printk ("%s:%d opcode=0x%x\n" , __FUNCTION__, __LINE__, + done_listp->opcode); +#endif +/* +* TODO: need better return value here +*/ + discover_contextp->openStatus =OPEN_REJECT_BAD_DESTINATION ; +break ; + } + + sm_contextp->wakeup_state_machine (sm_contextp); +} + +DISCOVER_RESULTS +asd_smp_request (struct state_machine_context *sm_contextp, +struct asd_target *target, +unsigned request_length,unsigned response_length) +{ +struct asd_smp_task_hscb *smp_hscb; +unsigned long flags; +struct scb *scb; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_lock (discover_contextp->asd, &flags); + +/* +* Get an scb to use. +*/ +if ((scb =asd_hwi_get_scb (discover_contextp->asd,1 )) ==NULL ) { +// TODO - fix this + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + + scb->flags |=SCB_INTERNAL ; + scb->platform_data->dev =NULL ; + scb->platform_data->targ = target; + +list_add_tail (&scb->owner_links, + &discover_contextp->asd->platform_data->pending_os_scbs); + + smp_hscb = &scb->hscb->smp_task; + + smp_hscb->header.opcode =SCB_INITIATE_SMP_TASK ; + smp_hscb->protocol_conn_rate = target->ddb_profile.conn_rate; + + smp_hscb->smp_req_busaddr = discover_contextp->SMPRequestBusAddr; + smp_hscb->smp_req_size = request_length; + + smp_hscb->smp_req_ds =0 ; + smp_hscb->sister_scb =0xffff ; + smp_hscb->conn_handle = target->ddb_profile.conn_handle; + + smp_hscb->smp_resp_busaddr = discover_contextp->SMPResponseBusAddr; + smp_hscb->smp_resp_size = response_length; + + smp_hscb->smp_resp_ds =0 ; + +asd_push_post_stack (discover_contextp->asd, scb, (void *)sm_contextp, + asd_smp_request_done); + + scb->flags |=SCB_ACTIVE ; + +asd_hwi_post_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_OK ; +} + +void +asd_smp_request_done (struct asd_softc *asd, +struct scb *scb,struct asd_done_list *done_listp) +{ +struct state_machine_context *sm_contextp; +struct discover_context *discover_contextp; + + sm_contextp = (struct state_machine_context *)scb->io_ctx; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_scb_internal_done (asd, scb, done_listp); + +#if 0 +if (done_listp->opcode !=TASK_COMP_WO_ERR ) { +printk ("%s:%d: opcode = 0x%x\n" , __FUNCTION__, __LINE__, + done_listp->opcode); + } +#endif + + discover_contextp->resid_len =0 ; + +/* +* TODO: need better return value here +*/ +switch (done_listp->opcode) { +case TASK_COMP_WO_ERR : + discover_contextp->openStatus =OPEN_ACCEPT ; +break ; +#ifdef SMP_UNDERRUN_WORKAROUND +case TASK_COMP_W_UNDERRUN : +printk ("Ignoring UNDERRUN condition on SMP request\n" ); + discover_contextp->openStatus =OPEN_ACCEPT ; + discover_contextp->resid_len = +asd_le32toh (done_listp->stat_blk.data.res_len); +break ; +#endif +#ifdef SMP_OVERRUN_WORKAROUND +case TASK_COMP_W_OVERRUN : +/* +* This wasn't fixed in B0, so it will be investigated more. +*/ +//printk("Ignoring OVERRUN condition on SMP request - "); +//printk("should be fixed in B0\n"); + discover_contextp->openStatus =OPEN_ACCEPT ; +break ; +#endif +case TASK_F_W_SMPRSP_TO : +case TASK_F_W_SMP_XMTRCV_ERR : + discover_contextp->openStatus =OPEN_REJECT_BAD_DESTINATION ; +break ; +case TASK_ABORTED_BY_ITNL_EXP : +switch (done_listp->stat_blk.itnl_exp.reason) { +case TASK_F_W_PHY_DOWN : +case TASK_F_W_BREAK_RCVD : +case TASK_F_W_OPEN_TO : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +break ; + +case TASK_F_W_OPEN_REJECT : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +#if 0 + discover_contextp->openStatus = +OPEN_REJECT_RATE_NOT_SUPPORTED ; + discover_contextp->openStatus = +OPEN_REJECT_NO_DESTINATION ; + discover_contextp->openStatus = +OPEN_REJECT_PATHWAY_BLOCKED ; + discover_contextp->openStatus = +OPEN_REJECT_PROTOCOL_NOT_SUPPORTED ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_ABANDON ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_CONTINUE ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_INITIALIZE ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_STOP ; + discover_contextp->openStatus =OPEN_REJECT_RETRY ; + discover_contextp->openStatus = +OPEN_REJECT_STP_RESOURCES_BUSY ; + discover_contextp->openStatus = +OPEN_REJECT_WRONG_DESTINATION ; +#endif +break ; + } +break ; +case TASK_CLEARED : +/* Aborted command. Status needs to be changed .... */ +break ; +default : + discover_contextp->openStatus =OPEN_REJECT_BAD_DESTINATION ; +break ; + } + + sm_contextp->wakeup_state_machine (sm_contextp); +} + +DISCOVER_RESULTS +asd_sata_identify_request (struct state_machine_context *sm_contextp, +struct asd_target *target) +{ +unsigned long flags; +struct scb *scb; +struct discover_context *discover_contextp; +struct asd_target *old_target; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_lock (discover_contextp->asd, &flags); + +/* +* Get an scb to use. +*/ +if ((scb =asd_hwi_get_scb (discover_contextp->asd,1 )) ==NULL ) { +// TODO - fix this + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + + scb->flags |=SCB_INTERNAL ; + scb->platform_data->dev =NULL ; + +asd_push_post_stack (discover_contextp->asd, scb, (void *)sm_contextp, + asd_sata_identify_request_done); + +list_add_tail (&scb->owner_links, + &discover_contextp->asd->platform_data->pending_os_scbs); + +if (asd_sata_identify_build (discover_contextp->asd, target, scb) !=0 ) { + +asd_hwi_free_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + + scb->flags |=SCB_ACTIVE ; + +/* +* We want to use the flow control of the device queue if possible. +* Look through the old/new discover list for this target. +* If target exists, see if device exists. +*/ + old_target =asd_find_target (discover_contextp->asd->old_discover_listp, + target->ddb_profile.sas_addr); + +if (old_target ==NULL ) { + old_target = +asd_find_target (discover_contextp->asd->discover_listp, + target->ddb_profile.sas_addr); + } + +/* +* sata devices should have only one lun, check lun 0. +*/ +if (old_target !=NULL ) { + +if (old_target->devices[0 ] !=NULL ) { + + scb->platform_data->dev = target->devices[0 ]; + +asd_unlock (discover_contextp->asd, &flags); + +if ((asd_discovery_queue_cmd (discover_contextp->asd, + scb, old_target, + old_target->devices[0 ]))) { + +asd_hwi_free_scb (discover_contextp->asd, scb); + +return DISCOVER_FAILED ; + } + +return DISCOVER_OK ; + } + } + +asd_hwi_post_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_OK ; +} + +static int +asd_discovery_queue_cmd (struct asd_softc *asd, +struct scb *scb,struct asd_target *targ, +struct asd_device *dev) +{ +struct scsi_cmnd *cmd; +u_long flags; + +if ((cmd =asd_alloc_mem (sizeof (struct scsi_cmnd ),GFP_ATOMIC )) ==NULL ) { +return -ENOMEM ; + } + +/* indicate its discovery SM generated scsi_cmnd */ + cmd->sc_magic =ASD_CSMI_COMMAND ; + +/* stick SCB into scsi_cmnd */ + cmd->host_scribble = (unsigned char *)scb; + +asd_lock (asd, &flags); +list_add_tail (&((union asd_cmd *)cmd)->acmd_links, &dev->busyq); +if ((dev->flags &ASD_DEV_ON_RUN_LIST ) ==0 ) { +list_add_tail (&dev->links, &asd->platform_data->device_runq); + dev->flags |=ASD_DEV_ON_RUN_LIST ; + +asd_run_device_queues (asd); + } +asd_unlock (asd, &flags); + +return 0 ; +} + +void +asd_sata_identify_request_done (struct asd_softc *asd, +struct scb *scb, +struct asd_done_list *done_listp) +{ +struct state_machine_context *sm_contextp; +struct discover_context *discover_contextp; + + sm_contextp = (struct state_machine_context *)scb->io_ctx; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +/* +* If this is not NULL, scb was sent via device queue. +*/ +if (scb->platform_data->dev) { + scb->platform_data->dev->active--; + scb->platform_data->dev->openings++; + scb->platform_data->dev->commands_issued--; + } + +asd_scb_internal_done (asd, scb, done_listp); + + discover_contextp->resid_len =0 ; + +/* +* TODO: need better return value here +*/ +switch (done_listp->opcode) { +case TASK_COMP_WO_ERR : + discover_contextp->openStatus =OPEN_ACCEPT ; +break ; + +case TASK_COMP_W_UNDERRUN : + discover_contextp->openStatus =OPEN_ACCEPT ; + discover_contextp->resid_len = +asd_le32toh (done_listp->stat_blk.data.res_len); +break ; + +case TASK_ABORTED_BY_ITNL_EXP : +switch (done_listp->stat_blk.itnl_exp.reason) { +case TASK_F_W_PHY_DOWN : +case TASK_F_W_BREAK_RCVD : +case TASK_F_W_OPEN_TO : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +break ; + +case TASK_F_W_OPEN_REJECT : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +#if 0 + discover_contextp->openStatus = +OPEN_REJECT_RATE_NOT_SUPPORTED ; + discover_contextp->openStatus = +OPEN_REJECT_NO_DESTINATION ; + discover_contextp->openStatus = +OPEN_REJECT_PATHWAY_BLOCKED ; + discover_contextp->openStatus = +OPEN_REJECT_PROTOCOL_NOT_SUPPORTED ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_ABANDON ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_CONTINUE ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_INITIALIZE ; + discover_contextp->openStatus = +OPEN_REJECT_RESERVE_STOP ; + discover_contextp->openStatus =OPEN_REJECT_RETRY ; + discover_contextp->openStatus = +OPEN_REJECT_STP_RESOURCES_BUSY ; + discover_contextp->openStatus = +OPEN_REJECT_WRONG_DESTINATION ; +#endif +break ; + } +break ; +case TASK_CLEARED : +/* Aborted command. Status needs to be changed .... */ +break ; +default : + discover_contextp->openStatus =OPEN_REJECT_BAD_DESTINATION ; +break ; + } + + sm_contextp->wakeup_state_machine (sm_contextp); +} + +DISCOVER_RESULTS +asd_sata_configure_features (struct state_machine_context *sm_contextp, +struct asd_target *target, +uint8_t feature,uint8_t sector_count) +{ +unsigned long flags; +struct scb *scb; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_lock (discover_contextp->asd, &flags); + +/* +* Get an scb to use. +*/ +if ((scb =asd_hwi_get_scb (discover_contextp->asd,1 )) ==NULL ) { +// TODO - fix this + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + + scb->flags |=SCB_INTERNAL ; + scb->platform_data->dev =NULL ; + scb->platform_data->targ = target; + +list_add_tail (&scb->owner_links, + &discover_contextp->asd->platform_data->pending_os_scbs); + +if (asd_sata_set_features_build (discover_contextp->asd, target, scb, + feature, sector_count) !=0 ) { + +asd_hwi_free_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_FAILED ; + } + +asd_push_post_stack (discover_contextp->asd, scb, (void *)sm_contextp, + asd_sata_configure_features_done); + + scb->flags |=SCB_ACTIVE ; + +asd_hwi_post_scb (discover_contextp->asd, scb); + +asd_unlock (discover_contextp->asd, &flags); + +return DISCOVER_OK ; +} + +void +asd_sata_configure_features_done (struct asd_softc *asd, +struct scb *scb, +struct asd_done_list *done_listp) +{ +struct state_machine_context *sm_contextp; +struct discover_context *discover_contextp; + + sm_contextp = (struct state_machine_context *)scb->io_ctx; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +asd_scb_internal_done (asd, scb, done_listp); + + discover_contextp->resid_len =0 ; + +/* +* TODO: need better return value here +*/ +switch (done_listp->opcode) { +case TASK_COMP_WO_ERR : + discover_contextp->openStatus =OPEN_ACCEPT ; +break ; + +case TASK_COMP_W_UNDERRUN : + discover_contextp->openStatus =OPEN_ACCEPT ; + discover_contextp->resid_len = +asd_le32toh (done_listp->stat_blk.data.res_len); +break ; + +case TASK_ABORTED_BY_ITNL_EXP : +switch (done_listp->stat_blk.itnl_exp.reason) { +case TASK_F_W_PHY_DOWN : +case TASK_F_W_BREAK_RCVD : +case TASK_F_W_OPEN_TO : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +break ; + +case TASK_F_W_OPEN_REJECT : + discover_contextp->openStatus = +OPEN_REJECT_BAD_DESTINATION ; +break ; + } +break ; +default : + discover_contextp->openStatus =OPEN_REJECT_BAD_DESTINATION ; +break ; + } + + sm_contextp->wakeup_state_machine (sm_contextp); +} + +struct asd_target *asd_discover_get_target (struct state_machine_context + *sm_contextp, +uint8_t * dest_sas_address, +struct list_head *old_discover_listp, +struct list_head *found_listp, +unsigned conn_rate, +TRANSPORT_TYPE transport_type) +{ +struct asd_target *target; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + target =asd_find_target (old_discover_listp, dest_sas_address); + +if (target !=NULL ) { +/* +* This target was previously found. +*/ + target->flags |=ASD_TARG_RESEEN ; + + target->ddb_profile.conn_rate = conn_rate; + +asd_hwi_build_ddb_site (discover_contextp->asd, target); + +/* +* First, take this target off of the general chain of all +* targets in the domain. +*/ +list_del_init (&target->all_domain_targets); + +return target; + } + +/* +* See if we haven't already talked to this device during the current +* discovery process. +*/ + target =asd_find_target (found_listp, dest_sas_address); + +if (target !=NULL ) { +/* +* First, take this target off of the general chain of all +* targets in the domain. +*/ +list_del_init (&target->all_domain_targets); + +return target; + } + + target =asd_alloc_target (discover_contextp->asd, + discover_contextp->port); + +/* +* make sure we only do this if the allocation is successful +*/ +if (target ==NULL ) { +return NULL ; + } + + target->domain = + discover_contextp->asd->platform_data->domains[discover_contextp-> + port->id]; + + target->ddb_profile.conn_rate = conn_rate; + + target->ddb_profile.itnl_const =ITNL_TIMEOUT_CONST ; + + target->parent =NULL ; + +/* +* Set to 1 for SSP, STP, and SMP device ports. 0 for all SATA direct +* attached ports. Every device that is initialized by this routine +* is not a SATA direct attach. +*/ + target->ddb_profile.open_affl =OPEN_AFFILIATION ; + +memcpy (target->ddb_profile.sas_addr, dest_sas_address,SAS_ADDR_LEN ); + +if (transport_type ==ASD_TRANSPORT_STP ) { +//TODO: get SUPPORTS_AFFILIATION out of SMP request + target->ddb_profile.open_affl |= + (STP_AFFILIATION |SUPPORTS_AFFILIATION ); + } + +asd_hwi_hash (target->ddb_profile.sas_addr, + target->ddb_profile.hashed_sas_addr); + +// TODO: - we need to allocate this from LRU DDB list +// (doesn't exist yet) +asd_hwi_setup_ddb_site (discover_contextp->asd, target); + +return target; +} + +DISCOVER_RESULTS +asd_find_subtractive_phy (struct state_machine_context * sm_contextp, +struct asd_target * expander, +uint8_t * subtractiveSASAddress, +uint8_t * attachedPhyIdentifier, +unsigned *conn_rate,uint8_t * phyIdentifier) +{ +struct Discover *discover; +DISCOVER_RESULTS result; +uint8_t phyCount; +unsigned foundSubtractive; + +SAS_ZERO (subtractiveSASAddress); + *attachedPhyIdentifier =0 ; + + foundSubtractive =0 ; + +/* +* walk through all the phys of this expander +*/ +for (phyCount =0 ; phyCount < expander->num_phys; phyCount++) { + +/* +* this is just a pointer helper +*/ + discover = &(expander->Phy[phyCount].Result); + +/* +* look for phys with edge or fanout devices attached... +*/ +if ((discover->RoutingAttribute !=SUBTRACTIVE ) || + ((discover->AttachedDeviceType != +EDGE_EXPANDER_DEVICE ) && + (discover->AttachedDeviceType != +FANOUT_EXPANDER_DEVICE ))) { + +continue ; + } + +/* +* make sure all the subtractive phys point to +* the same address when we are connected to an +* expander device +*/ +if (SAS_ISZERO (subtractiveSASAddress)) { + +SASCPY (subtractiveSASAddress, + discover->AttachedSASAddress); + + *attachedPhyIdentifier = + discover->AttachedPhyIdentifier; + + result =DISCOVER_OK ; + + *conn_rate = discover->NegotiatedPhysicalLinkRate; + + *phyIdentifier = phyCount; + + foundSubtractive =1 ; + }else if (!SAS_ISEQUAL (subtractiveSASAddress, + discover->AttachedSASAddress)) { + +/* +* the addresses don't match... + * problem... +*/ +asd_log (ASD_DBG_ERROR ,"\n" +"topology error, diverging " +"subtractive phys" +", '%0llx' != '%0llx' \n" , + *((uint64_t *) subtractiveSASAddress), + *((uint64_t *) discover->AttachedSASAddress)); + +return DISCOVER_FAILED ; + } + } + +if (foundSubtractive ==0 ) { +return DISCOVER_FINISHED ; + } + +return DISCOVER_OK ; +} + +/* +* find the table structure associated with a specific SAS address +*/ +struct asd_target *asd_find_target (struct list_head *target_list, +uint8_t * SASAddress) +{ +struct asd_target *target; + +/* +* walk the list of expanders, when we find the one that matches, stop +*/ +list_for_each_entry (target, target_list, all_domain_targets) { +/* +* do the SASAdresses match +*/ +if (SAS_ISEQUAL (target->ddb_profile.sas_addr, SASAddress)) { +return target; + } + } + +return NULL ; +} + +/* +* find the table structure associated with a specific target identity. +*/ +struct asd_target *asd_find_target_ident (struct list_head *target_list, +struct asd_target *check_target) +{ +struct asd_target *target; + +/* +* walk the list of expanders, when we find the one that matches, stop +*/ +list_for_each_entry (target, target_list, all_domain_targets) { + +/* +* Make sure we don't match ourselves. +*/ +if (check_target == target) { +continue ; + } + +/* +* It can't possibly be a match if the transport types don't +* match. +*/ +if (check_target->transport_type != target->transport_type) { +continue ; + } + +switch (target->transport_type) { +case ASD_TRANSPORT_SSP : +if (target->scsi_cmdset.ident_len != + check_target->scsi_cmdset.ident_len) { + +continue ; + } + +if (memcmp (target->scsi_cmdset.ident, + check_target->scsi_cmdset.ident, + target->scsi_cmdset.ident_len) ==0 ) { + +return target; + } +break ; + +case ASD_TRANSPORT_STP : +if (SAS_ISEQUAL (target->ddb_profile.sas_addr, + check_target->ddb_profile.sas_addr)) { + +return target; + } +break ; + +default : +continue ; + } + + } + +return NULL ; +} + +struct asd_target *asd_find_multipath (struct asd_softc *asd, +struct asd_target *target) +{ +struct asd_port *port; +unsigned port_id; +struct asd_target *multipath_target; + +/* +* Check to make sure that this same device hasn't been exposed to the +* OS on a different port. +*/ +for (port_id =0 ; port_id < asd->hw_profile.max_ports; port_id++) { + + port = asd->port_list[port_id]; + + multipath_target =asd_find_target_ident (&port->targets, + target); + +if (multipath_target !=NULL ) { +return multipath_target; + } + } + +return NULL ; +} + +/* +* +* this routine searches the subtractive phys for the upstream expander address +* +*/ +static int +asd_upstream_expander (struct asd_target *expander, +uint8_t * SASAddress,uint8_t * PhyIdentifier) +{ +struct Discover *discover; +uint8_t phyCount; +int found; + + found =0 ; + +/* +* walk through all the phys of this expander, searching for +* subtractive phys return the SASAddress and PhyIdentifier for the +* first subtractive phy encountered, they should all be the same if +* they have anything attached +*/ +for (phyCount =0 ; phyCount < expander->num_phys; phyCount++) { +/* +* this is just a pointer helper +*/ + discover = &(expander->Phy[phyCount].Result); + +/* +* look for phys with edge or fanout devices attached... +*/ +if ((discover->RoutingAttribute ==SUBTRACTIVE ) && + ((discover->AttachedDeviceType ==EDGE_EXPANDER_DEVICE ) || + (discover->AttachedDeviceType == +FANOUT_EXPANDER_DEVICE ))) { + +SASCPY (SASAddress, discover->AttachedSASAddress); + + *PhyIdentifier = discover->AttachedPhyIdentifier; + + found =1 ; + +break ; + } + } + +return found; +} + +/* +* this routine determines whether a SAS address is directly attached to +* an expander +*/ +static int +asd_direct_attached (struct asd_target *expander,uint8_t * SASAddress) +{ +int direct; +uint8_t phyCount; + + direct =0 ; + +for (phyCount =0 ; phyCount < expander->num_phys; phyCount++) { + +/* +* did we find the address attached locally +*/ +if (*((uint64_t *) SASAddress) == + *((uint64_t *) expander->Phy[phyCount]. + Result.AttachedSASAddress)) { + + direct =1 ; +break ; + } + } + +return direct; +} + +/* +* this routine determines whether the SAS address, can be optimized out +* of the route table. +* +* expander: the expander whose route table we are configuring. +* +* discover: the response to the discovery request for the device attached +* to the phy of the expander that we are trying to configure +* into "expander's" route table. +*/ +static int +asd_qualified_address (struct asd_target *expander, +uint8_t PhyIdentifier, +struct Discover *discover,uint8_t * DisableRouteEntry) +{ +int qualified; +uint16_t routeIndex; +uint8_t *sas_address; + + qualified =1 ; + +if (DiscoverAlgorithm !=SAS_UNIQUE_LEVEL_DESCENT ) { +return qualified; + } + +/* +* leave in any entries that are direct routing attribute, +* assumes that they are slots that will be filled by end +* devices, if it is not direct, then filter out any empty +* connections, connections that match the expander we are +* configuring and connections that are truly direct attached +*/ +if (!SAS_ISZERO (discover->AttachedSASAddress) && + !SAS_ISEQUAL (discover->AttachedSASAddress, + expander->ddb_profile.sas_addr) && + (!asd_direct_attached (expander, discover->AttachedSASAddress))) { + +if (discover->RoutingAttribute ==DIRECT ) { +/* +* if this is a phy that is has a direct +* routing attribute then, have it consume an +* entry, it may be filled in at any time +*/ + }else { +for (routeIndex =0 ; routeIndex < + expander->num_route_indexes; routeIndex++) { + + sas_address =ROUTE_ENTRY (expander, + PhyIdentifier, + routeIndex); + +if (SAS_ISEQUAL (sas_address, + discover->AttachedSASAddress)) { + + qualified =0 ; + +break ; + } + } + } + }else if (SAS_ISZERO (discover->AttachedSASAddress)) { +/* +* if a 0 address, then assume it is an +* empty slot that can be filled at any time, + * this keeps things positionally stable for most +* reasonable topologies +*/ + *DisableRouteEntry =DISABLED ; + }else { + qualified =0 ; + } + +return qualified; +} + +void +asd_add_child (struct asd_port *port, +struct asd_target *parent,struct asd_target *child) +{ +/* +* Check to make sure that this particular target hasn't already been +* put in the tree, or that it isn't the top of the tree. +*/ +if ((port->tree_root == child) || (child->parent !=NULL )) { +return ; + } + + child->parent = parent; + +if (child->parent !=NULL ) { +list_add_tail (&child->siblings, &parent->children); + } +} + +#define DUMP_LIST (a) dump_list(__FUNCTION__, __LINE__, #a, a); +void +dump_list (char *function,unsigned line,char *s,struct list_head *target_list) +{ +struct asd_target *target; + +printk ("%s:%d: dumping list %s\n" , function, line, s); +/* +* walk the list of expanders, when we find the one that matches, stop +*/ +list_for_each_entry (target, target_list, all_domain_targets) { +printk ("%s:%d: %llx\n" , __FUNCTION__, __LINE__, + *((uint64_t *) target->ddb_profile.sas_addr)); + } +} + +DISCOVER_RESULTS +asd_configure_device (struct state_machine_context *sm_contextp, +struct asd_target *parentExpander, +struct Discover *discover, +struct list_head *discover_listp, +struct list_head *found_listp, +struct list_head *old_discover_listp,unsigned conn_rate) +{ +struct asd_target *target; +COMMAND_SET_TYPE command_set_type; +DEVICE_PROTOCOL_TYPE device_protocol_type; +MANAGEMENT_TYPE management_type; +TRANSPORT_TYPE transport_type; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +/* +* TODO: right now we are ignoring all virtual phy devices. +*/ +if ((discover->InitiatorBits !=0 ) || (discover->VirtualPhy ==1 )) { +return DISCOVER_OK ; + } + +switch (conn_rate) { +case RATE_UNKNOWN : +case PHY_DISABLED : +case PHY_FAILED : +return DISCOVER_FAILED ; + +case SPINUP_HOLD_OOB : +printk ("found SPINUP_HOLD\n" ); +break ; +case GBPS_1_5 : +case GBPS_3_0 : +/* +* Nothing special to do. +*/ +break ; + } + +/* +* This routine is only called for end devices. +*/ +ASSERT ((discover->TargetBits &SMP_TGT_PORT ) ==0 ); + +if (discover->TargetBits &SSP_TGT_PORT ) { + + command_set_type =ASD_COMMAND_SET_SCSI ; + device_protocol_type =ASD_DEVICE_PROTOCOL_SCSI ; + transport_type =ASD_TRANSPORT_SSP ; + management_type =ASD_DEVICE_END ; + + }else if (discover->TargetBits &STP_TGT_PORT ) { +/* + * We don't know the command set yet (could be ATAPI or ATA) +* We won't know until IDENTIFY / PIDENTIFY. +*/ + command_set_type =ASD_COMMAND_SET_UNKNOWN ; + device_protocol_type =ASD_DEVICE_PROTOCOL_ATA ; + transport_type =ASD_TRANSPORT_STP ; + management_type =ASD_DEVICE_END ; + + }else if (discover->TargetBits &SATA_TGT_PORT ) { +/* + * We don't know the command set yet (could be ATAPI or ATA) +* We won't know until IDENTIFY / PIDENTIFY. +*/ +/* + * An "attached SATA host" which is "outside of the +* scope of this standard" + * T10/1562-D Rev 5 - 10.4.3.5 pg. 340 - 7/9/2003 +*/ + command_set_type =ASD_COMMAND_SET_UNKNOWN ; + device_protocol_type =ASD_DEVICE_PROTOCOL_ATA ; + transport_type =ASD_TRANSPORT_STP ; + management_type =ASD_DEVICE_END ; + }else { + command_set_type =ASD_COMMAND_SET_UNKNOWN ; + device_protocol_type =ASD_DEVICE_PROTOCOL_UNKNOWN ; + transport_type =ASD_TRANSPORT_UNKNOWN ; + management_type =ASD_DEVICE_UNKNOWN ; + } + + target =asd_discover_get_target (sm_contextp, + discover->AttachedSASAddress, + old_discover_listp, + found_listp, conn_rate, + transport_type); + +if (target ==NULL ) { + +printk ("couldn't allocate target\n" ); + +return DISCOVER_FAILED ; + } + + target->command_set_type = command_set_type; + target->device_protocol_type = device_protocol_type; + target->management_type = management_type; + target->transport_type = transport_type; + +/* +* Add the device to the tree. +*/ +asd_add_child (discover_contextp->port, parentExpander, target); + +list_add_tail (&target->all_domain_targets, discover_listp); + +return DISCOVER_OK ; +} + +void +asd_destroy_discover_list (struct asd_softc *asd, +struct list_head *discover_list) +{ +struct asd_target *target; +struct asd_target *tmp_target; + +list_for_each_entry_safe (target, tmp_target, discover_list, + all_domain_targets) { + +list_del_init (&target->all_domain_targets); + +asd_free_ddb (asd, target->ddb_profile.conn_handle); + +asd_free_target (asd, target); + } +} + +/* -------------------------------------------------------------------------- */ + +DISCOVER_RESULTS +asd_issue_discover_request (struct state_machine_context *sm_contextp, +struct asd_target *expander,unsigned phyIndex) +{ +DISCOVER_RESULTS results; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + discover_contextp->SMPRequestFrame->Function =DISCOVER ; + discover_contextp->SMPRequestFrame->Request.Discover.PhyIdentifier = + phyIndex; + +/* +* get the discover information for each phy +*/ + results =asd_smp_request (sm_contextp, expander, +sizeof (struct SMPRequestPhyInput ), +sizeof (struct SMPResponseDiscover )); + +return results; +} + +DISCOVER_RESULTS +asd_issue_discover_request_post (struct state_machine_context * sm_contextp, +struct asd_target * expander,unsigned phyIndex) +{ +struct Discover *discover; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +if ((discover_contextp->openStatus !=OPEN_ACCEPT ) || + (discover_contextp->SMPResponseFrame->FunctionResult != +SMP_FUNCTION_ACCEPTED )) { + +/* +* if we had a problem on this link, then don't + * bother to do anything else, production code, +* should be more robust... +*/ +// asd_log(ASD_DBG_ERROR, "\n" +printk ("discover error, %02Xh at %0llx\n" , + discover_contextp->SMPResponseFrame->FunctionResult, + *((uint64_t *) expander->ddb_profile.sas_addr)); + +return DISCOVER_FAILED ; + } + + discover = &(expander->Phy[phyIndex].Result); + +/* +* copy the result into the topology table +*/ +memcpy ((void *)&(expander->Phy[phyIndex]), + (void *)&discover_contextp->SMPResponseFrame->Response.Discover, +sizeof (struct SMPResponseDiscover )); + +#if 0 +printk ("----------\n" ); +printk ("PhyIdentifier 0x%x SASAddress 0x%llx\n" , + phyIndex, *((uint64_t *) discover->SASAddress)); +printk ("AttachedSASAddress 0x%llx AttachedPhyIdentifier 0x%x\n" , + *((uint64_t *) discover->AttachedSASAddress), + discover->AttachedPhyIdentifier); +printk ("InitiatorBits 0x%x TargetBits 0x%x\n" , + discover->InitiatorBits, discover->TargetBits); +#endif + +return DISCOVER_OK ; +} + +/* -------------------------------------------------------------------------- */ + +/* +* this function gets the report general and discover information for +* a specific expander. The discover process should begin at the subtractive +* boundary and progress downstream. +* +* If the dest_sas_address is an expander, the expander structure is returned +* in retExpander. +*/ +DISCOVER_RESULTS +asd_issue_report_general (struct state_machine_context * sm_contextp, +uint8_t * dest_sas_address, +uint8_t conn_rate, +uint8_t attachedDeviceType, +struct list_head * old_discover_listp, +struct list_head * found_listp, +struct asd_target ** retExpander) +{ +struct asd_target *expander; +DISCOVER_RESULTS results; +COMMAND_SET_TYPE command_set_type; +DEVICE_PROTOCOL_TYPE device_protocol_type; +TRANSPORT_TYPE transport_type; +MANAGEMENT_TYPE management_type; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + expander =NULL ; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + discover_contextp->SMPRequestFrame->Function =REPORT_GENERAL ; + +switch (attachedDeviceType) { +case EDGE_EXPANDER_DEVICE : + command_set_type =ASD_COMMAND_SET_SMP ; + device_protocol_type =ASD_DEVICE_PROTOCOL_SMP ; + transport_type =ASD_TRANSPORT_SMP ; + management_type =ASD_DEVICE_EDGE_EXPANDER ; +break ; + +case FANOUT_EXPANDER_DEVICE : + management_type =ASD_DEVICE_FANOUT_EXPANDER ; + device_protocol_type =ASD_DEVICE_PROTOCOL_SMP ; + command_set_type =ASD_COMMAND_SET_SMP ; + transport_type =ASD_TRANSPORT_SMP ; +break ; + +default : +/* +* This should never happen. +*/ +return DISCOVER_FAILED ; + } + + expander =asd_discover_get_target (sm_contextp, dest_sas_address, + old_discover_listp, found_listp, + conn_rate, transport_type); + +/* +* make sure we only do this if the allocation is successful +*/ +if (expander ==NULL ) { +return DISCOVER_FAILED ; + } + + expander->command_set_type = command_set_type; + expander->device_protocol_type = device_protocol_type; + expander->transport_type = transport_type; + expander->management_type = management_type; + +/* +* get the report general information for the expander +*/ + results =asd_smp_request (sm_contextp, expander, +sizeof (struct SMPRequestGeneralInput ), +sizeof (struct SMPResponseReportGeneral )); + + *retExpander = expander; + +return results; +} + +DISCOVER_RESULTS +asd_issue_report_general_post (struct state_machine_context * sm_contextp, +struct asd_target * expander) +{ +uint8_t phyCount; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + phyCount =0 ; + +/* +* the assumptions we made were exceeded, need to bump limits... +*/ +if ((discover_contextp->openStatus !=OPEN_ACCEPT ) || + (discover_contextp->SMPResponseFrame->FunctionResult != +SMP_FUNCTION_ACCEPTED )) { +/* +* if we had a problem getting report general for this expander, +* something is wrong, can't go any further down this path... +* production code, should be more robust... +*/ +asd_log (ASD_DBG_ERROR ,"\n" +"report general error, open %02Xh result %02Xh at " +"0x%0llx\n" , + discover_contextp->openStatus, + discover_contextp->SMPResponseFrame->FunctionResult, + *((uint64_t *) expander->ddb_profile.sas_addr)); + +asd_free_ddb (discover_contextp->asd, + expander->ddb_profile.conn_handle); + +asd_free_target (discover_contextp->asd, expander); + +return DISCOVER_FAILED ; + } + +if (discover_contextp->SMPResponseFrame->Response. + ReportGeneral.NumberOfPhys >MAXIMUM_EXPANDER_PHYS ) { + +asd_log (ASD_DBG_ERROR ,"\n" +"report general error" +", NumberOfPhys %d exceeded limit %d on %0llx\n" , + discover_contextp->SMPResponseFrame-> + Response.ReportGeneral.NumberOfPhys, +MAXIMUM_EXPANDER_PHYS , + *((uint64_t *) expander->ddb_profile.sas_addr)); + +asd_free_ddb (discover_contextp->asd, + expander->ddb_profile.conn_handle); + +asd_free_target (discover_contextp->asd, expander); + +return DISCOVER_FAILED ; + } + + expander->num_phys = discover_contextp->SMPResponseFrame-> + Response.ReportGeneral.NumberOfPhys; + + expander->num_route_indexes = +asd_be16toh (discover_contextp->SMPResponseFrame->Response. + ReportGeneral.ExpanderRouteIndexes); + +if (expander->Phy !=NULL ) { +asd_free_mem (expander->Phy); + } + + expander->Phy = + (struct SMPResponseDiscover *) +asd_alloc_mem (sizeof (struct SMPResponseDiscover ) * + expander->num_phys,GFP_KERNEL ); + +if (expander->Phy ==NULL ) { + +printk ("unable to allocate memory\n" ); + +asd_free_ddb (discover_contextp->asd, + expander->ddb_profile.conn_handle); + +asd_free_target (discover_contextp->asd, expander); + +return DISCOVER_FAILED ; + } + +if (expander->num_route_indexes !=0 ) { + +if (expander->RouteTable !=NULL ) { +asd_free_mem (expander->RouteTable); + } + + expander->RouteTable = + (uint8_t *)asd_alloc_mem (SAS_ADDR_LEN * + expander->num_phys * + expander->num_route_indexes, +GFP_KERNEL ); + +if (expander->route_indexes !=NULL ) { +asd_free_mem (expander->route_indexes); + } + + expander->route_indexes = +asd_alloc_mem (expander->num_route_indexes + *sizeof (uint16_t ),GFP_KERNEL ); + +memset (expander->route_indexes,0 , + expander->num_route_indexes *sizeof (uint16_t )); + } + +return DISCOVER_OK ; +} + +/* -------------------------------------------------------------------------- */ + +DISCOVER_RESULTS +asd_issue_report_manufacturer_info (struct state_machine_context * sm_contextp, +struct asd_target * expander) +{ +DISCOVER_RESULTS results; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + discover_contextp->SMPRequestFrame->Function = +REPORT_MANUFACTURER_INFORMATION ; + + results =asd_smp_request (sm_contextp, expander, +sizeof (struct SMPRequestGeneralInput ), +sizeof (struct +SMPResponseReportManufacturerInfo )); + +return results; +} + +DISCOVER_RESULTS +asd_issue_report_manufacturer_info_post (struct state_machine_context * + sm_contextp, +struct asd_target * expander) +{ +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +/* +* the assumptions we made were exceeded, need to bump limits... +*/ +if ((discover_contextp->openStatus !=OPEN_ACCEPT ) || + (discover_contextp->SMPResponseFrame->FunctionResult != +SMP_FUNCTION_ACCEPTED )) { +/* +* if we had a problem getting report general for this expander, +* something is wrong, can't go any further down this path... +* production code, should be more robust... +*/ +asd_log (ASD_DBG_ERROR ,"\n" +"get manufacturer information error, " +"open %02Xh result %02Xh at " +"0x%0llx\n" , + discover_contextp->openStatus, + discover_contextp->SMPResponseFrame->FunctionResult, + *((uint64_t *) expander->ddb_profile.sas_addr)); + +asd_free_ddb (discover_contextp->asd, + expander->ddb_profile.conn_handle); + +asd_free_target (discover_contextp->asd, expander); + +return DISCOVER_FAILED ; + } + +memcpy (&expander->smp_cmdset.manufacturer_info, + &discover_contextp->SMPResponseFrame-> + Response.ReportManufacturerInfo, +sizeof (struct SMPResponseReportManufacturerInfo )); + +#if 0 +printk ("%8.8s|%16.16s|%4.4s\n" , + expander->smp_cmdset.manufacturer_info.VendorIdentification, + expander->smp_cmdset.manufacturer_info.ProductIdentification, + expander->smp_cmdset.manufacturer_info.ProductRevisionLevel); +#endif + +return DISCOVER_OK ; +} + +/* -------------------------------------------------------------------------- */ + +DISCOVER_RESULTS +asd_issue_route_config (struct state_machine_context * sm_contextp, +struct asd_target * expander, +unsigned phyIndex, +uint8_t disableRouteEntry,uint8_t * attachedSASAddress) +{ +uint16_t index; +DISCOVER_RESULTS results; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + index = expander->route_indexes[phyIndex]; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + discover_contextp->SMPRequestFrame->Function = +CONFIGURE_ROUTE_INFORMATION ; + + discover_contextp->SMPRequestFrame->Request. + ConfigureRouteInformation.ExpanderRouteIndex =asd_htobe16 (index); + + discover_contextp->SMPRequestFrame->Request. + ConfigureRouteInformation.PhyIdentifier = phyIndex; + + discover_contextp->SMPRequestFrame->Request. + ConfigureRouteInformation.Configure.DisableRouteEntry = + disableRouteEntry; + +SASCPY (discover_contextp->SMPRequestFrame->Request. + ConfigureRouteInformation.Configure.RoutedSASAddress, + attachedSASAddress); + +/* +* configure the route indexes for the +* expander with the attached address +* information +*/ + results =asd_smp_request (sm_contextp, expander, +sizeof (struct +SMPRequestConfigureRouteInformation ), +sizeof (struct +SMPResponseConfigureRouteInformation )); + +return results; +} + +DISCOVER_RESULTS +asd_issue_route_config_post (struct state_machine_context * sm_contextp, +struct asd_target * expander,unsigned phyIndex) +{ +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +/* +* the assumptions we made were exceeded, need to bump limits... +*/ +if ((discover_contextp->openStatus !=OPEN_ACCEPT ) || + (discover_contextp->SMPResponseFrame->FunctionResult != +SMP_FUNCTION_ACCEPTED )) { +/* +* if we had a problem getting report general for this expander, +* something is wrong, can't go any further down this path... +* production code, should be more robust... +*/ +asd_log (ASD_DBG_ERROR ,"\n" +"route config error, open %02Xh result %02Xh at " +"0x%0llx\n" , + discover_contextp->openStatus, + discover_contextp->SMPResponseFrame->FunctionResult, + *((uint64_t *) expander->ddb_profile.sas_addr)); + +return DISCOVER_FAILED ; + } + +return DISCOVER_OK ; +} + +/* -------------------------------------------------------------------------- */ + +DISCOVER_RESULTS +asd_issue_report_phy_sata (struct state_machine_context * sm_contextp, +struct asd_target * expander,unsigned phyIndex) +{ +DISCOVER_RESULTS results; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + discover_contextp->SMPRequestFrame->Function =REPORT_PHY_SATA ; + + discover_contextp->SMPRequestFrame->Request. + ReportPhySATA.PhyIdentifier = phyIndex; + + results =asd_smp_request (sm_contextp, expander, +sizeof (struct SMPRequestPhyInput ), +sizeof (struct SMPResponseReportPhySATA )); + +return results; +} + +DISCOVER_RESULTS +asd_issue_report_phy_sata_post (struct state_machine_context * sm_contextp, +struct asd_target * expander) +{ +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +/* +* the assumptions we made were exceeded, need to bump limits... +*/ +if ((discover_contextp->openStatus !=OPEN_ACCEPT ) || + (discover_contextp->SMPResponseFrame->FunctionResult != +SMP_FUNCTION_ACCEPTED )) { +/* +* if we had a problem getting report general for this expander, +* something is wrong, can't go any further down this path... +* production code, should be more robust... +*/ +asd_log (ASD_DBG_ERROR ,"\n" +"report phy SATA error, open %02Xh result %02Xh at " +"0x%0llx\n" , + discover_contextp->openStatus, + discover_contextp->SMPResponseFrame->FunctionResult, + *((uint64_t *) expander->ddb_profile.sas_addr)); + +return DISCOVER_FAILED ; + } + +return DISCOVER_OK ; +} + +COMMAND_SET_TYPE asd_sata_get_type (struct adp_dev_to_host_fis * fis) +{ +if ((fis->sector_count ==1 ) && (fis->lba0 ==1 ) && + (fis->lba1 ==0x14 ) && (fis->lba2 ==0xeb )) { + +return ASD_COMMAND_SET_ATAPI ; + } + +return ASD_COMMAND_SET_ATA ; +} + +void +asd_init_sata_direct_attached (struct state_machine_context *sm_contextp, +struct asd_target *target) +{ +struct asd_phy *phy; +struct adp_dev_to_host_fis *fis; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + + phy =list_entry (target->src_port->phys_attached.next, + struct asd_phy, links); + + fis = (struct adp_dev_to_host_fis *) + &phy->bytes_dmaed_rcvd.initial_fis_rcvd.fis[0 ]; + + target->command_set_type =asd_sata_get_type (fis); + +memcpy ((void *)&target->device_protocol. + ata_device_protocol.initial_fis[0 ], + (void *)fis,sizeof (struct adp_dev_to_host_fis )); + + target->ddb_profile.sata_status = fis->status; + +asd_hwi_update_sata (discover_contextp->asd, target); +} + +/* -------------------------------------------------------------------------- */ + +DISCOVER_RESULTS +asd_issue_phy_control (struct state_machine_context *sm_contextp, +struct asd_target *expander, +unsigned phyIndex,unsigned operation) +{ +DISCOVER_RESULTS results; +struct discover_context *discover_contextp; + + discover_contextp = (struct discover_context *) + sm_contextp->state_handle; + +memset (discover_contextp->SMPRequestFrame,0 , +sizeof (struct SMPRequest )); + + discover_contextp->SMPRequestFrame->SMPFrameType =SMP_REQUEST_FRAME ; + + discover_contextp->SMPRequestFrame->Function =PHY_CONTROL ; + + discover_contextp->SMPRequestFrame->Request.PhyControl. + PhyIdentifier = phyIndex; + + discover_contextp->SMPRequestFrame->Request.PhyControl. + PhyOperation = operation; + +/* +* get the discover information for each phy +*/ + results =asd_smp_request (sm_contextp, expander, +sizeof (struct SMPRequestPhyControl ), +sizeof (struct SMPResponsePhyControl )); + +return results; +}
Luben,
Your emails do not comply with the Linux kernel patch submission format.
Please read
http://linux.yyz.us/patch-format.html
Most critical is rule number #5 (signed-off-by line), but also important is rule number #1 (providing a useful subject line).
NOTE: I am _not_ requesting that you resubmit your 27 patches; that's up to James. Just making a note for the future.
Everyone who submits patches to Linux needs to include a signed-off-by line, and format their emails such that automated scripts will process the emails correctly.
Jeff
Quoted 7 lines · Jeff Garzik
Luben,
Your emails do not comply with the Linux kernel patch submission format.
Please read
http://linux.yyz.us/patch-format.htmlMost critical is rule number #5 (signed-off-by line), but also important is rule number #1 (providing a useful subject line).
Hi Jeff,
Thanks for you reply. I'm well aware of the patch format. I wasn't sure about a different subject line since it it all part of a driver posting, "announce" rathern than "patch".
Yes, I forgot to add a signed off line. Sorry, but then again I didn't write the code, just presenting it. (#5. Sign your work...)
Also this is more an announcement rather than a patch, but yes, recent sd patch I submitted I think I followed the rules.
Thanks for reminding me of the rules,
Luben
Quoted 7 lines · Luben Tuikov
Quoted 5 lines · Jeff Garzik
Luben,
Your emails do not comply with the Linux kernel patch submission format. Please read
http://linux.yyz.us/patch-format.html
Quoted 8 lines
Quoted 1 line
Most critical is rule number #5 (signed-off-by line), but also important is rule number #1 (providing a useful subject line).
Hi Jeff,
Thanks for you reply. I'm well aware of the patch format. I wasn't sure about a different subject line since it it all part of a driver posting, "announce" rathern than "patch".
Yes, I understand that.
A key point is that it is impossible to differentiate your 27 patches, from looking at them in a email summary. Putting a short summary of each patch in the email subject line greatly assists those reviewing your code.
Quoted 2 lines
Yes, I forgot to add a signed off line. Sorry, but then again I didn't write the code, just presenting it. (#5. Sign your work...)
"sign your work" is more of a legal sign-off than a notation of authorship. In some cases, a company lawyer may be the person included in the signed-off-by line.
Jeff
Quoted 1 line · Jeff Garzik
A key point is that it is impossible to differentiate your 27 patches, from looking at them in a email summary. Putting a short summary of each patch in the email subject line greatly assists those reviewing your code.
Ok, that makes sense. I wish I had added that to the subject lines.
Quoted 1 line
"sign your work" is more of a legal sign-off than a notation of authorship. In some cases, a company lawyer may be the person included in the signed-off-by line.
Ok, I see. I guess I was a bit shy on that.
Feel free to add "Signed-off-by: Luben Tuikov <[email protected]>", to each patch.
Thanks Jeff!
Luben
Quoted 1 line · Jeff Garzik
Luben,
[]
Quoted 1 line
Everyone who submits patches to Linux needs to include a signed-off-by line, and format their emails such that automated scripts will process the emails correctly.
BTW, as this is a completely new driver (for the kernel source anyway), and there's no "patch" per se here in usual sense (but alot of closely related new files), I think it'll be better to submit it as a tarball, not a series of "patches", most of which are with useless comments (given after the filename the path introduces)... Tarball and a patch for usual places like Kconfig and Makefiles in the upper-level in the source tree... Just IMHO ofcourse.
/mjt