* [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
@ 2005-02-17 17:35 Luben Tuikov
2005-02-17 19:03 ` Jeff Garzik
0 siblings, 1 reply; 6+ messages in thread
From: Luben Tuikov @ 2005-02-17 17:35 UTC (permalink / raw)
To: SCSI Mailing List
This is the SAS domain discovery code. Part 1/3.
diff -Nru a/drivers/scsi/adp94xx/adp94xx_discover.c b/drivers/scsi/adp94xx/adp94xx_discover.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/scsi/adp94xx/adp94xx_discover.c 2005-02-16 16:08:12 -05:00
@@ -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 <robt@PacificCodeWorks.com>
+ *
+ * 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;
+}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
2005-02-17 17:35 [ANNOUNCE] Adaptec SAS/SATA device driver [03/27] Luben Tuikov
@ 2005-02-17 19:03 ` Jeff Garzik
2005-02-17 19:09 ` Luben Tuikov
2005-02-17 21:39 ` Michael Tokarev
0 siblings, 2 replies; 6+ messages in thread
From: Jeff Garzik @ 2005-02-17 19:03 UTC (permalink / raw)
To: Luben Tuikov; +Cc: SCSI Mailing List, James Bottomley
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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
2005-02-17 19:03 ` Jeff Garzik
@ 2005-02-17 19:09 ` Luben Tuikov
2005-02-17 19:17 ` Jeff Garzik
2005-02-17 21:39 ` Michael Tokarev
1 sibling, 1 reply; 6+ messages in thread
From: Luben Tuikov @ 2005-02-17 19:09 UTC (permalink / raw)
To: Jeff Garzik; +Cc: SCSI Mailing List, James Bottomley
On 02/17/05 14:03, Jeff Garzik wrote:
> 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).
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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
2005-02-17 19:09 ` Luben Tuikov
@ 2005-02-17 19:17 ` Jeff Garzik
2005-02-17 19:22 ` Luben Tuikov
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Garzik @ 2005-02-17 19:17 UTC (permalink / raw)
To: Luben Tuikov; +Cc: SCSI Mailing List, James Bottomley
Luben Tuikov wrote:
> On 02/17/05 14:03, Jeff Garzik wrote:
>
>> 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).
>
>
> 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.
> 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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
2005-02-17 19:17 ` Jeff Garzik
@ 2005-02-17 19:22 ` Luben Tuikov
0 siblings, 0 replies; 6+ messages in thread
From: Luben Tuikov @ 2005-02-17 19:22 UTC (permalink / raw)
To: Jeff Garzik; +Cc: SCSI Mailing List, James Bottomley
On 02/17/05 14:17, Jeff Garzik wrote:
> 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.
> "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 <luben_tuikov@adaptec.com>",
to each patch.
Thanks Jeff!
Luben
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [03/27]
2005-02-17 19:03 ` Jeff Garzik
2005-02-17 19:09 ` Luben Tuikov
@ 2005-02-17 21:39 ` Michael Tokarev
1 sibling, 0 replies; 6+ messages in thread
From: Michael Tokarev @ 2005-02-17 21:39 UTC (permalink / raw)
To: SCSI Mailing List
Jeff Garzik wrote:
> Luben,
[]
> 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
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2005-02-17 21:39 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-17 17:35 [ANNOUNCE] Adaptec SAS/SATA device driver [03/27] Luben Tuikov
2005-02-17 19:03 ` Jeff Garzik
2005-02-17 19:09 ` Luben Tuikov
2005-02-17 19:17 ` Jeff Garzik
2005-02-17 19:22 ` Luben Tuikov
2005-02-17 21:39 ` Michael Tokarev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox