diff options
Diffstat (limited to 'usr/src/uts/common/sys')
41 files changed, 7138 insertions, 186 deletions
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 29518c52ea..5300263225 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -142,6 +142,8 @@ CHKHDRS= \ cyclic_impl.h \ dacf.h \ dacf_impl.h \ + damap.h \ + damap_impl.h \ dc_ki.h \ ddi.h \ ddifm.h \ diff --git a/usr/src/uts/common/sys/autoconf.h b/usr/src/uts/common/sys/autoconf.h index 5aa9351981..df743597b7 100644 --- a/usr/src/uts/common/sys/autoconf.h +++ b/usr/src/uts/common/sys/autoconf.h @@ -265,7 +265,7 @@ extern void i_ddi_forceattach_drivers(void); extern int i_ddi_io_initialized(void); extern dev_info_t *i_ddi_create_branch(dev_info_t *, int); extern void i_ddi_add_devimap(dev_info_t *dip); -extern void i_ddi_di_cache_invalidate(int kmflag); +extern void i_ddi_di_cache_invalidate(void); extern void i_ddi_di_cache_free(struct di_cache *cache); /* devname_state - for /dev to denote reconfig and system available */ diff --git a/usr/src/uts/common/sys/bitset.h b/usr/src/uts/common/sys/bitset.h index b14636373b..daf608e835 100644 --- a/usr/src/uts/common/sys/bitset.h +++ b/usr/src/uts/common/sys/bitset.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -72,6 +72,20 @@ int bitset_in_set(bitset_t *, uint_t); int bitset_is_null(bitset_t *); uint_t bitset_find(bitset_t *); +/* + * Bitset computations + */ +int bitset_and(bitset_t *, bitset_t *, bitset_t *); +int bitset_or(bitset_t *, bitset_t *, bitset_t *); +int bitset_xor(bitset_t *, bitset_t *, bitset_t *); + +/* + * Miscellaneous bitset operations + */ +void bitset_zero(bitset_t *); +void bitset_copy(bitset_t *, bitset_t *); +int bitset_match(bitset_t *, bitset_t *); + #endif /* !_KERNEL && !_KMEMUSER */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/damap.h b/usr/src/uts/common/sys/damap.h new file mode 100644 index 0000000000..59777e8033 --- /dev/null +++ b/usr/src/uts/common/sys/damap.h @@ -0,0 +1,156 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DAMAP_H +#define _SYS_DAMAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Delta (device) Address Map Interfaces + * + * These interfaces provide time-stablized sets of 'addresses', + * where addresses are string representations of device + * or bus-specific address. The mechanisms include interfaces to + * report and remove address from a map, time stabilization, callouts + * to higher-level configuration and unconfiguration actions, and + * address lookup functions. + * + * Per Address Reports + * With per-address reporting, the caller reports the addition and removal + * each address visible to it. Each report is independently time stabilized; + * Once a report has stabilized, the reported address is either + * activated & configured, or unconfigured & released. + * + * Full Set Reports + * When using fullset reporting, the report provider enumerates the entire + * set of addresses visible to the provider at a given point in time. + * The entire set is then stabilized. + * Upon stabilizing, any newly reported addresses are activated & configured + * and any previously active addresses which are no longer visible are + * automatically unconfigured and released, freeing the provider from + * the need to explicitly unconfigure addresses no longer present. + * + * Stabilization + * Once an address has been reported (or reported as removed), the report + * is time stabilized before the framework initiates a configuration + * or unconfiguration action. If the address is re-reported while undergoing + * stabilization, the timer is reset for either the address or the full + * set of addresses reported to the map. + * + * Activation/Release + * Once a reported address has passed its stabilization, the address is + * 'activated' by the framework. Once activated, the address is passed + * to a configuration callout to perform whatever actions are necessary. + * If a reported address is deleted or fails to stabilize, the address + * is released by the map. + * A report provider may register callback functions to be invoked + * as part of the address activation & release process. In addition to + * the callbacks, a provider can also supply a handle to provider-private + * data at the time an address is reported. This handle is returned to + * provider as an argument to the activation & release callbacks. + * + * Lookup/Access + * The set of stable addresses contained in a map can be obtained by + * calling interfaces to lookup either a single address or the full + * list of stable addresses. + */ + +/* + * damap_t: Handle to a delta address map + * damap_id_t: Handle to an entry of damap_t + * damap_id_list_t: List of damap_id_handles + */ +typedef struct __damap_dm *damap_t; +typedef struct __damap_id_list *damap_id_list_t; +typedef id_t damap_id_t; + +#define NODAM (damap_id_t)0 + +/* + * activate_cb: Provider callback when reported address is activated + * deactivate_cb: Provider callback when address has been released + * + * configure_cb: Class callout to configure newly activated addresses + * unconfig_cb: Class callout to unconfigure deactivated addresses + */ +typedef void (*damap_activate_cb_t)(void *, char *, int, void **); +typedef void (*damap_deactivate_cb_t)(void *, char *, int, void *); + +typedef void (*damap_configure_cb_t)(void *, damap_t *, damap_id_list_t); +typedef void (*damap_unconfig_cb_t)(void *, damap_t *, damap_id_list_t); + +/* + * Map reporting mode + */ +typedef enum {DAMAP_REPORT_PERADDR, DAMAP_REPORT_FULLSET} damap_rptmode_t; + +#define DAMAP_RESET 1 /* flag to damap_addrset_end */ + +int damap_create(char *, size_t, damap_rptmode_t, clock_t, + void *, damap_activate_cb_t, damap_deactivate_cb_t, + void *, damap_configure_cb_t, damap_unconfig_cb_t, + damap_t **); +void damap_destroy(damap_t *); + +char *damap_name(damap_t *); +int damap_sync(damap_t *); + +int damap_addr_add(damap_t *, char *, damap_id_t *, nvlist_t *, void *); +int damap_addr_del(damap_t *, char *); +int damap_addrid_del(damap_t *, int); + +int damap_addrset_begin(damap_t *); +int damap_addrset_add(damap_t *, char *, damap_id_t *, nvlist_t *, void *); +int damap_addrset_end(damap_t *, int); +int damap_addrset_reset(damap_t *, int); + +damap_id_t damap_id_next(damap_t *, damap_id_list_t, damap_id_t); +char *damap_id2addr(damap_t *, damap_id_t); +nvlist_t *damap_id2nvlist(damap_t *, damap_id_t); +int damap_id_hold(damap_t *, damap_id_t); +void damap_id_rele(damap_t *, damap_id_t); +int damap_id_ref(damap_t *, damap_id_t); +void damap_id_list_rele(damap_t *, damap_id_list_t); +void *damap_id_priv_get(damap_t *, damap_id_t); +void damap_id_priv_set(damap_t *, damap_id_t, void *); +damap_id_t damap_lookup(damap_t *, char *); +int damap_lookup_all(damap_t *, damap_id_list_t *); + +#define DAM_SUCCESS 0 +#define DAM_EEXIST 1 +#define DAM_MAPFULL 2 +#define DAM_EINVAL 3 +#define DAM_FAILURE 4 +#define DAM_SHAME 5 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DAMAP_H */ diff --git a/usr/src/uts/common/sys/damap_impl.h b/usr/src/uts/common/sys/damap_impl.h new file mode 100644 index 0000000000..1cbdad3716 --- /dev/null +++ b/usr/src/uts/common/sys/damap_impl.h @@ -0,0 +1,181 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DAMAP_IMPL_H +#define _SYS_DAMAP_IMPL_H + +#include <sys/isa_defs.h> +#include <sys/dditypes.h> +#include <sys/time.h> +#include <sys/cmn_err.h> +#include <sys/ddi_impldefs.h> +#include <sys/ddi_implfuncs.h> +#include <sys/ddi_isa.h> +#include <sys/model.h> +#include <sys/devctl.h> +#include <sys/nvpair.h> +#include <sys/sysevent.h> +#include <sys/bitset.h> +#include <sys/sdt.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dam dam_t; + +/* + * activate_cb: Provider callback when reported address is activated + * deactivate_cb: Provider callback when address has been released + * + * configure_cb: Class callout to configure newly activated addresses + * unconfig_cb: Class callout to unconfigure deactivated addresses + */ +typedef void (*activate_cb_t)(void *, char *addr, int idx, void **privp); +typedef void (*deactivate_cb_t)(void *, char *addr, int idx, void *priv); + +typedef void (*configure_cb_t)(void *, dam_t *mapp, bitset_t *config_ids); +typedef void (*unconfig_cb_t)(void *, dam_t *mapp, bitset_t *unconfig_ids); + +struct dam { + char *dam_name; + int dam_flags; /* state and locks */ + int dam_options; /* options at map creation */ + int dam_rptmode; /* report mode */ + clock_t dam_stabletmo; /* stabilization (ticks) */ + uint_t dam_size; /* max index for addr hash */ + id_t dam_high; /* highest index allocated */ + timeout_id_t dam_tid; /* timeout(9F) ID */ + + void *dam_activate_arg; /* activation private */ + activate_cb_t dam_activate_cb; /* activation callback */ + deactivate_cb_t dam_deactivate_cb; /* deactivation callback */ + + void *dam_config_arg; /* config-private */ + configure_cb_t dam_configure_cb; /* configure callout */ + unconfig_cb_t dam_unconfig_cb; /* unconfigure callout */ + + ddi_strid *dam_addr_hash; /* addresss to ID hash */ + bitset_t dam_active_set; /* activated address set */ + bitset_t dam_stable_set; /* stable address set */ + bitset_t dam_report_set; /* reported address set */ + void *dam_da; /* per-address soft state */ + ddi_taskq_t *dam_taskqp; /* taskq for map activation */ + hrtime_t dam_last_update; /* last map update */ + hrtime_t dam_last_stable; /* last map stable */ + int dam_stable_cnt; /* # of times map stabilized */ + int dam_stable_overrun; + kcondvar_t dam_cv; + kmutex_t dam_lock; + kstat_t *dam_kstatsp; +}; + +/* + * damap.dam_flags + */ +#define ADDR_LOCK 0x1000 /* per-addr lock */ +#define MAP_LOCK 0x2000 /* global map lock */ +#define DAM_LOCK(m, l) { \ + mutex_enter(&(m)->dam_lock); \ + while ((m)->dam_flags & (l)) \ + cv_wait(&(m)->dam_cv, &(m)->dam_lock); \ + (m)->dam_flags |= (l); \ + mutex_exit(&(m)->dam_lock); \ +} +#define DAM_UNLOCK(m, l) { \ + mutex_enter(&(m)->dam_lock); \ + (m)->dam_flags &= ~(l); \ + cv_signal(&(m)->dam_cv); \ + mutex_exit(&(m)->dam_lock); \ +} +#define DAM_ASSERT_LOCKED(m, l) ASSERT((m)->dam_flags & (l)) + +#define DAM_SPEND 0x10 /* stable pending */ +#define DAM_DESTROYPEND 0x20 /* in process of being destroyed */ +#define DAM_SETADD 0x100 /* fullset update pending */ +#define DAM_FLAG_SET(m, f) { \ + mutex_enter(&(m)->dam_lock); \ + (m)->dam_flags |= f; \ + mutex_exit(&(m)->dam_lock); \ +} +#define DAM_FLAG_CLR(m, f) { \ + mutex_enter(&(m)->dam_lock); \ + (m)->dam_flags &= ~f; \ + mutex_exit(&(m)->dam_lock); \ +} + +/* + * per address softstate stucture + */ +typedef struct { + uint_t da_flags; /* flags */ + int da_jitter; /* address report count */ + int da_ref; /* refcount on address */ + void *da_ppriv; /* stable provider private */ + void *da_cfg_priv; /* config/unconfig private */ + nvlist_t *da_nvl; /* stable nvlist */ + void *da_ppriv_rpt; /* reported provider-private */ + nvlist_t *da_nvl_rpt; /* reported nvlist */ + int64_t da_deadline; /* lbolt64 value when stable */ + hrtime_t da_last_report; /* timestamp of last report */ + int da_report_cnt; /* # of times address reported */ + hrtime_t da_last_stable; /* timestamp of last stable address */ + int da_stable_cnt; /* # of times address has stabilized */ + char *da_addr; /* string in dam_addr_hash (for mdb) */ +} dam_da_t; + +/* + * dam_da_t.da_flags + */ +#define DA_INIT 0x1 /* address initizized */ +#define DA_ACTIVE 0x2 /* address stable */ +#define DA_RELE 0x4 /* adddress released */ + + +/* + * report type + */ +#define RPT_ADDR_ADD 0 +#define RPT_ADDR_DEL 1 + +#define DAM_IN_REPORT(m, i) (bitset_in_set(&(m)->dam_report_set, (i))) +#define DAM_IS_STABLE(m, i) (bitset_in_set(&(m)->dam_active_set, (i))) + +/* + * DAM statistics + */ +struct dam_kstats { + struct kstat_named dam_stable; + struct kstat_named dam_stable_blocked; + struct kstat_named dam_rereport; + struct kstat_named dam_numstable; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DAMAP_IMPL_H */ diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h index 7be6c896ad..5b5d103e08 100644 --- a/usr/src/uts/common/sys/ddi_impldefs.h +++ b/usr/src/uts/common/sys/ddi_impldefs.h @@ -40,6 +40,9 @@ #include <sys/ddidmareq.h> #include <sys/ddi_intr.h> #include <sys/ddi_isa.h> +#include <sys/id_space.h> +#include <sys/modhash.h> +#include <sys/bitset.h> #ifdef __cplusplus extern "C" { @@ -105,7 +108,7 @@ typedef struct devi_port { } port; uint64_t type64; } info; - void *priv_p; + void *priv_p; } devi_port_t; typedef struct devi_bus_priv { @@ -145,7 +148,7 @@ struct dev_info { struct dev_info *devi_next; /* Next instance of this device */ kmutex_t devi_lock; /* Protects per-devinfo data */ - /* logical parents for busop primitives */ + /* logical parents for busop primitives */ struct dev_info *devi_bus_map_fault; /* bus_map_fault parent */ struct dev_info *devi_bus_dma_map; /* bus_dma_map parent */ @@ -395,12 +398,13 @@ struct dev_info { #define DEVI_SET_DEVICE_REMOVED(dip) { \ ASSERT(mutex_owned(&DEVI(dip)->devi_lock)); \ - DEVI(dip)->devi_state |= DEVI_DEVICE_REMOVED; \ + DEVI(dip)->devi_state |= DEVI_DEVICE_REMOVED | DEVI_S_REPORT; \ } #define DEVI_SET_DEVICE_REINSERTED(dip) { \ ASSERT(mutex_owned(&DEVI(dip)->devi_lock)); \ DEVI(dip)->devi_state &= ~DEVI_DEVICE_REMOVED; \ + DEVI(dip)->devi_state |= DEVI_S_REPORT; \ } /* Bus state change macros */ @@ -691,11 +695,14 @@ struct ddi_minor { * * DDI_HIDDEN_NODE indicates that the node should not show up in snapshots * or in /devices. + * + * DDI_HOTPLUG_NODE indicates that the node created by nexus hotplug. */ #define DDI_PERSISTENT 0x01 #define DDI_AUTO_ASSIGNED_NODEID 0x02 #define DDI_VHCI_NODE 0x04 #define DDI_HIDDEN_NODE 0x08 +#define DDI_HOTPLUG_NODE 0x10 #define DEVI_VHCI_NODE(dip) \ (DEVI(dip)->devi_node_attributes & DDI_VHCI_NODE) @@ -741,16 +748,35 @@ struct ddi_parent_private_data { #define sparc_pd_getintr(dev, n) (&DEVI_PD(dev)->par_intr[(n)]) #define sparc_pd_getrng(dev, n) (&DEVI_PD(dev)->par_rng[(n)]) +#ifdef _KERNEL /* - * This data structure is entirely private to the soft state allocator. + * This data structure is private to the indexed soft state allocator. */ -struct i_ddi_soft_state { +typedef struct i_ddi_soft_state { void **array; /* the array of pointers */ - kmutex_t lock; /* serialize access to this struct */ - size_t size; /* how many bytes per state struct */ + kmutex_t lock; /* serialize access to this struct */ + size_t size; /* how many bytes per state struct */ size_t n_items; /* how many structs herein */ struct i_ddi_soft_state *next; /* 'dirty' elements */ -}; +} i_ddi_soft_state; + +/* + * This data structure is private to the stringhashed soft state allocator. + */ +typedef struct i_ddi_soft_state_bystr { + size_t ss_size; /* how many bytes per state struct */ + mod_hash_t *ss_mod_hash; /* hash implementation */ +} i_ddi_soft_state_bystr; + +/* + * This data structure is private to the ddi_strid_* implementation + */ +typedef struct i_ddi_strid { + id_space_t *strid_space; + mod_hash_t *strid_byid; + mod_hash_t *strid_bystr; +} i_ddi_strid; +#endif /* _KERNEL */ /* * Solaris DDI DMA implementation structure and function definitions. diff --git a/usr/src/uts/common/sys/devctl.h b/usr/src/uts/common/sys/devctl.h index a201fded95..5dce50c72a 100644 --- a/usr/src/uts/common/sys/devctl.h +++ b/usr/src/uts/common/sys/devctl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,7 +41,7 @@ extern "C" { * and nexus driver devctl IOCTL interface. * * Applications and nexus drivers may not access the contents of this - * structure directly. Instead, drivers must use the ndi_dc_XXX(9n) + * structure directly. Instead, drivers must use the ndi_dc_*(9n) * interfaces, while applications must use the interfaces provided by * libdevice.so.1. */ @@ -230,6 +230,9 @@ typedef struct devctl_ap_state32 { #define BUS_QUIESCED 0x20 #define BUS_SHUTDOWN 0x40 +#define DEVICE_STATES_ASCII "Dev_Online", "Dev_Busy", "Dev_Offline", \ + "Dev_Down", "Bus_Active", "Bus_Quiesced", "Bus_Shutdown" + #define DC_DEVI_NODENAME "ndi_dc.devi_nodename" #define DEVCTL_CONSTRUCT 0x1 diff --git a/usr/src/uts/common/sys/devinfo_impl.h b/usr/src/uts/common/sys/devinfo_impl.h index e64f5fc601..4f874ea1e3 100644 --- a/usr/src/uts/common/sys/devinfo_impl.h +++ b/usr/src/uts/common/sys/devinfo_impl.h @@ -317,6 +317,7 @@ struct di_path { uint_t path_snap_state; /* describes valid fields */ int path_instance; /* path instance */ uint64_t user_private_data; + uint_t path_flags; /* path flags */ }; /* @@ -331,6 +332,11 @@ struct di_path { #define DI_PATH_SNAP_LINKS 0x40 /* linkages have been postprocessed */ /* + * Flags for path_flags + */ +#define DI_PATH_FLAGS_DEVICE_REMOVED 0x01 /* peer of DI_DEVICE_REMOVED */ + +/* * path properties */ struct di_path_prop { diff --git a/usr/src/uts/common/sys/id_space.h b/usr/src/uts/common/sys/id_space.h index c6f7246658..1f7762316f 100644 --- a/usr/src/uts/common/sys/id_space.h +++ b/usr/src/uts/common/sys/id_space.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ID_SPACE_H #define _ID_SPACE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -47,6 +44,8 @@ void id_space_destroy(id_space_t *); void id_space_extend(id_space_t *, id_t, id_t); id_t id_alloc(id_space_t *); id_t id_alloc_nosleep(id_space_t *); +id_t id_allocff(id_space_t *); +id_t id_allocff_nosleep(id_space_t *); void id_free(id_space_t *, id_t); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/mdi_impldefs.h b/usr/src/uts/common/sys/mdi_impldefs.h index 0f2b0dfe58..563c62af08 100644 --- a/usr/src/uts/common/sys/mdi_impldefs.h +++ b/usr/src/uts/common/sys/mdi_impldefs.h @@ -342,7 +342,7 @@ typedef struct mdi_phci { struct mdi_phci *ph_next; /* next pHCI link */ struct mdi_phci *ph_prev; /* prev pHCI link */ dev_info_t *ph_dip; /* pHCI devi handle */ - struct mdi_vhci *ph_vhci; /* pHCI back ref. to vHCI */ + struct mdi_vhci *ph_vhci; /* pHCI back ref. to vHCI */ /* protected by MDI_PHCI_LOCK ph_mutex... */ kmutex_t ph_mutex; /* per-pHCI mutex */ @@ -398,7 +398,7 @@ typedef struct mdi_phci { #define MDI_PHCI_IS_READY(ph) \ (((ph)->ph_flags & MDI_PHCI_DISABLE_MASK) == 0) -#define MDI_PHCI_SET_OFFLINE(ph) {\ +#define MDI_PHCI_SET_OFFLINE(ph) {\ ASSERT(MDI_PHCI_LOCKED(ph)); \ (ph)->ph_flags |= MDI_PHCI_FLAGS_OFFLINE; } #define MDI_PHCI_SET_ONLINE(ph) {\ @@ -407,7 +407,7 @@ typedef struct mdi_phci { #define MDI_PHCI_IS_OFFLINE(ph) \ ((ph)->ph_flags & MDI_PHCI_FLAGS_OFFLINE) -#define MDI_PHCI_SET_SUSPEND(ph) {\ +#define MDI_PHCI_SET_SUSPEND(ph) {\ ASSERT(MDI_PHCI_LOCKED(ph)); \ (ph)->ph_flags |= MDI_PHCI_FLAGS_SUSPEND; } #define MDI_PHCI_SET_RESUME(ph) {\ @@ -501,7 +501,7 @@ typedef struct mdi_phci { * OPTIMAL - Client device has at least one redundant path. * DEGRADED - No redundant paths (critical). Failure in the current active * path would result in data access failures. - * FAILED - No paths are available to access this device. + * FAILED - No paths are available to access this device. * * Locking order: * @@ -517,7 +517,7 @@ typedef struct mdi_client { char *ct_drvname; /* client driver name */ char *ct_guid; /* client guid */ client_lb_t ct_lb; /* load balancing scheme */ - client_lb_args_t *ct_lb_args; /* load balancing args */ + client_lb_args_t *ct_lb_args; /* load balancing args */ /* protected by MDI_CLIENT_LOCK ct_mutex... */ @@ -726,8 +726,9 @@ struct mdi_pathinfo { kcondvar_t pi_ref_cv; /* condition variable */ struct mdi_pi_kstats *pi_kstats; /* aggregate kstats */ int pi_pm_held; /* phci's kidsup incremented */ - int pi_preferred; /* Preferred path */ + int pi_preferred; /* Preferred path */ void *pi_vprivate; /* vhci private info */ + uint_t pi_flags; /* path flags */ }; /* @@ -959,6 +960,26 @@ struct pi_errs { #define MDI_PI_IS_SUSPENDED(pip) \ ((MDI_PI(pip))->pi_phci->ph_flags & MDI_PHCI_FLAGS_SUSPEND) +#define MDI_PI_FLAGS_SET_HIDDEN(pip) {\ + ASSERT(MDI_PI_LOCKED(pip)); \ + MDI_PI(pip)->pi_flags |= MDI_PATHINFO_FLAGS_HIDDEN; } +#define MDI_PI_FLAGS_CLR_HIDDEN(pip) {\ + ASSERT(MDI_PI_LOCKED(pip)); \ + MDI_PI(pip)->pi_flags &= ~MDI_PATHINFO_FLAGS_HIDDEN; } +#define MDI_PI_FLAGS_IS_HIDDEN(pip) \ + ((MDI_PI(pip)->pi_flags & MDI_PATHINFO_FLAGS_HIDDEN) == \ + MDI_PATHINFO_FLAGS_HIDDEN) + +#define MDI_PI_FLAGS_SET_DEVICE_REMOVED(pip) {\ + ASSERT(MDI_PI_LOCKED(pip)); \ + MDI_PI(pip)->pi_flags |= MDI_PATHINFO_FLAGS_DEVICE_REMOVED; } +#define MDI_PI_FLAGS_CLR_DEVICE_REMOVED(pip) {\ + ASSERT(MDI_PI_LOCKED(pip)); \ + MDI_PI(pip)->pi_flags &= ~MDI_PATHINFO_FLAGS_DEVICE_REMOVED; } +#define MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip) \ + ((MDI_PI(pip)->pi_flags & MDI_PATHINFO_FLAGS_DEVICE_REMOVED) == \ + MDI_PATHINFO_FLAGS_DEVICE_REMOVED) + /* * mdi_vhcache_client, mdi_vhcache_pathinfo, and mdi_vhcache_phci structures * hold the vhci to phci client mappings of the on-disk vhci busconfig cache. diff --git a/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h b/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h index b54df92613..1f69323c62 100644 --- a/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h +++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_ADAPTERS_MPAPI_IMPL_H #define _SYS_SCSI_ADAPTERS_MPAPI_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/sunmdi.h> #include <sys/sunddi.h> #include <sys/mdi_impldefs.h> @@ -253,6 +251,7 @@ typedef struct mp_path_prop { #define MP_DRVR_PATH_STATE_REMOVED 5 #define MP_DRVR_PATH_STATE_TRANSITIONING 6 #define MP_DRVR_PATH_STATE_UNKNOWN 7 +#define MP_DRVR_PATH_STATE_UNINIT 8 /* Structure for MP_PROPRIETARY_LOAD_BALANCE_PROPERTIES */ diff --git a/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h b/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h index dcb359c13e..652258acff 100644 --- a/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h +++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_ADAPTERS_MPAPI_SCSI_VHCI_H #define _SYS_SCSI_ADAPTERS_MPAPI_SCSI_VHCI_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -110,11 +108,18 @@ typedef struct mpapi_lu_data { /* * Structure to maintain mpapi path data. + * + * The hide flag is set when pip was detroyed or should + * have been destroyed(MDI_PATHINFO_FLAGS_DEVICE_REMOVED). + * The valid flag is set to 0 when the path is neither online + * nor standby state. When hide flag is set the valid flag set + * to 0 also. */ typedef struct mpapi_path_data { void *resp; /* pip */ char *path_name; int valid; + int hide; char pclass[MPAPI_SCSI_MAXPCLASSLEN]; mp_path_prop_t prop; } mpapi_path_data_t; diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/ata.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/ata.h new file mode 100644 index 0000000000..f503d856ff --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/ata.h @@ -0,0 +1,279 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * Misc ATA definitions + */ +#ifndef _ATA_H +#define _ATA_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "ata8-acs.h" +#include "atapi7v3.h" + +/* + * IDENTIFY Data + */ +typedef struct { + uint16_t word0; + uint16_t word1; + uint16_t word2; + uint16_t word3; + uint16_t word4; + uint16_t word5; + uint16_t word6; + uint16_t word7; + uint16_t word8; + uint16_t word9; + uint16_t serial_number[10]; + uint16_t word20; + uint16_t word21; + uint16_t word22; + uint16_t firmware_revision[4]; + uint16_t model_number[20]; + uint16_t word47; + uint16_t word48; + uint16_t word49; + uint16_t word50; + uint16_t word51; + uint16_t word52; + uint16_t word53; + uint16_t word54; + uint16_t word55; + uint16_t word56; + uint16_t word57; + uint16_t word58; + uint16_t word59; + uint16_t word60; + uint16_t word61; + uint16_t word62; + uint16_t word63; + uint16_t word64; + uint16_t word65; + uint16_t word66; + uint16_t word67; + uint16_t word68; + uint16_t word69; + uint16_t word70; + uint16_t word71; + uint16_t word72; + uint16_t word73; + uint16_t word74; + uint16_t word75; + uint16_t word76; + uint16_t word77; + uint16_t word78; + uint16_t word79; + uint16_t word80; + uint16_t word81; + uint16_t word82; + uint16_t word83; + uint16_t word84; + uint16_t word85; + uint16_t word86; + uint16_t word87; + uint16_t word88; + uint16_t word89; + uint16_t word90; + uint16_t word91; + uint16_t word92; + uint16_t word93; + uint16_t word94; + uint16_t word95; + uint16_t word96; + uint16_t word97; + uint16_t word98; + uint16_t word99; + uint16_t word100; + uint16_t word101; + uint16_t word102; + uint16_t word103; + uint16_t word104; + uint16_t word105; + uint16_t word106; + uint16_t word107; + uint16_t word108; + uint16_t word109; + uint16_t word110; + uint16_t word111; + uint16_t word112; + uint16_t word113; + uint16_t word114; + uint16_t word115; + uint16_t word116; + uint16_t word117; + uint16_t word118; + uint16_t word119; + uint16_t word120; + uint16_t word121; + uint16_t word122; + uint16_t word123; + uint16_t word124; + uint16_t word125; + uint16_t word126; + uint16_t word127; + uint16_t word128; + uint16_t word129; + uint16_t word130; + uint16_t word131; + uint16_t word132; + uint16_t word133; + uint16_t word134; + uint16_t word135; + uint16_t word136; + uint16_t word137; + uint16_t word138; + uint16_t word139; + uint16_t word140; + uint16_t word141; + uint16_t word142; + uint16_t word143; + uint16_t word144; + uint16_t word145; + uint16_t word146; + uint16_t word147; + uint16_t word148; + uint16_t word149; + uint16_t word150; + uint16_t word151; + uint16_t word152; + uint16_t word153; + uint16_t word154; + uint16_t word155; + uint16_t word156; + uint16_t word157; + uint16_t word158; + uint16_t word159; + uint16_t word160; + uint16_t word161; + uint16_t word162; + uint16_t word163; + uint16_t word164; + uint16_t word165; + uint16_t word166; + uint16_t word167; + uint16_t word168; + uint16_t word169; + uint16_t word170; + uint16_t word171; + uint16_t word172; + uint16_t word173; + uint16_t word174; + uint16_t word175; + uint16_t word176; + uint16_t word177; + uint16_t word178; + uint16_t word179; + uint16_t word180; + uint16_t word181; + uint16_t word182; + uint16_t word183; + uint16_t word184; + uint16_t word185; + uint16_t word186; + uint16_t word187; + uint16_t word188; + uint16_t word189; + uint16_t word190; + uint16_t word191; + uint16_t word192; + uint16_t word193; + uint16_t word194; + uint16_t word195; + uint16_t word196; + uint16_t word197; + uint16_t word198; + uint16_t word199; + uint16_t word200; + uint16_t word201; + uint16_t word202; + uint16_t word203; + uint16_t word204; + uint16_t word205; + uint16_t word206; + uint16_t word207; + uint16_t word208; + uint16_t word209; + uint16_t word210; + uint16_t word211; + uint16_t word212; + uint16_t word213; + uint16_t word214; + uint16_t word215; + uint16_t word216; + uint16_t word217; + uint16_t word218; + uint16_t word219; + uint16_t word220; + uint16_t word221; + uint16_t word222; + uint16_t word223; + uint16_t word224; + uint16_t word225; + uint16_t word226; + uint16_t word227; + uint16_t word228; + uint16_t word229; + uint16_t word230; + uint16_t word231; + uint16_t word232; + uint16_t word233; + uint16_t word234; + uint16_t word235; + uint16_t word236; + uint16_t word237; + uint16_t word238; + uint16_t word239; + uint16_t word240; + uint16_t word241; + uint16_t word242; + uint16_t word243; + uint16_t word244; + uint16_t word245; + uint16_t word246; + uint16_t word247; + uint16_t word248; + uint16_t word249; + uint16_t word250; + uint16_t word251; + uint16_t word252; + uint16_t word253; + uint16_t word254; + uint16_t word255; +} ata_identify_t; + +#define LBA_CAPACITY(ati) \ + ((LE_16(ati->word83) & (1 << 10)) == 0)? \ + (LE_16(ati->word60) | ((LE_16(ati->word61)) << 16)) : \ + ((LE_16(ati->word100)) | ((LE_16(ati->word101)) << 16) | \ + (((uint64_t)LE_16(ati->word102)) << 32) | \ + (((uint64_t)LE_16(ati->word103)) << 48)) + + +#ifdef __cplusplus +} +#endif +#endif /* _ATA_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/ata8-acs.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/ata8-acs.h new file mode 100644 index 0000000000..6f0cc2d2cf --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/ata8-acs.h @@ -0,0 +1,122 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * ATA8-ACS Definitions (subset) Working Draft AT Attachment 8 - ATA/ATAPI + * Command Set (D1699r4c) + */ +#ifndef _ATA8_ACS_H +#define _ATA8_ACS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ATA Command Set + */ +enum ata_opcode { + ATA_NOP = 0x00, + CFA_REQUEST_EXTENDED_ERROR = 0x03, + DEVICE_RESET = 0x08, + READ_SECTORS = 0x20, + READ_SECTORS_EXT = 0x24, + READ_DMA_EXT = 0x25, + READ_DMA_QUEUED_EXT = 0x26, + READ_NATIVE_MAX_ADDRESS_EXT = 0x27, + READ_MULTIPLE_EXT = 0x29, + READ_STREAM_DMA_EXT = 0x2A, + READ_STREAM_EXT = 0x2B, + READ_LOG_EXT = 0x2F, + WRITE_SECTORS = 0x30, + WRITE_SECTORS_EXT = 0x34, + WRITE_DMA_EXT = 0x35, + WRITE_DMA_QUEUED_EXT = 0x36, + SET_MAX_ADDRESS_EXT = 0x37, + CFA_WRITE_SECTORS_WITHOUT_ERASE = 0x38, + WRITE_MULTIPLE_EXT = 0x39, + WRITE_STREAM_DMA_EXT = 0x3A, + WRITE_STREAM_EXT = 0x3B, + WRITE_DMA_FUA_EXT = 0x3D, + WRITE_DMA_QUEUED_FUA_EXT = 0x3E, + WRITE_LOG_EXT = 0x3F, + READ_VERIFY_SECTORS = 0x40, + READ_VERIFY_SECTORS_EXT = 0x42, + WRITE_UNCORRECTABLE_EXT = 0x45, + READ_LOG_DMA_EXT = 0x47, + CONFIGURE_STREAM = 0x51, + WRITE_LOG_DMA_EXT = 0x57, + TRUSTED_NON_DATA = 0x5B, + TRUSTED_RECEIVE = 0x5C, + TRUSTED_RECEIVE_DMA = 0x5D, + TRUSTED_SEND = 0x5E, + TRUSTED_SEND_DMA = 0x5E, + READ_FPDMA_QUEUED = 0x60, + WRITE_FPDMA_QUEUED = 0x61, + CFA_TRANSLATE_SECTOR = 0x87, + EXECUTE_DEVICE_DIAGNOSTIC = 0x90, + DOWNLOAD_MICROCODE = 0x92, + PACKET = 0xA0, + IDENTIFY_PACKET_DEVICE = 0xA1, + SERVICE = 0xA2, + SMART = 0xB0, + DEVICE_CONFIGURATION_OVERLAY = 0xB1, + NV_CACHE = 0xB6, + CFA_ERASE_SECTORS = 0xC0, + READ_MULTIPLE = 0xC4, + WRITE_MULTIPLE = 0xC5, + SET_MULTIPLE_MODE = 0xC6, + READ_DMA_QUEUED = 0xC7, + READ_DMA = 0xC8, + WRITE_DMA = 0xCA, + WRITE_DMA_QUEUED = 0xCC, + CFA_WRITE_MULTIPLE_WITHOUT_ERASE = 0xCD, + WRITE_MULTIPLE_FUA_EXT = 0xCE, + CHECK_MEDIA_CARD_TYPE = 0xD1, + STANDBY_IMMEDIATE = 0xE0, + IDLE_IMMEDIATE = 0xE1, + STANDBY = 0xE2, + IDLE = 0xE3, + ATA_READ_BUFFER = 0xE4, + CHECK_POWER_MODE = 0xE5, + SLEEP = 0xE6, + FLUSH_CACHE = 0xE7, + ATA_WRITE_BUFFER = 0xE8, + FLUSH_CACHE_EXT = 0xEA, + IDENTIFY_DEVICE = 0xEC, + MEDIA_EJECT = 0xED, + SET_FEATURES = 0xEF, + SECURITY_SET_PASSWORD = 0xF1, + SECURITY_UNLOCK = 0xF2, + SECURITY_ERASE_PREPARE = 0xF3, + SECURITY_ERASE_UNIT = 0xF4, + SECURITY_FREEZE_LOCK = 0xF5, + SECURITY_DISABLE_PASSWORD = 0xF6, + READ_NATIVE_MAX_ADDRESS = 0xF8, + SET_MAX_ADDRESS = 0xF9 +}; + +#ifdef __cplusplus +} +#endif +#endif /* _ATA8_ACS_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/atapi7v3.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/atapi7v3.h new file mode 100644 index 0000000000..e1bdf10af2 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/atapi7v3.h @@ -0,0 +1,228 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * ATAPI-7 Definitions (subset) that include Serial ATA + * ATA/ATAPI-7 V3 (d1532v3r4b-ATA-ATAPI-7) + */ +#ifndef _ATAPI7V3_H +#define _ATAPI7V3_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Register - Host to Device FIS + */ +typedef struct { + uint8_t fis_type; + uint8_t idcbits; + uint8_t cmd; + uint8_t features; +#define FEATURE_LBA 0x40 + uint8_t lba_low; + uint8_t lba_mid; + uint8_t lba_hi; + uint8_t device; + uint8_t lba_low_exp; + uint8_t lba_mid_exp; + uint8_t lba_hi_exp; + uint8_t features_exp; + uint8_t sector_count; + uint8_t sector_count_exp; + uint8_t reserved0; + uint8_t control; + uint8_t reserved1[4]; +} register_h2d_fis_t; + +/* + * Register - Device to Host FIS + */ +typedef struct { + uint8_t fis_type; + uint8_t idcbits; + uint8_t status; + uint8_t error; + uint8_t lba_low; + uint8_t lba_mid; + uint8_t lba_hi; + uint8_t device; + uint8_t lba_low_exp; + uint8_t lba_mid_exp; + uint8_t lba_hi_exp; + uint8_t reserved0; + uint8_t sector_count; + uint8_t sector_count_exp; + uint8_t reserved1[6]; +} register_d2h_fis_t; + +typedef struct { + uint8_t fis_type; + uint8_t idcbits; + uint8_t status_bits; +#define STATUS_HI_MASK 0xE +#define STATUS_HI_SHIFT 4 +#define STATUS_LO_MASK 0x7 + uint8_t error; + uint8_t reserved; +} set_device_bits_fis_t; + +typedef struct { + uint8_t fis_type; + uint8_t reserved[3]; +} dma_activate_fis_type; + +typedef struct { + uint8_t fis_type; + uint8_t idcbits; + uint8_t reserved0[2]; + uint32_t dma_buffer_id_lo; + uint32_t dma_buffer_id_hi; + uint32_t reserved1; + uint32_t dma_buffer_offset; + uint32_t dma_buffer_count; + uint32_t reserved2; +} dma_fpactivate_fis_t; + +typedef struct { + uint8_t fis_type; + uint8_t reserved0; + uint8_t bist_bits; + uint8_t reserved1; + uint8_t data[8]; +} bist_activate_fis_t; +#define BIST_T 0x80 +#define BIST_A 0x40 +#define BIST_S 0x20 +#define BIST_L 0x10 +#define BIST_F 0x08 +#define BIST_P 0x04 +#define BIST_V 0x01 + +typedef struct { + uint8_t fis_type; + uint8_t idcbits; + uint8_t status; + uint8_t error; + uint8_t lba_low; + uint8_t lba_mid; + uint8_t lba_high; + uint8_t device; + uint8_t lba_low_exp; + uint8_t lba_mid_exp; + uint8_t lba_high_exp; + uint8_t reserved0; + uint8_t sector_count; + uint8_t sector_count_exp; + uint8_t reserved1; + uint8_t E_status; + uint16_t transfer_count; + uint16_t reserved2; +} pio_setup_fis_t; + +typedef struct { + uint8_t fis_type; + uint32_t dwords[1]; +} bidirectional_fis_t; + +/* + * FIS Types + */ + +#define FIS_REG_H2DEV 0x27 /* 5 DWORDS */ +#define FIS_REG_D2H 0x34 /* 5 DWORDS */ +#define FIS_SET_DEVICE_BITS 0xA1 /* 2 DWORDS */ +#define FIS_DMA_ACTIVATE 0x39 /* 1 DWORD */ +#define FIS_DMA_FPSETUP 0x41 /* 7 DWORDS */ +#define FIS_BIST_ACTIVATE 0x58 /* 3 DWORDS */ +#define FIS_PIO_SETUP 0x5F /* 5 DWORDS */ +#define FIS_BI 0x46 /* 1 DWORD min, 2048 DWORD max */ + +/* + * IDC bits + */ +#define C_BIT 0x80 +#define I_BIT 0x40 +#define D_BIT 0x20 + +/* + * 28-Bit Command Mapping from ACS to FIS + * + * ACS Field FIS Field + * -------------------------------------- + * Feature (7:0) -> Feature + * Count (7:0) -> Sector Count + * LBA (7:0) -> LBA Low + * LBA (15:8) -> LBA Mid + * LBA (23:16) -> LBA High + * LBA (27:24) -> Device (3:0) + * Device (15:12) -> Device (7:4) + * Command -> Command + * + * 48- Bit Command Mapping from ACS to FIS + * + * ACS Field FIS Field + * -------------------------------------- + * Feature (7:0) -> Feature + * Feature (15:8) -> Feature (exp) + * Count (7:0) -> Sector Count + * Count (15:8) -> Sector Count (exp) + * LBA (7:0) -> LBA Low + * LBA (15:8) -> LBA Mid + * LBA (23:16) -> LBA High + * LBA (31:24) -> LBA Low (exp) + * LBA (39:32) -> LBA Mid (exp) + * LBA (47:40) -> LBA High (exp) + * Device (15:12) -> Device (7:4) + * Command -> Command + * + * FIS (FIS_REG_H2DEV) layout: + * + * 31.........24 23...........16 15....................8.7.............0 + * FEATURE | COMMAND | C R R RESERVED | FIS TYPE 0x27 + * DEVICE | LBA HIGH | LBA MID | LBA LOW + * FEATURE(exp) | LBA HIGH(exp) | LBA MID(exp) | LBA LOW(exp) + * CONTROL | RESERVED | Sector Count(exp) | Sector Count + * RESERVED | RESERVED | RESERVED | RESERVED + * + * FIS (FIS_REG_D2H) layout: + * + * 31.........24 23...........16 15....................8.7.............0 + * ERROR | STATUS | R I R RESERVED | FIS TYPE 0x34 + * DEVICE | LBA HIGH | LBA MID | LBA LOW + * RESERVED | LBA HIGH(exp) | LBA MID(exp) | LBA LOW(exp) + * RESERVED | RESERVED | Sector Count(exp) | Sector Count + * RESERVED | RESERVED | RESERVED | RESERVED + */ + + +/* + * Reasonable size to reserve for holding the most common FIS types. + */ +typedef uint32_t fis_t[5]; + +#ifdef __cplusplus +} +#endif +#endif /* _ATAPI7V3_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h new file mode 100644 index 0000000000..074560eeb6 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h @@ -0,0 +1,627 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is the principle header file for the PMCS driver + */ +#ifndef _PMCS_H +#define _PMCS_H +#ifdef __cplusplus +extern "C" { +#endif + + +#include <sys/cpuvar.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/pci.h> +#include <sys/pcie.h> +#include <sys/isa_defs.h> +#include <sys/sunmdi.h> +#include <sys/mdi_impldefs.h> +#include <sys/scsi/scsi.h> +#include <sys/scsi/impl/scsi_reset_notify.h> +#include <sys/scsi/impl/sas_transport.h> +#include <sys/scsi/generic/sas.h> +#include <sys/atomic.h> +#include <sys/byteorder.h> +#include <sys/bitmap.h> +#include <sys/queue.h> +#include <sys/sdt.h> +#include <sys/ddifm.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/fm/io/ddi.h> +#include <sys/scsi/impl/spc3_types.h> + +typedef struct pmcs_hw pmcs_hw_t; +typedef struct pmcs_iport pmcs_iport_t; +typedef struct pmcs_phy pmcs_phy_t; +typedef struct lsas_cmd lsas_cmd_t; +typedef struct lsas_result lsas_result_t; +typedef struct lsata_cmd lsata_cmd_t; +typedef struct lsata_result lsata_result_t; +typedef struct pmcwork pmcwork_t; +typedef struct pmcs_cmd pmcs_cmd_t; +typedef struct pmcs_xscsi pmcs_xscsi_t; +typedef struct pmcs_lun pmcs_lun_t; +typedef struct pmcs_chunk pmcs_chunk_t; + +#include <sys/scsi/adapters/pmcs/pmcs_param.h> +#include <sys/scsi/adapters/pmcs/pmcs_reg.h> +#include <sys/scsi/adapters/pmcs/pmcs_mpi.h> +#include <sys/scsi/adapters/pmcs/pmcs_iomb.h> +#include <sys/scsi/adapters/pmcs/pmcs_sgl.h> + +#include <sys/scsi/adapters/pmcs/smp_defs.h> +#include <sys/scsi/adapters/pmcs/ata.h> +#include <sys/scsi/adapters/pmcs/pmcs_def.h> +#include <sys/scsi/adapters/pmcs/pmcs_proto.h> +#include <sys/scsi/adapters/pmcs/pmcs_scsa.h> +#include <sys/scsi/adapters/pmcs/pmcs_smhba.h> + +#define PMCS_MAX_UA_SIZE 32 + +struct pmcs_xscsi { + uint32_t + ca : 1, /* SATA specific */ + ncq : 1, /* SATA specific */ + pio : 1, /* SATA specific */ + special_needed : 1, /* SATA specific */ + special_running : 1, /* SATA specific */ + reset_success : 1, /* last reset ok */ + reset_wait : 1, /* wait for reset */ + resetting : 1, /* now resetting */ + recover_wait : 1, /* wait for recovery */ + recovering : 1, /* now recovering */ + event_recovery : 1, /* event recovery */ + draining : 1, + dying : 1, + new : 1, + assigned : 1, + dev_gone : 1, + phy_addressable : 1, /* Direct attach SATA */ + dev_state : 4; + uint16_t maxdepth; + uint16_t qdepth; + uint16_t actv_cnt; + uint16_t target_num; + /* statlock protects both target stats and the special queue (sq) */ + kmutex_t statlock; + int32_t ref_count; + dev_info_t *dip; /* Solaris device dip */ + pmcs_phy_t *phy; + STAILQ_HEAD(wqh, pmcs_cmd) wq; + pmcs_cmd_t *wq_recovery_tail; /* See below */ + kmutex_t wqlock; + STAILQ_HEAD(aqh, pmcs_cmd) aq; + kmutex_t aqlock; + STAILQ_HEAD(sqh, pmcs_cmd) sq; /* SATA specific */ + uint32_t tagmap; /* SATA specific */ + pmcs_hw_t *pwp; + ddi_soft_state_bystr *lun_sstate; + uint64_t capacity; /* SATA specific */ + char unit_address[PMCS_MAX_UA_SIZE]; + kcondvar_t reset_cv; + kcondvar_t abort_cv; + char *ua; + pmcs_dtype_t dtype; +}; + +/* + * wq_recovery_tail in the pmcs_xscsi structure is a pointer to a command in + * the wait queue (wq). That pointer is the last command in the wait queue + * that needs to be reissued after device state recovery is complete. Commands + * that need to be retried are reinserted into the wq after wq_recovery_tail + * to maintain the order in which the commands were originally submitted. + */ + +#define PMCS_INVALID_TARGET_NUM (uint16_t)-1 + +#define PMCS_TGT_WAIT_QUEUE 0x01 +#define PMCS_TGT_ACTIVE_QUEUE 0x02 +#define PMCS_TGT_SPECIAL_QUEUE 0x04 +#define PMCS_TGT_ALL_QUEUES 0xff + +/* + * LUN representation. Just a LUN (number) and pointer to the target + * structure (pmcs_xscsi). + */ + +struct pmcs_lun { + pmcs_xscsi_t *target; + uint64_t lun_num; /* lun64 */ + scsi_lun_t scsi_lun; /* Wire format */ + char unit_address[PMCS_MAX_UA_SIZE]; +}; + +/* + * Interrupt coalescing values + */ +#define PMCS_MAX_IO_COMPS_PER_INTR 12 +#define PMCS_MAX_IO_COMPS_HIWAT_SHIFT 6 +#define PMCS_MAX_IO_COMPS_LOWAT_SHIFT 10 +#define PMCS_QUANTUM_TIME_USECS (1000000 / 10) /* 1/10th sec. */ +#define PMCS_MAX_COAL_TIMER 0x200 /* Don't set > than this */ +#define PMCS_MAX_CQ_THREADS 4 +#define PMCS_COAL_TIMER_GRAN 2 /* Go up/down by 2 usecs */ +#define PMCS_INTR_THRESHOLD(x) ((x) * 6 / 10) + +/* + * This structure is used to maintain state with regard to I/O interrupt + * coalescing. + */ + +typedef struct pmcs_io_intr_coal_s { + hrtime_t nsecs_between_intrs; + hrtime_t last_io_comp; + clock_t quantum; + uint32_t num_io_completions; + uint32_t num_intrs; + uint32_t max_io_completions; + uint32_t intr_latency; + uint32_t intr_threshold; + uint16_t intr_coal_timer; + boolean_t timer_on; + boolean_t stop_thread; + boolean_t int_cleared; +} pmcs_io_intr_coal_t; + +typedef struct pmcs_cq_thr_info_s { + kthread_t *cq_thread; + kmutex_t cq_thr_lock; + kcondvar_t cq_cv; + pmcs_hw_t *cq_pwp; +} pmcs_cq_thr_info_t; + +typedef struct pmcs_cq_info_s { + uint32_t cq_threads; + uint32_t cq_next_disp_thr; + boolean_t cq_stop; + pmcs_cq_thr_info_t *cq_thr_info; +} pmcs_cq_info_t; + +typedef struct pmcs_iocomp_cb_s { + pmcwork_t *pwrk; + char iomb[PMCS_QENTRY_SIZE << 1]; + struct pmcs_iocomp_cb_s *next; +} pmcs_iocomp_cb_t; + +typedef struct pmcs_iqp_trace_s { + char *head; + char *curpos; + uint32_t size_left; +} pmcs_iqp_trace_t; + +/* + * Used by string-based softstate as hint to possible size. + */ + +#define PMCS_TGT_SSTATE_SZ 64 +#define PMCS_LUN_SSTATE_SZ 4 + +/* + * HBA iport node softstate + */ +#define PMCS_IPORT_INVALID_PORT_ID 0xffff + +struct pmcs_iport { + kmutex_t lock; /* iport lock */ + list_node_t list_node; /* list node for pwp->iports list_t */ + kmutex_t refcnt_lock; /* refcnt lock */ + kcondvar_t refcnt_cv; /* refcnt cv */ + int refcnt; /* refcnt for this iport */ + dev_info_t *dip; /* iport dip */ + pmcs_hw_t *pwp; /* back pointer to HBA state */ + pmcs_phy_t *pptr; /* pointer to this port's primary phy */ + enum { /* unit address state in the phymap */ + UA_INACTIVE, + UA_PEND_ACTIVATE, + UA_ACTIVE, + UA_PEND_DEACTIVATE + } ua_state; + char *ua; /* unit address (phy mask) */ + int portid; /* portid */ + int report_skip; /* skip or report during discovery */ + list_t phys; /* list of phys on this port */ + int nphy; /* number of phys in this port */ + scsi_hba_tgtmap_t *iss_tgtmap; /* tgtmap */ + ddi_soft_state_bystr *tgt_sstate; /* tgt softstate */ +}; + +struct pmcs_chunk { + pmcs_chunk_t *next; + ddi_acc_handle_t acc_handle; + ddi_dma_handle_t dma_handle; + uint8_t *addrp; + uint64_t dma_addr; +}; + +/* + * HBA node (i.e. non-iport) softstate + */ +struct pmcs_hw { + /* + * Identity + */ + dev_info_t *dip; + + /* + * 16 possible initiator PHY WWNs + */ + uint64_t sas_wwns[PMCS_MAX_PORTS]; + + /* + * Card State + */ + enum pwpstate { + STATE_NIL, + STATE_PROBING, + STATE_RUNNING, + STATE_UNPROBING, + STATE_DEAD + } state; + + uint32_t + fw_disable_update : 1, + fw_force_update : 1, + blocked : 1, + stuck : 1, + locks_initted : 1, + mpi_table_setup : 1, + hba_attached : 1, + iports_attached : 1, + suspended : 1, + separate_ports : 1, + fwlog : 4, + phymode : 3, + physpeed : 3, + resource_limited : 1, + configuring : 1, + ds_err_recovering : 1; + + /* + * This HBA instance's iportmap and list of iport states. + * Note: iports_lock protects iports, iports_attached, and + * num_iports on the HBA softstate. + */ + krwlock_t iports_lock; + scsi_hba_iportmap_t *hss_iportmap; + list_t iports; + int num_iports; + + sas_phymap_t *hss_phymap; + int phymap_active; + + /* + * Locks + */ + kmutex_t lock; + kmutex_t dma_lock; + kmutex_t axil_lock; + kcondvar_t drain_cv; + + /* + * FMA Capabilities + */ + int fm_capabilities; + + /* + * Register Access Handles + */ + ddi_device_acc_attr_t dev_acc_attr; + ddi_device_acc_attr_t reg_acc_attr; + ddi_acc_handle_t pci_acc_handle; + ddi_acc_handle_t msg_acc_handle; + ddi_acc_handle_t top_acc_handle; + ddi_acc_handle_t mpi_acc_handle; + ddi_acc_handle_t gsm_acc_handle; + ddi_acc_handle_t iqp_acchdls[PMCS_MAX_IQ]; + ddi_acc_handle_t oqp_acchdls[PMCS_MAX_IQ]; + ddi_acc_handle_t cip_acchdls; + ddi_acc_handle_t fwlog_acchdl; + ddi_acc_handle_t regdump_acchdl; + + /* + * DMA Handles + */ + ddi_dma_attr_t iqp_dma_attr; + ddi_dma_attr_t oqp_dma_attr; + ddi_dma_attr_t cip_dma_attr; + ddi_dma_attr_t fwlog_dma_attr; + ddi_dma_attr_t regdump_dma_attr; + ddi_dma_handle_t iqp_handles[PMCS_MAX_IQ]; + ddi_dma_handle_t oqp_handles[PMCS_MAX_OQ]; + ddi_dma_handle_t cip_handles; + ddi_dma_handle_t fwlog_hndl; + ddi_dma_handle_t regdump_hndl; + + /* + * Register Pointers + */ + uint32_t *msg_regs; /* message unit registers */ + uint32_t *top_regs; /* top unit registers */ + uint32_t *mpi_regs; /* message passing unit registers */ + uint32_t *gsm_regs; /* GSM registers */ + + /* + * Message Passing and other offsets. + * + * mpi_offset is the offset within the fourth register set (mpi_regs) + * that contains the base of the MPI structures. Since this is actually + * set by the card firmware, it can change from startup to startup. + * + * The other offsets (gst, iqc, oqc) are for similar tables in + * MPI space, typically only accessed during setup. + */ + uint32_t mpi_offset; + uint32_t mpi_gst_offset; + uint32_t mpi_iqc_offset; + uint32_t mpi_oqc_offset; + + /* + * Inbound and outbound queue depth + */ + uint32_t ioq_depth; + + /* + * Kernel addresses and offsets for Inbound Queue Producer Indices + * + * See comments in pmcs_iomb.h about Inbound Queues. Since it + * is relatively expensive to go across the PCIe bus to read or + * write inside the card, we maintain shadow copies in kernel + * memory and update the card as needed. + */ + uint32_t shadow_iqpi[PMCS_MAX_IQ]; + uint32_t iqpi_offset[PMCS_MAX_IQ]; + uint32_t *iqp[PMCS_MAX_IQ]; + kmutex_t iqp_lock[PMCS_NIQ]; + + pmcs_iqp_trace_t *iqpt; + + /* + * Kernel addresses and offsets for Outbound Queue Consumer Indices + */ + uint32_t *oqp[PMCS_MAX_OQ]; + uint32_t oqci_offset[PMCS_MAX_OQ]; + + /* + * Driver's copy of the outbound queue indices + */ + + uint32_t oqci[PMCS_NOQ]; + uint32_t oqpi[PMCS_NOQ]; + + /* + * DMA addresses for both Inbound and Outbound queues. + */ + uint64_t oqaddr[PMCS_MAX_OQ]; + uint64_t iqaddr[PMCS_MAX_IQ]; + + /* + * Producer/Queue Host Memory Pointers and scratch areas, + * as well as DMA scatter/gather chunk areas. + * + * See discussion in pmcs_def.h about how this is laid out. + */ + uint8_t *cip; + uint64_t ciaddr; + + /* + * Scratch area pointer and DMA addrress for SATA and SMP operations. + */ + void *scratch; + uint64_t scratch_dma; + volatile uint8_t scratch_locked; /* Scratch area ownership */ + + /* + * Firmware log pointer + */ + uint32_t *fwlogp; + uint64_t fwaddr; + + /* + * Internal register dump region and flash chunk DMA info + */ + + caddr_t regdumpp; + uint32_t *flash_chunkp; + uint64_t flash_chunk_addr; + + /* + * Card information, some determined during MPI setup + */ + uint32_t fw; /* firmware version */ + uint8_t max_iq; /* maximum inbound queues this card */ + uint8_t max_oq; /* "" outbound "" */ + uint8_t nphy; /* number of phys this card */ + uint8_t chiprev; /* chip revision */ + uint16_t max_cmd; /* max number of commands supported */ + uint16_t max_dev; /* max number of devices supported */ + uint16_t last_wq_dev; /* last dev whose wq was serviced */ + + + /* + * Interrupt Setup stuff. + * + * int_type defines the kind of interrupt we're using with this card. + * oqvec defines the relationship between an Outbound Queue Number and + * a MSI-X vector. + */ + enum { + PMCS_INT_NONE, + PMCS_INT_TIMER, + PMCS_INT_MSI, + PMCS_INT_MSIX, + PMCS_INT_FIXED + } int_type; + uint8_t oqvec[PMCS_NOQ]; + + /* + * Interrupt handle table and size + */ + ddi_intr_handle_t *ih_table; + size_t ih_table_size; + + timeout_id_t wdhandle; + uint32_t intr_mask; + int intr_cnt; + int intr_cap; + uint32_t odb_auto_clear; + + /* + * DMA S/G chunk list + */ + int nchunks; + pmcs_chunk_t *dma_chunklist; + + /* + * Front of the DMA S/G chunk freelist + */ + pmcs_dmachunk_t *dma_freelist; + + /* + * PHY and Discovery Related Stuff + * + * The PMC chip can have up to 16 local phys. We build a level-first + * traversal tree of phys starting with the physical phys on the + * chip itself (i.e., treating the chip as if it were an expander). + * + * Our discovery process goes through a level and discovers what + * each entity is (and it's phy number within that expander's + * address space). It then configures each non-empty item (SAS, + * SATA/STP, EXPANDER). For expanders, it then performs + * discover on that expander itself via REPORT GENERAL and + * DISCOVERY SMP commands, attaching the discovered entities + * to the next level. Then we step down a level and continue + * (and so on). + * + * The PMC chip maintains an I_T_NEXUS notion based upon our + * registering each new device found (getting back a device handle). + * + * Like with the number of physical PHYS being a maximum of 16, + * there are a maximum number of PORTS also being 16. Some + * events apply to PORTS entirely, so we track PORTS as well. + */ + pmcs_phy_t *root_phys; /* HBA PHYs (level 0) */ + pmcs_phy_t *ports[PMCS_MAX_PORTS]; + kmutex_t dead_phylist_lock; /* Protects dead_phys */ + pmcs_phy_t *dead_phys; /* PHYs waiting to be freed */ + + kmem_cache_t *phy_cache; + + /* + * Discovery-related items. + * config_lock: Protects config_changed and should never be held + * outside of getting or setting the value of config_changed. + * config_changed: Boolean indicating whether discovery needs to + * be restarted. + * configuring: 1 = discovery is running, 0 = discovery not running. + * NOTE: configuring is now in the bitfield above. + */ + kmutex_t config_lock; + volatile boolean_t config_changed; + + /* + * Work Related Stuff + * + * Each command given to the PMC chip has an associated work structure. + * See the discussion in pmcs_def.h about work structures. + */ + pmcwork_t *work; /* pool of work structures */ + STAILQ_HEAD(wfh, pmcwork) wf; /* current freelist */ + STAILQ_HEAD(pfh, pmcwork) pf; /* current pending freelist */ + uint16_t wserno; /* rolling serial number */ + kmutex_t wfree_lock; /* freelist/actvlist/wserno lock */ + kmutex_t pfree_lock; /* freelist/actvlist/wserno lock */ + + /* + * Solaris/SCSA items. + */ + scsi_hba_tran_t *tran; + sas_hba_tran_t *smp_tran; + struct scsi_reset_notify_entry *reset_notify_listf; + + /* + * Thread Level stuff. + * + * A number of tasks are done off worker thread taskq. + */ + ddi_taskq_t *tq; /* For the worker thread */ + volatile ulong_t work_flags; + + /* + * Solaris target representation. + * targets = array of pointers to xscsi structures + * allocated by ssoftstate. + */ + pmcs_xscsi_t **targets; + + STAILQ_HEAD(dqh, pmcs_cmd) dq; /* dead commands */ + STAILQ_HEAD(cqh, pmcs_cmd) cq; /* completed commands */ + kmutex_t cq_lock; + kmem_cache_t *iocomp_cb_cache; + pmcs_iocomp_cb_t *iocomp_cb_head; + pmcs_iocomp_cb_t *iocomp_cb_tail; + + uint16_t debug_mask; + uint16_t phyid_block_mask; + uint16_t phys_started; + uint32_t hipri_queue; + uint32_t mpibar; + uint32_t intr_pri; + + pmcs_io_intr_coal_t io_intr_coal; + pmcs_cq_info_t cq_info; + kmutex_t ict_lock; + kcondvar_t ict_cv; + kthread_t *ict_thread; + +#ifdef DEBUG + kmutex_t dbglock; + uint32_t ltags[256]; + uint32_t ftags[256]; + hrtime_t ltime[256]; + hrtime_t ftime[256]; + uint16_t ftag_lines[256]; + uint8_t lti; /* last tag index */ + uint8_t fti; /* first tag index */ +#endif +}; + +extern void *pmcs_softc_state; +extern void *pmcs_iport_softstate; + +/* + * Some miscellaneous, oft used strings + */ +extern const char pmcs_nowrk[]; +extern const char pmcs_nomsg[]; +extern const char pmcs_timeo[]; + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h new file mode 100644 index 0000000000..5ed39d0a79 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h @@ -0,0 +1,514 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _PMCS_DEF_H +#define _PMCS_DEF_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NOTHING, /* nothing connected here */ + SATA, /* SATA connection */ + SAS, /* direct or indirect SAS connection */ + EXPANDER, /* connection to an expander */ + NEW /* Brand new device (pending state) */ +} pmcs_dtype_t; + +/* + * This structure defines a PHY device that represents what we + * are connected to. + * + * The eight real physical PHYs that are in the PMC8X6G are represented + * as an array of eight of these structures which define what these + * real PHYs are connected to. + * + * Depending upon what is actually connected to each PHY, the + * type set will define what we're connected to. If it is + * a direct SATA connection, the phy will describe a SATA endpoint + * If it is a direct SAS connection, it will describe a SAS + * endpoint. + * + * If it is an EXPANDER, this will describe the edge of an expander. + * As we perform discovery on what is in an EXPANDER we define an + * additional list of phys that represent what the Expander is connected to. + */ +#define PMCS_HW_MIN_LINK_RATE SAS_LINK_RATE_1_5GBIT +#define PMCS_HW_MAX_LINK_RATE SAS_LINK_RATE_6GBIT + +#define PMCS_INVALID_DEVICE_ID 0xffffffff + +struct pmcs_phy { + pmcs_phy_t *sibling; /* sibling phy */ + pmcs_phy_t *parent; /* parent phy */ + pmcs_phy_t *children; /* head of list of children */ + pmcs_phy_t *dead_next; /* dead PHY list link */ + list_node_t list_node; /* list element */ + uint32_t device_id; /* PMC8X6G device handle */ + uint32_t + ncphy : 8, /* # of contained phys for expander */ + hw_event_ack : 24; /* XXX: first level phy event acked */ + uint8_t phynum; /* phy number on parent expander */ + uint8_t width; /* how many phys wide */ + uint8_t ds_recovery_retries; /* # error retry attempts */ + pmcs_dtype_t dtype; /* current dtype of the phy */ + pmcs_dtype_t pend_dtype; /* new dtype (pending change) */ + uint32_t + level : 8, /* level in expander tree */ + tolerates_sas2 : 1, /* tolerates SAS2 SMP */ + spinup_hold : 1, /* spinup hold needs releasing */ + atdt : 3, /* attached device type */ + portid : 4, /* PMC8X6G port context */ + link_rate : 4, /* current supported speeds */ + valid_device_id : 1, /* device id is valid */ + abort_sent : 1, /* we've sent an abort */ + abort_pending : 1, /* we have an abort pending */ + need_rl_ext : 1, /* need SATA RL_EXT recocvery */ + subsidiary : 1, /* this is part of a wide phy */ + configured : 1, /* is configured */ + dead : 1, /* dead */ + changed : 1; /* this phy is changing */ + clock_t config_stop; /* When config attempts will stop */ + hrtime_t abort_all_start; + kcondvar_t abort_all_cv; /* Wait for ABORT_ALL completion */ + kmutex_t phy_lock; + volatile uint32_t ref_count; /* Targets & work on this PHY */ + uint8_t sas_address[8]; /* SAS address for this PHY */ + struct { + uint32_t + prog_min_rate :4, + hw_min_rate :4, + prog_max_rate :4, + hw_max_rate :4, + reserved :16; + } state; + char path[32]; /* path name for this phy */ + pmcs_hw_t *pwp; /* back ptr to hba struct */ + pmcs_iport_t *iport; /* back ptr to the iport handle */ + pmcs_xscsi_t *target; /* back ptr to current target */ + kstat_t *phy_stats; /* kstats for this phy */ +}; + +/* maximum number of ds recovery retries (ds_recovery_retries) */ +#define PMCS_MAX_DS_RECOVERY_RETRIES 4 + + +/* + * Inbound and Outbound Queue Related Definitions. + * + * The PMC8X6G has a programmable number of inbound and outbound circular + * queues for use in message passing between the host and the PMC8X6G + * (up to 64 queues for the Rev C Chip). This driver does not use all + * possible queues. + * + * Each Queue is given 4K of consistent memory and we set a 64 byte size for + * the queue entry size (this gives us 256 queue entries per queue). + * + * This allocation then continues up a further PMCS_SCRATCH_SIZE bytes + * that the driver uses as a temporary scratch area for things like + * SMP discovery. + * + * This control area looks like this: + * + * Offset What + * ------------------------------------------------ + * 0 IQ 0 Consumer Index + * 4 IQ 1 Consumer Index + * 8..255 ... + * 252..255 IQ 63 Consumer Index + * 256 OQ 0 Producer Index + * 260 OQ 1 Producer Index + * 264..259 .... + * 508..511 OQ 63 Producer Index + * 512..512+PMCS_SCRATCH_SIZE-1 Scratch area. + */ +#define IQCI_BASE_OFFSET 0 +#define IQ_OFFSET(qnum) (IQCI_BASE_OFFSET + (qnum << 2)) +#define OQPI_BASE_OFFSET 256 +#define OQ_OFFSET(qnum) (OQPI_BASE_OFFSET + (qnum << 2)) + +/* + * Work related structures. Each one of these structures is paired + * with *any* command that is fed to the PMC8X6G via one of the + * Inbound Queues. The work structure has a tag to compare with + * the message that comes back out of an Outbound Queue. The + * work structure also points to the phy which this command is + * tied to. It also has a pointer a callback function (if defined). + * See that TAG Architecture below for the various kinds of + * dispositions of a work structure. + */ + +/* + * Work Structure States + * + * NIL -> READY + * READY -> NIL + * READY -> ONCHIP + * ONCHIP -> INTR + * INTR -> READY + * INTR -> NIL + * INTR -> ABORTED + * INTR -> TIMED_OUT + * ABORTED -> NIL + * TIMED_OUT -> NIL + */ +typedef enum { + PMCS_WORK_STATE_NIL = 0, + PMCS_WORK_STATE_READY, + PMCS_WORK_STATE_ONCHIP, + PMCS_WORK_STATE_INTR, + PMCS_WORK_STATE_IOCOMPQ, + PMCS_WORK_STATE_ABORTED, + PMCS_WORK_STATE_TIMED_OUT +} pmcs_work_state_t; + +struct pmcwork { + STAILQ_ENTRY(pmcwork) next; + kmutex_t lock; + kcondvar_t sleep_cv; + void *ptr; /* linkage or callback function */ + void *arg; /* command specific data */ + pmcs_phy_t *phy; /* phy who owns this command */ + pmcs_xscsi_t *xp; /* Back pointer to xscsi struct */ + volatile uint32_t htag; /* tag for this structure */ + uint32_t + timer : 27, + onwire : 1, + dead : 1, + state : 3; + hrtime_t start; /* timestamp start */ + uint32_t ssp_event; /* ssp event */ + pmcs_dtype_t dtype; /* stash, incase phy gets cleared */ + + /* DEBUG-only fields from here on */ + void *last_ptr; + void *last_arg; + pmcs_phy_t *last_phy; + pmcs_xscsi_t *last_xp; + uint32_t last_htag; + pmcs_work_state_t last_state; + hrtime_t finish; +}; + +#define PMCS_REC_EVENT 0xffffffff /* event recovery */ + +/* + * This structure defines a PMC-Sierra defined firmware header. + */ +#pragma pack(4) +typedef struct { + char vendor_id[8]; + uint8_t product_id; + uint8_t hwrev; + uint8_t destination_partition; + uint8_t reserved0; + uint8_t fwrev[4]; + uint32_t firmware_length; + uint32_t crc; + uint32_t start_address; + uint8_t data[]; +} pmcs_fw_hdr_t; +#pragma pack() + +/* + * Offlevel work as a bit pattern. + */ +#define PMCS_WORK_DISCOVER 0 +#define PMCS_WORK_REM_DEVICES 2 +#define PMCS_WORK_ABORT_HANDLE 3 +#define PMCS_WORK_SPINUP_RELEASE 4 +#define PMCS_WORK_SAS_HW_ACK 5 +#define PMCS_WORK_SATA_RUN 6 +#define PMCS_WORK_RUN_QUEUES 7 +#define PMCS_WORK_ADD_DMA_CHUNKS 8 +#define PMCS_WORK_DS_ERR_RECOVERY 9 +#define PMCS_WORK_SSP_EVT_RECOVERY 10 + +/* + * The actual values as they appear in work_flags + */ +#define PMCS_WORK_FLAG_DISCOVER (1 << 0) +#define PMCS_WORK_FLAG_REM_DEVICES (1 << 2) +#define PMCS_WORK_FLAG_ABORT_HANDLE (1 << 3) +#define PMCS_WORK_FLAG_SPINUP_RELEASE (1 << 4) +#define PMCS_WORK_FLAG_SAS_HW_ACK (1 << 5) +#define PMCS_WORK_FLAG_SATA_RUN (1 << 6) +#define PMCS_WORK_FLAG_RUN_QUEUES (1 << 7) +#define PMCS_WORK_FLAG_ADD_DMA_CHUNKS (1 << 8) +#define PMCS_WORK_FLAG_DS_ERR_RECOVERY (1 << 9) +#define PMCS_WORK_FLAG_SSP_EVT_RECOVERY (1 << 10) + +/* + * This structure is used by this function to test MPI (and interrupts) + * after MPI has been started to make sure it's working reliably. + */ +typedef struct { + uint32_t signature; + uint32_t count; + uint32_t *ptr; +} echo_test_t; +#define ECHO_SIGNATURE 0xbebebeef + +/* + * Tag Architecture. The PMC has 32 bit tags for MPI messages. + * We use this tag this way. + * + * bits what + * ------------------------ + * 31 done bit + * 30..28 tag type + * 27..12 rolling serial number + * 11..0 index into work area to get pmcwork structure + * + * A tag type of NONE means that nobody is waiting on any results, + * so the interrupt code frees the work structure that has this + * tag. + * + * A tag type of CBACK means that the the interrupt handler + * takes the tag 'arg' in the work structure to be a callback + * function pointer (see pmcs_cb_t). The callee is responsible + * for freeing the work structure that has this tag. + * + * A tag type of WAIT means that the issuer of the work needs + * be woken up from interrupt level when the command completes + * (or times out). If work structure tag 'arg' is non-null, + * up to 2*PMCS_QENTRY_SIZE bits of data from the Outbound Queue + * entry may be copied to the area pointed to by 'arg'. This + * allows issuers to get directly at the results of the command + * they issed. The synchronization point for the issuer and the + * interrupt code for command done notification is the setting + * of the 'DONE' bit in the tag as stored in the work structure. + */ +#define PMCS_TAG_TYPE_FREE 0 +#define PMCS_TAG_TYPE_NONE 1 +#define PMCS_TAG_TYPE_CBACK 2 +#define PMCS_TAG_TYPE_WAIT 3 +#define PMCS_TAG_TYPE_SHIFT 28 +#define PMCS_TAG_SERNO_SHIFT 12 +#define PMCS_TAG_INDEX_SHIFT 0 +#define PMCS_TAG_TYPE_MASK 0x70000000 +#define PMCS_TAG_DONE 0x80000000 +#define PMCS_TAG_SERNO_MASK 0x0ffff000 +#define PMCS_TAG_INDEX_MASK 0x00000fff +#define PMCS_TAG_TYPE(x) \ + (((x) & PMCS_TAG_TYPE_MASK) >> PMCS_TAG_TYPE_SHIFT) +#define PMCS_TAG_SERNO(x) \ + (((x) & PMCS_TAG_SERNO_MASK) >> PMCS_TAG_SERNO_SHIFT) +#define PMCS_TAG_INDEX(x) \ + (((x) & PMCS_TAG_INDEX_MASK) >> PMCS_TAG_INDEX_SHIFT) +#define PMCS_TAG_FREE 0 +#define PMCS_COMMAND_DONE(x) \ + (((x)->htag == PMCS_TAG_FREE) || (((x)->htag & PMCS_TAG_DONE) != 0)) +#define PMCS_COMMAND_ACTIVE(x) \ + ((x)->htag != PMCS_TAG_FREE && (x)->state == PMCS_WORK_STATE_ONCHIP) + +/* + * Miscellaneous Definitions + */ +#define CLEAN_MESSAGE(m, x) { \ + int _j = x; \ + while (_j < PMCS_MSG_SIZE) { \ + m[_j++] = 0; \ + } \ +} + +#define COPY_MESSAGE(t, f, a) { \ + int _j; \ + for (_j = 0; _j < a; _j++) { \ + t[_j] = f[_j]; \ + } \ + while (_j < PMCS_MSG_SIZE) { \ + t[_j++] = 0; \ + } \ +} + +#define PMCS_PHY_ADDRESSABLE(pp) \ + ((pp)->level == 0 && (pp)->dtype == SATA && \ + ((pp)->sas_address[0] >> 4) != 5) + +#define RESTART_DISCOVERY(pwp) \ + ASSERT(!mutex_owned(&pwp->config_lock)); \ + mutex_enter(&pwp->config_lock); \ + pwp->config_changed = B_TRUE; \ + mutex_exit(&pwp->config_lock); \ + SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER); + +#define RESTART_DISCOVERY_LOCKED(pwp) \ + ASSERT(mutex_owned(&pwp->config_lock)); \ + pwp->config_changed = B_TRUE; \ + SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER); + +#define PHY_CHANGED(pwp, p) \ + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s changed in %s line %d", \ + p->path, __func__, __LINE__); \ + p->changed = 1 + +#define PHY_CHANGED_AT_LOCATION(pwp, p, func, line) \ + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s changed in %s line %d", \ + p->path, func, line); \ + p->changed = 1 + +#define PHY_TYPE(pptr) \ + (((pptr)->dtype == NOTHING)? "NOTHING" : \ + (((pptr)->dtype == SATA)? "SATA" : \ + (((pptr)->dtype == SAS)? "SAS" : "EXPANDER"))) + +#define IS_ROOT_PHY(pptr) (pptr->parent == NULL) + +#define PMCS_HIPRI(pwp, oq, c) \ + (pwp->hipri_queue & (1 << PMCS_IQ_OTHER)) ? \ + (PMCS_IOMB_HIPRI | PMCS_IOMB_IN_SAS(oq, c)) : \ + (PMCS_IOMB_IN_SAS(oq, c)) + +#define SCHEDULE_WORK(hwp, wrk) \ + (void) atomic_set_long_excl(&hwp->work_flags, wrk) + +/* + * Check to see if the requested work bit is set. Either way, the bit will + * be cleared upon return. + */ +#define WORK_SCHEDULED(hwp, wrk) \ + (atomic_clear_long_excl(&hwp->work_flags, wrk) == 0) + +/* + * Check to see if the requested work bit is set. The value will not be + * changed in this case. The atomic_xx_nv operations can be quite expensive + * so this should not be used in non-DEBUG code. + */ +#define WORK_IS_SCHEDULED(hwp, wrk) \ + ((atomic_and_ulong_nv(&hwp->work_flags, (ulong_t)-1) & (1 << wrk)) != 0) + +#define WAIT_FOR(p, t, r) \ + r = 0; \ + while (!PMCS_COMMAND_DONE(p)) { \ + clock_t tmp = cv_timedwait(&p->sleep_cv, \ + &p->lock, ddi_get_lbolt() + \ + drv_usectohz(t * 1000)); \ + if (!PMCS_COMMAND_DONE(p) && tmp < 0) { \ + r = 1; \ + break; \ + } \ + } + +/* + * Signal the next I/O completion thread to start running. + */ + +#define PMCS_CQ_RUN_LOCKED(hwp) \ + if (!STAILQ_EMPTY(&hwp->cq) || hwp->iocomp_cb_head) { \ + pmcs_cq_thr_info_t *cqti; \ + cqti = &hwp->cq_info.cq_thr_info \ + [hwp->cq_info.cq_next_disp_thr]; \ + hwp->cq_info.cq_next_disp_thr++; \ + if (hwp->cq_info.cq_next_disp_thr == \ + hwp->cq_info.cq_threads) { \ + hwp->cq_info.cq_next_disp_thr = 0; \ + } \ + mutex_enter(&cqti->cq_thr_lock); \ + cv_signal(&cqti->cq_cv); \ + mutex_exit(&cqti->cq_thr_lock); \ + } \ + +#define PMCS_CQ_RUN(hwp) \ + mutex_enter(&hwp->cq_lock); \ + PMCS_CQ_RUN_LOCKED(hwp); \ + mutex_exit(&hwp->cq_lock); + + +/* + * Watchdog/SCSA timer definitions + */ +/* usecs to SCSA watchdog ticks */ +#define US2WT(x) (x)/10 + +/* + * More misc + */ +#define BYTE0(x) (((x) >> 0) & 0xff) +#define BYTE1(x) (((x) >> 8) & 0xff) +#define BYTE2(x) (((x) >> 16) & 0xff) +#define BYTE3(x) (((x) >> 24) & 0xff) +#define BYTE4(x) (((x) >> 32) & 0xff) +#define BYTE5(x) (((x) >> 40) & 0xff) +#define BYTE6(x) (((x) >> 48) & 0xff) +#define BYTE7(x) (((x) >> 56) & 0xff) +#define WORD0(x) (((x) >> 0) & 0xffff) +#define WORD1(x) (((x) >> 16) & 0xffff) +#define WORD2(x) (((x) >> 32) & 0xffff) +#define WORD3(x) (((x) >> 48) & 0xffff) +#define DWORD0(x) ((uint32_t)(x)) +#define DWORD1(x) ((uint32_t)(((uint64_t)x) >> 32)) + +#define SAS_ADDR_FMT "0x%02x%02x%02x%02x%02x%02x%02x%02x" +#define SAS_ADDR_PRT(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7] + +#define PMCS_VALID_LINK_RATE(r) \ + ((r == SAS_LINK_RATE_1_5GBIT) || (r == SAS_LINK_RATE_3GBIT) || \ + (r == SAS_LINK_RATE_6GBIT)) + +/* + * This is here to avoid inclusion of <sys/ctype.h> which is not lint clean. + */ +#define HEXDIGIT(x) (((x) >= '0' && (x) <= '9') || \ + ((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F')) + + +typedef void (*pmcs_cb_t) (pmcs_hw_t *, pmcwork_t *, uint32_t *); + +/* + * Defines and structure used for tracing/logging information + */ + +#define PMCS_TBUF_ELEM_SIZE 120 + +#ifdef DEBUG +#define PMCS_TBUF_NUM_ELEMS_DEF 100000 +#else +#define PMCS_TBUF_NUM_ELEMS_DEF 15000 +#endif + +typedef struct { + timespec_t timestamp; + char buf[PMCS_TBUF_ELEM_SIZE]; +} pmcs_tbuf_t; + +/* + * Firmware event log header format + */ + +typedef struct pmcs_fw_event_hdr_s { + uint32_t fw_el_signature; + uint32_t fw_el_entry_start_offset; + uint32_t fw_el_rsvd1; + uint32_t fw_el_buf_size; + uint32_t fw_el_rsvd2; + uint32_t fw_el_oldest_idx; + uint32_t fw_el_latest_idx; + uint32_t fw_el_entry_size; +} pmcs_fw_event_hdr_t; + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_DEF_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h new file mode 100644 index 0000000000..0a397aee98 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h @@ -0,0 +1,724 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * PMC 8x6G IOMB Definitions + */ +#ifndef _PMCS_IOMB_H +#define _PMCS_IOMB_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * An IOMB (IO Message Buffer) is the principle means of communication + * between the PMC and the HOST. The host places IOMBs on the Inbound + * Queues (IQ) which are in HOST memory and updates a producer index + * within the PMC. The PMC pulls the IOMB off the IQ and updates a + * consumer index in HOST memory. If appropriate, when the PMC is + * done with the action requested by the IOMB, the PMC writes a + * reply IOMB to host memory and updates its producer index and + * interrupts the HOST. + */ +/* + * The first word of all IOMBs is always laid out thusly: + * + * |Byte 3 |Byte 2 |Byte 1 |Byte 0 | + * +-------------+-------------+----------------------+ + * |V Resvd BC|Resvd OBID |CAT | OPCODE | + * +--------------------------------------------------+ + * + * V == Valid + * BC = Buffer Count + * OBID = Outbound Queue ID + * CAT = Category + * OPCODE = Well, uh, OPCODE. + */ + +#define PMCS_IOMB_VALID (1U << 31) +#define PMCS_IOMB_HIPRI (1U << 30) +#define PMCS_IOMB_BC_SHIFT (24) +#define PMCS_IOMB_BC_MASK (0xf << PMCS_IOMB_BC_SHIFT) +#define PMCS_IOMB_OBID_SHIFT (16) +#define PMCS_IOMB_OBID_MASK (0xf << PMCS_IOMB_OBID_SHIFT) +#define PMCS_IOMB_CAT_SHIFT (12) +#define PMCS_IOMB_CAT_MASK (0xf << PMCS_IOMB_CAT_SHIFT) +#define PMCS_IOMB_OPCODE_MASK (0xfff) + + +#define PMCS_IOMB_CAT_NET 0 +#define PMCS_IOMB_CAT_FC 1 +#define PMCS_IOMB_CAT_SAS 2 +#define PMCS_IOMB_CAT_SCSI 3 + +/* + * Shorthand + */ +#define PMCS_IOMB_IN_SAS(q, opcode) \ + (PMCS_IOMB_VALID | (1 << PMCS_IOMB_BC_SHIFT) | \ + (PMCS_IOMB_CAT_SAS << PMCS_IOMB_CAT_SHIFT) | \ + ((q << PMCS_IOMB_OBID_SHIFT) & PMCS_IOMB_OBID_MASK) | \ + (opcode & PMCS_IOMB_OPCODE_MASK)) + +/* + * PMC IOMB Inbound Queue Opcodes + */ +#define PMCIN_ECHO 0x01 +#define PMCIN_GET_INFO 0x02 +#define PMCIN_GET_VPD 0x03 +#define PMCIN_PHY_START 0x04 +#define PMCIN_PHY_STOP 0x05 +#define PMCIN_SSP_INI_IO_START 0x06 +#define PMCIN_SSP_INI_TM_START 0x07 +#define PMCIN_SSP_INI_EXT_IO_START 0x08 +#define PMCIN_DEVICE_HANDLE_ACCEPT 0x09 +#define PMCIN_SSP_TGT_IO_START 0x0A +#define PMCIN_SSP_TGT_RESPONSE_START 0x0B +#define PMCIN_SSP_INI_EDC_EXT_IO_START 0x0C +#define PMCIN_SSP_INI_EDC_EXT_IO_START1 0x0D +#define PMCIN_SSP_TGT_EDC_IO_START 0x0E +#define PMCIN_SSP_ABORT 0x0F +#define PMCIN_DEREGISTER_DEVICE_HANDLE 0x10 +#define PMCIN_GET_DEVICE_HANDLE 0x11 +#define PMCIN_SMP_REQUEST 0x12 +#define PMCIN_SMP_RESPONSE 0x13 +#define PMCIN_SMP_ABORT 0x14 +#define PMCIN_ASSISTED_DISCOVERY 0x15 +#define PMCIN_REGISTER_DEVICE 0x16 +#define PMCIN_SATA_HOST_IO_START 0x17 +#define PMCIN_SATA_ABORT 0x18 +#define PMCIN_LOCAL_PHY_CONTROL 0x19 +#define PMCIN_GET_DEVICE_INFO 0x1A +#define PMCIN_TWI 0x1B +#define PMCIN_FW_FLASH_UPDATE 0x20 +#define PMCIN_SET_VPD 0x21 +#define PMCIN_GPIO 0x22 +#define PMCIN_SAS_DIAG_MODE_START_END 0x23 +#define PMCIN_SAS_DIAG_EXECUTE 0x24 +#define PMCIN_SAW_HW_EVENT_ACK 0x25 +#define PMCIN_GET_TIME_STAMP 0x26 +#define PMCIN_PORT_CONTROL 0x27 +#define PMCIN_GET_NVMD_DATA 0x28 +#define PMCIN_SET_NVMD_DATA 0x29 +#define PMCIN_SET_DEVICE_STATE 0x2A +#define PMCIN_GET_DEVICE_STATE 0x2B + +/* + * General Inbound Queue related parameters (DWORD 4) + */ +#define PMCIN_MESSAGE_REPORT (1 << 2) +#define PMCIN_DS_ABORT_TASK (1 << 3) +#define PMCIN_DS_IN_RECOVERY (1 << 4) +#define PMCIN_DATADIR_NONE (0x00 << 8) +#define PMCIN_DATADIR_2_INI (0x01 << 8) +#define PMCIN_DATADIR_2_DEV (0x02 << 8) + + +/* + * SATA Host IO Start ATA Protocol Types + * (placed into DWORD 4) + */ + +#define SATA_PROTOCOL_SRST_ASSERT (0x01 << 10) +#define SATA_PROTOCOL_SRT_DEASSERT (0x02 << 10) +#define SATA_PROTOCOL_EXECDEVDIAG (0x03 << 10) +#define SATA_PROTOCOL_NONDATA (0x04 << 10) +#define SATA_PROTOCOL_PIO (0x05 << 10) +#define SATA_PROTOCOL_DMA (0x06 << 10) +#define SATA_PROTOCOL_FPDMA (0x07 << 10) + +/* + * SAS Host IO Start TLR definitions + * (placed into DWORD 4) + */ +#define SAS_TLR_ALL 0 /* SAS 1.1 and SAS 2.0 per device mode page */ +#define SAS_TLR_ON 1 /* unconditionally on */ +#define SAS_TLR_OFF 2 /* unconditionally off */ +#define SAS_TLR_SAS2 3 /* SAS 2.0 per device mode page */ + +/* + * IOP SMP Request Information + */ +#define SMP_INDIRECT_RESPONSE 0x01 +#define SMP_INDIRECT_REQUEST 0x02 +#define SMP_PHY_OVERRIDE 0x04 +#define SMP_REQUEST_LENGTH_SHIFT 16 + +/* + * PHY Start related definitions + */ +#define PHY_LINK_1_5 0x01 +#define PHY_LINK_3 0x02 +#define PHY_LINK_6 0x04 +#define PHY_LINK_ALL (PHY_LINK_1_5 | PHY_LINK_3 | PHY_LINK_6) +#define PHY_LINK_SHIFT 8 + +#define PHY_LM_SAS 1 +#define PHY_LM_SATA 2 +#define PHY_LM_AUTO 3 +#define PHY_MODE_SHIFT 12 + +#define PHY_SPINUP_HOLD (1 << 14) + +/* + * LOCAL PHY CONTROL related definitions + */ + +/* + * Device Registration related definitions + */ +#define PMCS_DEVREG_LINK_RATE_SHIFT 24 +#define PMCS_DEVREG_TYPE_SATA 0 +#define PMCS_DEVREG_TYPE_SAS (1 << 28) +#define PMCS_DEVREG_TYPE_SATA_DIRECT (1 << 29) + +#define PMCS_PHYID_SHIFT 4 /* level 0 registration only */ +#define PMCS_DEVREG_TLR 0x1 /* Transport Layer Retry */ + +#define PMCS_DEVREG_IT_NEXUS_TIMEOUT 200U + +#define PMCS_DEVREG_HA 0x2 /* Host Assigned upper 16 */ + /* bits for device ID. */ +/* + * These are used for getting/setting data in the NVRAM (SEEPROM, VPD, etc.) + */ + +typedef struct pmcs_get_nvmd_cmd_s { + uint32_t header; /* DWORD 0 */ + uint32_t htag; /* DWORD 1 */ + uint8_t tdas_nvmd; /* DWORD 2 */ + uint8_t tbn_tdps; + uint8_t tda; + uint8_t ip; + uint8_t doa[3]; /* DWORD 3 Data Offset Addr */ + uint8_t d_len; /* Direct Pld Data Len */ + uint32_t rsvd[8]; /* DWORDS 4-11 */ + uint32_t ipbal; /* 12 - Ind Pld buf addr low */ + uint32_t ipbah; /* 13 - Ind Pld buf addr high */ + uint32_t ipdl; /* 14 - Ind Pld data length */ + uint32_t rsvd3; +} pmcs_get_nvmd_cmd_t; + +typedef struct pmcs_set_nvmd_cmd_s { + uint32_t header; /* DWORD 0 */ + uint32_t htag; /* DWORD 1 */ + uint8_t tdas_nvmd; /* DWORD 2 */ + uint8_t tbn_tdps; + uint8_t tda; + uint8_t ip; + uint8_t doa[3]; /* DWORD 3 Data Offset Addr */ + uint8_t d_len; /* Direct Pld Data Len */ + uint32_t signature; /* DWORD 4 */ + uint32_t rsvd[7]; /* DWORDS 5-11 */ + uint32_t ipbal; /* 12 - Ind Pld buf addr low */ + uint32_t ipbah; /* 13 - Ind Pld buf addr high */ + uint32_t ipdl; /* 14 - Ind Pld data length */ + uint32_t rsvd2; +} pmcs_set_nvmd_cmd_t; + +#define PMCIN_NVMD_DIRECT_PLD 0x00 +#define PMCIN_NVMD_INDIRECT_PLD 0x80 + +/* TWI bus number is upper 4 bits of tbn_tdps */ +#define PMCIN_NVMD_TBN(x) (x << 4) + +/* TWI Device Page Size bits (lower 4 bits of tbn_tdps */ +#define PMCIN_NVMD_TDPS_1 0 /* 1 byte */ +#define PMCIN_NVMD_TDPS_8 1 /* 8 bytes */ +#define PMCIN_NVMD_TDPS_16 2 /* 16 bytes */ +#define PMCIN_NVMD_TDPS_32 3 /* 32 bytes */ + +/* TWI Device Address Size (upper 4 bits of tdas_nvmd) */ +#define PMCIN_NVMD_TDAS_1 (0 << 4) /* 1 byte */ +#define PMCIN_NVMD_TDAS_2 (1 << 4) /* 2 bytes */ + +/* + * TWI Device Address + * The address used to access TWI device for the 2Kb SEEPROM device is + * arranged as follows: + * Bits 7-4 are fixed (0xA) + * Bits 3-1 are page numbers for each 256 byte page + * Bit 0: Set to "1" to read, "0" to write + * Bit 0 is set/reset by the firmware based on whether the command is a + * SET or a GET. + */ +#define PMCIN_TDA_BASE 0xA0 +#define PMCIN_TDA_PAGE(x) (PMCIN_TDA_BASE | (x << 1)) + +/* NVM Device bits (lower 4 bits of tdas_nvmd) */ +#define PMCIN_NVMD_TWI 0 /* TWI Device */ +#define PMCIN_NVMD_SEEPROM 1 /* SEEPROM Device */ +#define PMCIN_NVMD_VPD 4 /* VPD Flash Memory */ +#define PMCIN_NVMD_AAP1 5 /* AAP1 Register Dump */ +#define PMCIN_NVMD_IOP 6 /* IOP Register Dump */ + +#define PMCS_SEEPROM_PAGE_SIZE 256 + +/* + * Minimum and maximum sizes of SPCBoot image + */ +#define PMCS_SPCBOOT_MIN_SIZE 64 +#define PMCS_SPCBOOT_MAX_SIZE 512 + +#define PMCS_SEEPROM_SIGNATURE 0xFEDCBA98 + +/* + * Register dump information + * + * There are two 16KB regions for register dump information + */ + +#define PMCS_REGISTER_DUMP_FLASH_SIZE (1024 * 16) +#define PMCS_REGISTER_DUMP_BLOCK_SIZE 4096 /* Must be read 4K at a time */ +#define PMCS_FLASH_CHUNK_SIZE 4096 /* Must be read 4K at a time */ +#define PMCS_REG_DUMP_SIZE (1024 * 1024 * 12) +#define PMCS_NVMD_EVENT_LOG_OFFSET 0x10000 +#define PMCS_IQP_TRACE_BUFFER_SIZE (1024 * 512) + +/* + * The list of items we can retrieve via the GET_NVMD_DATA command + */ + +typedef enum { + PMCS_NVMD_VPD = 0, + PMCS_NVMD_REG_DUMP, + PMCS_NVMD_EVENT_LOG, + PMCS_NVMD_SPCBOOT +} pmcs_nvmd_type_t; + +/* + * Command types, descriptors and offsets for SAS_DIAG_EXECUTE. + */ +#define PMCS_DIAG_CMD_DESC_SHIFT 8 +#define PMCS_DIAG_CMD_SHIFT 13 +#define PMCS_DIAG_REPORT_GET 0x04 /* Get counters */ +#define PMCS_ERR_CNT_RESET 0x05 /* Clear counters */ +#define PMCS_DISPARITY_ERR_CNT 0x02 /* Disparity error count */ +#define PMCS_LOST_DWORD_SYNC_CNT 0x05 /* Lost DWord sync count */ +#define PMCS_INVALID_DWORD_CNT 0x06 /* Invalid DWord count */ +#define PMCS_RESET_FAILED_CNT 0x0C /* PHY reset failed count */ + +/* + * VPD data layout + */ + +#define PMCS_VPD_DATA_PAGE 2 /* VPD starts at offset 512 */ +#define PMCS_VPD_VERSION 2 /* Expected version number */ +#define PMCS_VPD_RO_BYTE 0x90 /* Start of "read-only" data */ +#define PMCS_VPD_START 0x82 /* VPD start byte */ +#define PMCS_VPD_END 0x78 /* VPD end byte */ + +/* + * This structure defines the "header" for the VPD data. Everything + * following this structure is self-defining. The consumer just needs + * to allocate a buffer large enough for vpd_length + 3 bytes of data. + */ + +typedef struct { + uint8_t eeprom_version; + uint8_t vpd_length[2]; /* # bytes that follow, little-endian */ + uint8_t hba_sas_wwid[8]; + uint8_t subsys_pid[2]; + uint8_t subsys_vid[2]; + uint8_t vpd_start_byte; /* 0x82 */ + uint8_t strid_length[2]; /* little-endian */ + /* strid_length bytes follow */ +} pmcs_vpd_header_t; + +typedef struct { + char keyword[2]; + uint8_t value_length; + char value[1]; /* Length is actually value_length */ +} pmcs_vpd_kv_t; + +/* + * From here on out are definitions related to Outbound Queues + * (completions of Inbound Queue requests and async events) + */ + +/* + * PMC IOMB Outbound Queue Opcodes + */ +#define PMCOUT_ECHO 0x01 +#define PMCOUT_GET_INFO 0x02 +#define PMCOUT_GET_VPD 0x03 +#define PMCOUT_SAS_HW_EVENT 0x04 +#define PMCOUT_SSP_COMPLETION 0x05 +#define PMCOUT_SMP_COMPLETION 0x06 +#define PMCOUT_LOCAL_PHY_CONTROL 0x07 +#define PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT 0x08 +#define PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT 0x09 +#define PMCOUT_DEVICE_REGISTRATION 0x0A +#define PMCOUT_DEREGISTER_DEVICE_HANDLE 0x0B +#define PMCOUT_GET_DEVICE_HANDLE 0x0C +#define PMCOUT_SATA_COMPLETION 0x0D +#define PMCOUT_SATA_EVENT 0x0E +#define PMCOUT_SSP_EVENT 0x0F +#define PMCOUT_DEVICE_HANDLE_ARRIVED 0x10 +#define PMCOUT_SMP_REQUEST_RECEIVED 0x11 +#define PMCOUT_SSP_REQUEST_RECEIVED 0x12 +#define PMCOUT_DEVICE_INFO 0x13 +#define PMCOUT_FW_FLASH_UPDATE 0x14 +#define PMCOUT_SET_VPD 0x15 +#define PMCOUT_GPIO 0x16 +#define PMCOUT_GPIO_EVENT 0x17 +#define PMCOUT_GENERAL_EVENT 0x18 +#define PMCOUT_TWI 0x19 +#define PMCOUT_SSP_ABORT 0x1A +#define PMCOUT_SATA_ABORT 0x1B +#define PMCOUT_SAS_DIAG_MODE_START_END 0x1C +#define PMCOUT_SAS_DIAG_EXECUTE 0x1D +#define PMCOUT_GET_TIME_STAMP 0x1E +#define PMCOUT_SAS_HW_EVENT_ACK_ACK 0x1F +#define PMCOUT_PORT_CONTROL 0x20 +#define PMCOUT_SKIP_ENTRIES 0x21 +#define PMCOUT_SMP_ABORT 0x22 +#define PMCOUT_GET_NVMD_DATA 0x23 +#define PMCOUT_SET_NVMD_DATA 0x24 +#define PMCOUT_DEVICE_HANDLE_REMOVED 0x25 +#define PMCOUT_SET_DEVICE_STATE 0x26 +#define PMCOUT_GET_DEVICE_STATE 0x27 +#define PMCOUT_SET_DEVICE_INFO 0x28 + +/* + * General Outbound Status Definitions + */ +#define PMCOUT_STATUS_OK 0x00 +#define PMCOUT_STATUS_ABORTED 0x01 +#define PMCOUT_STATUS_OVERFLOW 0x02 +#define PMCOUT_STATUS_UNDERFLOW 0x03 +#define PMCOUT_STATUS_FAILED 0x04 +#define PMCOUT_STATUS_ABORT_RESET 0x05 +#define PMCOUT_STATUS_IO_NOT_VALID 0x06 +#define PMCOUT_STATUS_NO_DEVICE 0x07 +#define PMCOUT_STATUS_ILLEGAL_PARAMETER 0x08 +#define PMCOUT_STATUS_LINK_FAILURE 0x09 +#define PMCOUT_STATUS_PROG_ERROR 0x0A +#define PMCOUT_STATUS_EDC_IN_ERROR 0x0B +#define PMCOUT_STATUS_EDC_OUT_ERROR 0x0C +#define PMCOUT_STATUS_ERROR_HW_TIMEOUT 0x0D +#define PMCOUT_STATUS_XFER_ERR_BREAK 0x0E +#define PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY 0x0F +#define PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED 0x10 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION 0x11 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_BREAK 0x12 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS 0x13 +#define PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION 0x14 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED 0x15 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY 0x16 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION 0x17 +#define PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_EROOR 0x18 +#define PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED 0x19 +#define PMCOUT_STATUS_XFER_ERROR_ACK_NAK_TIMEOUT 0x1A +#define PMCOUT_STATUS_XFER_ERROR_PEER_ABORTED 0x1B +#define PMCOUT_STATUS_XFER_ERROR_RX_FRAME 0x1C +#define PMCOUT_STATUS_IO_XFER_ERROR_DMA 0x1D +#define PMCOUT_STATUS_XFER_ERROR_CREDIT_TIMEOUT 0x1E +#define PMCOUT_STATUS_XFER_ERROR_SATA_LINK_TIMEOUT 0x1F +#define PMCOUT_STATUS_XFER_ERROR_SATA 0x20 +#define PMCOUT_STATUS_XFER_ERROR_REJECTED_NCQ_MODE 0x21 +#define PMCOUT_STATUS_XFER_ERROR_ABORTED_DUE_TO_SRST 0x22 +#define PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE 0x23 +#define PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT 0x24 +#define PMCOUT_STATUS_SMP_RESP_CONNECTION_ERROR 0x25 +#define PMCOUT_STATUS_XFER_ERROR_UNEXPECTED_PHASE 0x26 +#define PMCOUT_STATUS_XFER_ERROR_RDY_OVERRUN 0x27 +#define PMCOUT_STATUS_XFER_ERROR_RDY_NOT_EXPECTED 0x28 +/* 0x29 */ +/* 0x2A */ +/* 0x2B */ +/* 0x2C */ +/* 0x2D */ +/* 0x2E */ +/* 0x2F */ +#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT 0x30 +#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK 0x31 +#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK 0x32 +/* 0x33 */ +#define PMCOUT_STATUS_XFER_ERROR_OFFSET_MISMATCH 0x34 +#define PMCOUT_STATUS_XFER_ERROR_ZERO_DATA_LEN 0x35 +#define PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED 0x36 +#define PMCOUT_STATUS_ERROR_INTERNAL_SMP_RESOURCE 0x37 +#define PMCOUT_STATUS_IO_PORT_IN_RESET 0x38 +#define PMCOUT_STATUS_IO_DS_NON_OPERATIONAL 0x39 +#define PMCOUT_STATUS_IO_DS_IN_RECOVERY 0x3A +#define PMCOUT_STATUS_IO_ABORT_IN_PROGRESS 0x40 + +/* + * Device State definitions + */ +#define PMCS_DEVICE_STATE_OPERATIONAL 0x1 +#define PMCS_DEVICE_STATE_PORT_IN_RESET 0x2 +#define PMCS_DEVICE_STATE_IN_RECOVERY 0x3 +#define PMCS_DEVICE_STATE_IN_ERROR 0x4 +#define PMCS_DEVICE_STATE_NON_OPERATIONAL 0x7 + +/* + * Reset Types + */ +#define PMCS_SSP_LINK_RESET 0x1 +#define PMCS_SSP_HARD_RESET 0x2 +#define PMCS_SMP_HARD_RESET 0x3 + +/* + * PHYOP for LOCAL_PHY_CONTROL Command + */ +#define PMCS_PHYOP_LINK_RESET 0x01 +#define PMCS_PHYOP_HARD_RESET 0x02 + +/* + * Specialized status values + */ +/* PHY Stop Status Results */ +#define IOP_PHY_STOP_OK 0x0 +#define IOP_PHY_STOP_INVALID 0x1 +#define IOP_PHY_STOP_ERROR 0x3 +#define IOP_PHY_STOP_ALREADY 0x4 + +/* PHY Start Status Results */ +#define IOP_PHY_START_OK 0 +#define IOP_PHY_START_INVALID 1 +#define IOP_PHY_START_ALREADY 2 +#define IOP_PHY_START_ERROR 3 + +/* SET/GET_NVMD status results */ +#define PMCS_NVMD_STAT_SUCCESS 0x0000 +#define PMCS_NVMD_STAT_PLD_NVMD_COMB_ERR 0x0001 +#define PMCS_NVMD_STAT_PLD_LEN_ERR 0x0002 +#define PMCS_NVMD_STAT_TWI_DEV_NACK 0x2001 +#define PMCS_NVMD_STAT_TWI_DEV_LOST_ARB 0x2002 +#define PMCS_NVMD_STAT_TWI_TIMEOUT 0x2021 +#define PMCS_NVMD_STAT_TWI_BUS_NACK 0x2081 +#define PMCS_NVMD_STAT_TWI_DEV_ARB_FAIL 0x2082 +#define PMCS_NVMD_STAT_TWI_BUS_SER_TIMEO 0x20FF +#define PMCS_NVMD_STAT_PART_NOT_IN_FLASH 0x9001 +#define PMCS_NVMD_STAT_LEN_TOO_LARGE 0x9002 +#define PMCS_NVMD_STAT_FLASH_PRGRM_FAIL 0x9003 +#define PMCS_NVMD_STAT_DEVID_MATCH_FAIL 0x9004 +#define PMCS_NVMD_STAT_VENDID_MATCH_FAIL 0x9005 +#define PMCS_NVMD_STAT_SEC_ERASE_TIMEO 0x9006 +#define PMCS_NVMD_STAT_SEC_ERASE_CWE 0x9007 +#define PMCS_NVMD_STAT_FLASH_DEV_BUSY 0x9008 +#define PMCS_NVMD_STAT_FLASH_DEV_NOT_SUP 0x9009 +#define PMCS_NVMD_STAT_FLASH_NO_CFI 0x900A +#define PMCS_NVMD_STAT_ERASE_BLOCKS 0x900B +#define PMCS_NVMD_STAT_PART_READ_ONLY 0x900C +#define PMCS_NVMD_STAT_PART_INV_MAP_TYPE 0x900D +#define PMCS_NVMD_STAT_PART_INIT_STR_DIS 0x900E + +/* + * General Event Status Codes + */ +#define INBOUND_IOMB_V_BIT_NOT_SET 0x1 +#define INBOUND_IOMB_OPC_NOT_SUPPORTED 0x2 + +/* Device Register Status Results */ +#define PMCS_DEVREG_OK 0x0 +#define PMCS_DEVREG_DEVICE_ALREADY_REGISTERED 0x2 +#define PMCS_DEVREG_PHY_ALREADY_REGISTERED 0x4 + +/* + * Flash Update responses + */ +#define FLASH_UPDATE_COMPLETE_PENDING_REBOOT 0x0 +#define FLASH_UPDATE_IN_PROGRESS 0x1 +#define FLASH_UPDATE_HDR_ERR 0x2 +#define FLASH_UPDATE_OFFSET_ERR 0x3 +#define FLASH_UPDATE_UPDATE_CRC_ERR 0x4 +#define FLASH_UPDATE_LENGTH_ERR 0x5 +#define FLASH_UPDATE_HW_ERR 0x6 +#define FLASH_UPDATE_DNLD_NOT_SUPPORTED 0x10 +#define FLASH_UPDATE_DISABLED 0x11 + +/* + * IOP SAS HW Event Related definitions + */ + +#define IOP_EVENT_LINK_RATE(x) ((x >> 28) & 0xf) +#define IOP_EVENT_STATUS(x) ((x >> 24) & 0xf) +#define IOP_EVENT_EVENT(x) ((x >> 8) & 0xffff) +#define IOP_EVENT_PHYNUM(x) ((x >> 4) & 0xf) +#define IOP_EVENT_PORTID(x) ((x) & 0xf) + + +#define IOP_EVENT_PHY_STOP_STATUS 0x03 +#define IOP_EVENT_SAS_PHY_UP 0x04 +#define IOP_EVENT_SATA_PHY_UP 0x05 +#define IOP_EVENT_SATA_SPINUP_HOLD 0x06 +#define IOP_EVENT_PHY_DOWN 0x07 +#define IOP_EVENT_PORT_INVALID 0x08 /* < fw 1.6 */ +#define IOP_EVENT_BROADCAST_CHANGE 0x09 +#define IOP_EVENT_BROADCAST_SES 0x0B +#define IOP_EVENT_PHY_ERR_INBOUND_CRC 0x0C +#define IOP_EVENT_HARD_RESET_RECEIVED 0x0D +#define IOP_EVENT_EVENT_ID_FRAME_TIMO 0x0F +#define IOP_EVENT_BROADCAST_EXP 0x10 +#define IOP_EVENT_PHY_START_STATUS 0x11 +#define IOP_EVENT_PHY_ERR_INVALID_DWORD 0x12 +#define IOP_EVENT_PHY_ERR_DISPARITY_ERROR 0x13 +#define IOP_EVENT_PHY_ERR_CODE_VIOLATION 0x14 +#define IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN 0x15 +#define IOP_EVENT_PHY_ERR_PHY_RESET_FAILD 0x16 +#define IOP_EVENT_PORT_RECOVERY_TIMER_TMO 0x17 +#define IOP_EVENT_PORT_RECOVER 0x18 +#define IOP_EVENT_PORT_RESET_TIMER_TMO 0x19 +#define IOP_EVENT_PORT_RESET_COMPLETE 0x20 +#define IOP_EVENT_BROADCAST_ASYNC_EVENT 0x21 + + +#define IOP_EVENT_PORT_STATE(x) ((x) & 0xf) +#define IOP_EVENT_NPIP(x) (((x) >> 4) & 0xf) + +#define IOP_EVENT_PS_NIL 0x0 /* PORT_ID not valid yet */ +#define IOP_EVENT_PS_VALID 0x1 /* PORT_ID now valid */ +#define IOP_EVENT_PS_LOSTCOMM 0x2 /* Link temporarily down */ +#define IOP_EVENT_PS_IN_RESET 0x4 /* Port in reset */ +#define IOP_EVENT_PS_INVALID 0x8 /* PORT_ID now dead */ + +/* + * HW Event Acknowledge Response Values + */ +#define SAS_HW_EVENT_ACK_OK 0x0 +#define SAS_HW_EVENT_ACK_INVALID_SEA 0x1 +#define SAS_HW_EVENT_ACK_INVALID_PHY 0x2 +#define SAS_HW_EVENT_ACK_INVALID_PORT 0x4 +#define SAS_HW_EVENT_ACK_INVALID_PARAM 0x8 + +/* + * IOMB Queue definitions and Macros + */ + +#define ADDQI(ix, n, qd) ((ix + n) & (qd - 1)) +#define INCQI(ix, qd) ix = ADDQI(ix, 1, qd) +#define QI2O(ix, n, qd) (ADDQI(ix, n, qd) * PMCS_QENTRY_SIZE) + +/* + * Inbound Queue Producer Indices live inside the PMC card. + * + * Inbound Queue Consumer indices live in host memory. We use the Consumer + * Index to return a pointer to an Inbound Queue entry. We then can fill + * it with an IOMB. We then update the the Producer index which kicks + * card to read the IOMB we just wrote. + * + * There is one mutex for each inbound queue that is held from the time + * we get an entry until we increment the producer index, or released + * manually if we don't actually send the message. + */ + +/* + * NB: the appropriate iqp_lock must be held + */ +#define GET_IQ_ENTRY(hwp, qnum) \ + ((ADDQI(hwp->shadow_iqpi[qnum], 1, hwp->ioq_depth) == \ + pmcs_rd_iqci(hwp, qnum)) ? NULL : \ + &hwp->iqp[qnum][hwp->shadow_iqpi[qnum] * (PMCS_QENTRY_SIZE >> 2)]) + +/* + * NB: This releases the lock on the Inbound Queue that GET_IO_IQ_ENTRY + * acquired below. + */ +#ifdef DEBUG +#define INC_IQ_ENTRY(hwp, qnum) \ +{ \ + uint32_t htag; \ + ASSERT(mutex_owned(&(hwp)->iqp_lock[qnum])); \ + htag = hwp->iqp[qnum][(hwp->shadow_iqpi[qnum] * \ + (PMCS_QENTRY_SIZE >> 2)) + 1]; \ + mutex_enter(&(hwp)->dbglock); \ + pmcs_iqp_trace(hwp, qnum); \ + mutex_exit(&(hwp)->dbglock); \ + INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth); \ + if (ddi_dma_sync(hwp->cip_handles, 0, 0, \ + DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) { \ + pmcs_prt(hwp, PMCS_PRT_DEBUG, "Condition failed at " \ + " %s():%d", __func__, __LINE__); \ + } \ + pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]); \ + mutex_exit(&(hwp)->iqp_lock[qnum]); \ + mutex_enter(&(hwp)->dbglock); \ + hwp->ftag_lines[hwp->fti] = __LINE__; \ + hwp->ftime[hwp->fti] = gethrtime(); \ + hwp->ftags[hwp->fti++] = htag; \ + mutex_exit(&(hwp)->dbglock); \ +} +#else +#define INC_IQ_ENTRY(hwp, qnum) \ + INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth); \ + if (ddi_dma_sync(hwp->cip_handles, 0, 0, \ + DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) { \ + pmcs_prt(hwp, PMCS_PRT_DEBUG, "Condition failed at " \ + " %s():%d", __func__, __LINE__); \ + } \ + pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]); \ + mutex_exit(&(hwp)->iqp_lock[qnum]) +#endif + + +/* + * NB: sucessfull acquisition of an IO Inbound Queue + * entry leaves the lock on that Inbound Queue held. + */ +#define GET_IO_IQ_ENTRY(pwp, msg, did, iq) \ + iq = did & PMCS_IO_IQ_MASK; \ + mutex_enter(&(pwp)->iqp_lock[iq]); \ + msg = GET_IQ_ENTRY(pwp, iq); \ + if (msg == NULL) { \ + mutex_exit(&(pwp)->iqp_lock[iq]); \ + for (iq = 0; iq <= PMCS_NON_HIPRI_QUEUES; iq++) { \ + mutex_enter(&(pwp)->iqp_lock[iq]); \ + msg = GET_IQ_ENTRY(pwp, iq); \ + if (msg) { \ + break; \ + } \ + mutex_exit(&(pwp->iqp_lock[iq])); \ + } \ + } + +/* + * Outbound Queue Macros + * + * Outbound Queue Consumer indices live inside the card. + * + * Outbound Queue Producer indices live in host memory. When the card + * wants to send an IOMB, it uses the producer index to find the spot + * to write the IOMB. After it's done it updates the producer index + * and interrupts the host. The host reads the producer index (from + * host memory) and reads IOMBs up to but not including that index. + * It writes that index back to the consumer index on the card, + * signifying that it has read up to that which the card has sent. + */ +#define GET_OQ_ENTRY(hwp, qn, ix, o) \ + &hwp->oqp[qn][QI2O(ix, o, hwp->ioq_depth) >> 2] + +#define STEP_OQ_ENTRY(hwp, qn, ix, n) ix = ADDQI(ix, n, hwp->ioq_depth) + +#define SYNC_OQ_ENTRY(hwp, qn, ci, pi) \ + pmcs_wr_oqci(hwp, qn, ci); \ + (hwp)->oqci[qn] = ci; \ + (hwp)->oqpi[qn] = pi + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_IOMB_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_mpi.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_mpi.h new file mode 100644 index 0000000000..b0c875e871 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_mpi.h @@ -0,0 +1,222 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * PMC 8x6G Message Passing Interface Definitions + */ +#ifndef _PMCS_MPI_H +#define _PMCS_MPI_H +#ifdef __cplusplus +extern "C" { +#endif + +#define PMCS_DWRD(x) (x << 2) + +/* + * MPI Configuration Table Offsets + */ +#define PMCS_MPI_AS PMCS_DWRD(0) /* ASCII Signature */ +#define PMCS_SIGNATURE 0x53434D50 + +#define PMCS_MPI_IR PMCS_DWRD(1) /* Interface Revision */ +#define PMCS_MPI_REVISION1 1 + +#define PMCS_MPI_FW PMCS_DWRD(2) /* Firmware Version */ +#define PMCS_FW_TYPE(hwp) (hwp->fw & 0xf) +#define PMCS_FW_TYPE_RELEASED 0 +#define PMCS_FW_TYPE_DEVELOPMENT 1 +#define PMCS_FW_TYPE_ALPHA 2 +#define PMCS_FW_TYPE_BETA 3 +#define PMCS_FW_VARIANT(hwp) ((hwp->fw >> 4) & 0xf) +#define PMCS_FW_MAJOR(hwp) ((hwp->fw >> 24) & 0xff) +#define PMCS_FW_MINOR(hwp) ((hwp->fw >> 16) & 0xff) +#define PMCS_FW_MICRO(hwp) ((hwp->fw >> 8) & 0xff) +#define PMCS_FW_REV(hwp) ((hwp->fw >> 8) & 0xffffff) +#define PMCS_FW_VERSION(maj, min, mic) ((maj << 16)|(min << 8)|mic) + +#define PMCS_MPI_MOIO PMCS_DWRD(3) /* Maximum # of outstandiong I/Os */ +#define PMCS_MPI_INFO0 PMCS_DWRD(4) /* Maximum S/G Elem, Max Dev Handle */ +#define PMCS_MSGL(x) (x & 0xffff) +#define PMCS_MD(x) ((x >> 16) & 0xffff) + +#define PMCS_MPI_INFO1 PMCS_DWRD(5) /* Info #0 */ + +#define PMCS_MNIQ(x) (x & 0xff) /* Max # of Inbound Queues */ +#define PMCS_MNOQ(x) ((x >> 8) & 0xff) /* Max # of Outbound Queues */ +#define PMCS_HPIQ(x) ((x >> 16) & 0x1) /* High Pri Queue Supported */ +#define PMCS_ICS(x) ((x >> 18) & 0x1) /* Interrupt Coalescing */ +#define PMCS_NPHY(x) ((x >> 19) & 0x3f) /* Numbers of PHYs */ +#define PMCS_SASREV(x) ((x >> 25) & 0x7) /* SAS Revision Specification */ + +#define PMCS_MPI_GSTO PMCS_DWRD(6) /* General Status Table Offset */ +#define PMCS_MPI_IQCTO PMCS_DWRD(7) /* Inbound Queue Config Table Offset */ +#define PMCS_MPI_OQCTO PMCS_DWRD(8) /* Outbound Queue Config Table Offset */ + +#define PMCS_MPI_INFO2 PMCS_DWRD(9) /* Info #1 */ + +#define IQ_NORMAL_PRI_DEPTH_SHIFT 0 +#define IQ_NORMAL_PRI_DEPTH_MASK 0xff +#define IQ_HIPRI_PRI_DEPTH_SHIFT 8 +#define IQ_HIPRI_PRI_DEPTH_MASK 0xff00 +#define GENERAL_EVENT_OQ_SHIFT 16 +#define GENERAL_EVENT_OQ_MASK 0xff0000 +#define DEVICE_HANDLE_REMOVED_SHIFT 24 +#define DEVICE_HANDLE_REMOVED_MASK 0xff000000ul + +#define PMCS_MPI_EVQS PMCS_DWRD(0xA) /* SAS Event Queues */ +#define PMCS_MPI_EVQSET(pwp, oq, phy) { \ + uint32_t woff = phy / 4; \ + uint32_t shf = (phy % 4) * 8; \ + uint32_t tmp = pmcs_rd_mpi_tbl(pwp, PMCS_MPI_EVQS + (woff << 2)); \ + tmp &= ~(0xff << shf); \ + tmp |= ((oq & 0xff) << shf); \ + pmcs_wr_mpi_tbl(pwp, PMCS_MPI_EVQS + (woff << 2), tmp); \ +} + +#define PMCS_MPI_SNCQ PMCS_DWRD(0xC) /* Sata NCQ Notification Queues */ +#define PMCS_MPI_NCQSET(pwp, oq, phy) { \ + uint32_t woff = phy / 4; \ + uint32_t shf = (phy % 4) * 8; \ + uint32_t tmp = pmcs_rd_mpi_tbl(pwp, PMCS_MPI_SNCQ + (woff << 2)); \ + tmp &= ~(0xff << shf); \ + tmp |= ((oq & 0xff) << shf); \ + pmcs_wr_mpi_tbl(pwp, PMCS_MPI_SNCQ + (woff << 2), tmp); \ +} + +/* + * I_T Nexus Target Event Notification Queue + */ +#define PMCS_MPI_IT_NTENQ PMCS_DWRD(0xE) + +/* + * SSP Target Event Notification Queue + */ +#define PMCS_MPI_SSP_TENQ PMCS_DWRD(0x10) + +/* + * SMP Target Event Notification Queue + */ +#define PMCS_MPI_SMP_TENQ PMCS_DWRD(0x12) + +/* + * This specifies a log buffer in host memory for the MSGU. + */ +#define PMCS_MPI_MELBAH PMCS_DWRD(0x14) /* MSGU Log Buffer high 32 bits */ +#define PMCS_MPI_MELBAL PMCS_DWRD(0x15) /* MSGU Log Buffer low 32 bits */ +#define PMCS_MPI_MELBS PMCS_DWRD(0x16) /* size in bytes of MSGU log buffer */ +#define PMCS_MPI_MELSEV PMCS_DWRD(0x17) /* Log Severity */ + +/* + * This specifies a log buffer in host memory for the IOP. + */ +#define PMCS_MPI_IELBAH PMCS_DWRD(0x18) /* IOP Log Buffer high 32 bits */ +#define PMCS_MPI_IELBAL PMCS_DWRD(0x19) /* IOP Log Buffer low 32 bits */ +#define PMCS_MPI_IELBS PMCS_DWRD(0x1A) /* size in bytes of IOP log buffer */ +#define PMCS_MPI_IELSEV PMCS_DWRD(0x1B) /* Log Severity */ + +/* + * Fatal Error Handling + */ +#define PMCS_MPI_FERR PMCS_DWRD(0x1C) +#define PMCS_FERRIE 0x1 /* Fatal Err Interrupt Enable */ +#define PMCS_FERIV_MASK 0xff00 /* Fatal Err Interrupt Mask */ +#define PMCS_FERIV_SHIFT 8 /* Fatal Err Interrupt Shift */ + +#define PMCS_MPI_IRAE 0x20000 /* Interrupt Reassertion Enable */ +#define PMCS_MPI_IRAU 0x40000 /* Interrupt Reassertion Unit */ +#define PMCS_MPI_IRAD_MASK 0xfff80000 /* Reassertion Delay Mask */ + +#define PMCS_FERDOMSGU PMCS_DWRD(0x1D) +#define PMCS_FERDLMSGU PMCS_DWRD(0x1E) +#define PMCS_FERDOIOP PMCS_DWRD(0x1F) +#define PMCS_FERDLIOP PMCS_DWRD(0x20) + +/* + * MPI GST Table Offsets + */ + +#define PMCS_GST_BASE 0 +#define PMCS_GST_IQFRZ0 (PMCS_GST_BASE + PMCS_DWRD(1)) +#define PMCS_GST_IQFRZ1 (PMCS_GST_BASE + PMCS_DWRD(2)) +#define PMCS_GST_MSGU_TICK (PMCS_GST_BASE + PMCS_DWRD(3)) +#define PMCS_GST_IOP_TICK (PMCS_GST_BASE + PMCS_DWRD(4)) +#define PMCS_GST_PHY_INFO(x) (PMCS_GST_BASE + PMCS_DWRD(0x6) + PMCS_DWRD(x)) +#define PMCS_GST_RERR_BASE (PMCS_GST_BASE + PMCS_DWRD(0x11)) +#define PMCS_GST_RERR_INFO(x) (PMCS_GST_RERR_BASE + PMCS_DWRD(x)) + +#define PMCS_MPI_S(x) ((x) & 0x7) +#define PMCS_QF(x) (((x) >> 3) & 0x1) +#define PMCS_GSTLEN(x) (((x) >> 4) & 0x3fff) +#define PMCS_HMI_ERR(x) (((x) >> 16) & 0xffff) + +#define PMCS_MPI_STATE_NIL 0 +#define PMCS_MPI_STATE_INIT 1 +#define PMCS_MPI_STATE_DEINIT 2 +#define PMCS_MPI_STATE_ERR 3 + +/* + * MPI Inbound Queue Configuration Table Offsets + * + * Each Inbound Queue configuration area consumes 8 DWORDS (32 bit words), + * or 32 bytes. + */ +#define PMCS_IQC_PARMX(x) ((x) << 5) +#define PMCS_IQBAHX(x) (((x) << 5) + 4) +#define PMCS_IQBALX(x) (((x) << 5) + 8) +#define PMCS_IQCIBAHX(x) (((x) << 5) + 12) +#define PMCS_IQCIBALX(x) (((x) << 5) + 16) +#define PMCS_IQPIBARX(x) (((x) << 5) + 20) +#define PMCS_IQPIOFFX(x) (((x) << 5) + 24) +#define PMCS_IQDX(x) ((x) & 0xffff) +#define PMCS_IQESX(x) (((x) >> 16) & 0x3fff) +#define PMCS_IQPX(x) (((x) >> 30) & 0x3) + +/* + * MPI Outbound Queue Configuration Table Offsets + * + * Each Outbound Queue configuration area consumes 9 DWORDS (32 bit words), + * or 36 bytes. + */ +#define PMCS_OQC_PARMX(x) (x * 36) +#define PMCS_OQBAHX(x) ((x * 36) + 4) +#define PMCS_OQBALX(x) ((x * 36) + 8) +#define PMCS_OQPIBAHX(x) ((x * 36) + 12) +#define PMCS_OQPIBALX(x) ((x * 36) + 16) +#define PMCS_OQCIBARX(x) ((x * 36) + 20) +#define PMCS_OQCIOFFX(x) ((x * 36) + 24) +#define PMCS_OQIPARM(x) ((x * 36) + 28) +#define PMCS_OQDICX(x) ((x * 36) + 32) + +#define PMCS_OQDX(x) ((x) & 0xffff) +#define PMCS_OQESX(x) (((x) >> 16) & 0x3fff) +#define PMCS_OQICT(x) ((x) & 0xffff) +#define PMCS_OQICC(x) (((x) >> 16) & 0xff) +#define PMCS_OQIV(x) (((x) >> 24) & 0xff) + +#define OQIEX (1 << 30) + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_MPI_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_param.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_param.h new file mode 100644 index 0000000000..0522ce6e88 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_param.h @@ -0,0 +1,138 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * PMC Compile Time Tunable Parameters + */ +#ifndef _PMCS_PARAM_H +#define _PMCS_PARAM_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Maximum number of microseconds we will try to configure a PHY + */ +#define PMCS_MAX_CONFIG_TIME (60 * 1000000) + +#define PMCS_MAX_OQ 64 /* maximum number of OutBound Queues */ +#define PMCS_MAX_IQ 64 /* maximum number of InBound Queues */ + +#define PMCS_MAX_PORTS 16 /* maximum port contexts */ + +#define PMCS_MAX_XPND 16 /* 16 levels of expansion */ + +#define PMCS_INDICES_SIZE 512 + +#define PMCS_MIN_CHUNK_PAGES 512 +#define PMCS_ADDTL_CHUNK_PAGES 8 + +/* + * Scratch area has to hold Max SMP Request and Max SMP Response, + * plus some slop. + */ +#define PMCS_SCRATCH_SIZE 2304 +#define PMCS_INITIAL_DMA_OFF PMCS_INDICES_SIZE+PMCS_SCRATCH_SIZE +#define PMCS_CONTROL_SIZE ptob(1) + +/* + * 2M bytes was allocated to firmware log and split between two logs + */ +#define PMCS_FWLOG_SIZE (2 << 20) +#define PMCS_FWLOG_MAX 5 /* maximum logging level */ +#define SATLSIZE 1024 + +/* + * PMCS_NQENTRY is tunable by setting pmcs-num-io-qentries + */ +#define PMCS_NQENTRY 512 /* 512 entries per queue */ +#define PMCS_MIN_NQENTRY 32 /* No less than 32 entries per queue */ +#define PMCS_QENTRY_SIZE 64 /* 64 bytes per entry */ +#define PMCS_MSG_SIZE (PMCS_QENTRY_SIZE >> 2) + +/* + * Watchdog interval, in usecs. + * NB: Needs to be evenly divisible by 10 + */ +#define PMCS_WATCH_INTERVAL 250000 /* watchdog interval in us */ + +/* + * Inbound Queue definitions + */ +#define PMCS_NIQ 9 /* 9 Inbound Queues */ +#define PMCS_IO_IQ_MASK 7 /* IO queues are 0..7 */ +#define PMCS_IQ_OTHER 8 /* "Other" queue is 8 (HiPri) */ +#define PMCS_NON_HIPRI_QUEUES PMCS_IO_IQ_MASK + +/* + * Outbound Queue definitions + * + * Note that the OQ definitions map to bits set in + * the Outbound Doorbell register to indicate service + * is needed on one of these queues. + */ +#define PMCS_NOQ 3 /* 3 Outbound Queues */ + +#define PMCS_OQ_IODONE 0 /* I/O completion Outbound Queue */ +#define PMCS_OQ_GENERAL 1 /* General Outbound Queue */ +#define PMCS_OQ_EVENTS 2 /* Event Outbound Queue */ + + +/* + * External Scatter Gather come in chunks- each this many deep. + */ +#define PMCS_SGL_NCHUNKS 16 /* S/G List Chunk Size */ +#define PMCS_MAX_CHUNKS 32 /* max chunks per command */ + +/* + * MSI/MSI-X related definitions. + * + * These are the maximum number of interrupt vectors we could use. + */ +#define PMCS_MAX_MSIX (PMCS_NOQ + 1) +#define PMCS_MAX_MSI PMCS_MAX_MSIX +#define PMCS_MAX_FIXED 1 + +#define PMCS_MSIX_IODONE PMCS_OQ_IODONE /* I/O Interrupt vector */ +#define PMCS_MSIX_GENERAL PMCS_OQ_GENERAL /* General Interrupt vector */ +#define PMCS_MSIX_EVENTS PMCS_OQ_EVENTS /* Events Interrupt vector */ +#define PMCS_MSIX_FATAL (PMCS_MAX_MSIX-1) /* Fatal Int vector */ + +#define PMCS_FATAL_INTERRUPT 15 /* fatal interrupt OBDB bit */ + +/* + * Blessed firmware version + */ +#define PMCS_FIRMWARE_CODE_NAME "firmware" +#define PMCS_FIRMWARE_ILA_NAME "ila" +#define PMCS_FIRMWARE_SPCBOOT_NAME "SPCBoot" +#define PMCS_FIRMWARE_START_SUF ".bin_start" +#define PMCS_FIRMWARE_END_SUF ".bin_end" +#define PMCS_FIRMWARE_FILENAME "misc/pmcs/pmcs8001fw" +#define PMCS_FIRMWARE_VERSION_NAME "pmcs8001_fwversion" + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_PARAM_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h new file mode 100644 index 0000000000..d28b0a56ef --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h @@ -0,0 +1,353 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file provides prototype function definitions. + */ +#ifndef _PMCS_PROTO_H +#define _PMCS_PROTO_H +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum { + PMCS_PRT_DEBUG = 0, + PMCS_PRT_DEBUG1, + PMCS_PRT_DEBUG2, + PMCS_PRT_DEBUG3, + PMCS_PRT_DEBUG_CONFIG, + PMCS_PRT_DEBUG_IPORT, + PMCS_PRT_DEBUG_MAP, + PMCS_PRT_DEBUG_UNDERFLOW, + PMCS_PRT_DEBUG_SCSI_STATUS, + PMCS_PRT_DEBUG_PHY_LOCKING, + PMCS_PRT_DEBUG_DEV_STATE, + PMCS_PRT_DEBUG_DEVEL, + PMCS_PRT_INFO, + PMCS_PRT_WARN, + PMCS_PRT_ERR +} pmcs_prt_level_t; + +#define pmcs_prt(pwp, level, fmt...) { \ + int lvl = level; \ + if (((pwp->debug_mask & (1 << lvl)) != 0) || \ + (lvl > PMCS_PRT_DEBUG_DEVEL)) { \ + pmcs_prt_impl(pwp, lvl, fmt); \ + } \ +} + +/*PRINTFLIKE3*/ +void +pmcs_prt_impl(pmcs_hw_t *, pmcs_prt_level_t, const char *, ...) + __KPRINTFLIKE(3); + +boolean_t pmcs_assign_device(pmcs_hw_t *, pmcs_xscsi_t *); +void pmcs_remove_device(pmcs_hw_t *, pmcs_phy_t *); +void pmcs_handle_dead_phys(pmcs_hw_t *); + +int pmcs_acquire_scratch(pmcs_hw_t *, boolean_t); +void pmcs_release_scratch(pmcs_hw_t *); + +/* get a work structure */ +pmcwork_t *pmcs_gwork(pmcs_hw_t *, uint32_t, pmcs_phy_t *); + +/* put a work structure */ +void pmcs_pwork(pmcs_hw_t *, struct pmcwork *); + +/* given a tag, find a work structure */ +pmcwork_t *pmcs_tag2wp(pmcs_hw_t *, uint32_t); + +/* + * Abort function + */ +int pmcs_abort(pmcs_hw_t *, pmcs_phy_t *, uint32_t, int, int); + +/* + * SSP Task Management Function + */ +int pmcs_ssp_tmf(pmcs_hw_t *, pmcs_phy_t *, uint8_t, uint32_t, uint64_t, + uint32_t *); + +/* + * Abort NCQ function + */ +int pmcs_sata_abort_ncq(pmcs_hw_t *, pmcs_phy_t *); + +/* + * Interrupt Functions + */ +void pmcs_general_intr(pmcs_hw_t *); +void pmcs_iodone_intr(pmcs_hw_t *); +void pmcs_event_intr(pmcs_hw_t *); +void pmcs_timed_out(pmcs_hw_t *, uint32_t, const char *); + +/* + * Abort handler + */ +int pmcs_abort_handler(pmcs_hw_t *); + +/* + * Deregister all expander connected devices + */ +void pmcs_deregister_devices(pmcs_hw_t *, pmcs_phy_t *); +int pmcs_register_device(pmcs_hw_t *, pmcs_phy_t *); +void pmcs_deregister_device(pmcs_hw_t *, pmcs_phy_t *); + +/* + * endian transform a data structure + */ +void pmcs_endian_transform(pmcs_hw_t *, void *, void *, const uint8_t *); + +/* get the connection rate string */ +const char *pmcs_get_rate(unsigned int); + +/* get the device type string */ +const char *pmcs_get_typename(pmcs_dtype_t pmcs_dtype); + +/* get the SAS Task Management function name */ +const char *pmcs_tmf2str(int); + +/* get the PMC status string */ +const char *pmcs_status_str(uint32_t); + +/* + * WWN to Byte Array and vice versa conversion + */ +uint64_t pmcs_barray2wwn(uint8_t[8]); +void pmcs_wwn2barray(uint64_t, uint8_t[8]); + +/* + * Print f/w version + */ +void pmcs_report_fwversion(pmcs_hw_t *); + +/* + * Build a device name. + */ +void pmcs_phy_name(pmcs_hw_t *, pmcs_phy_t *, char *, size_t); + +/* + * Find a PHY by device_id + */ +pmcs_phy_t *pmcs_find_phy_by_devid(pmcs_hw_t *, uint32_t); + +/* + * Find a PHY by wwn + */ +pmcs_phy_t *pmcs_find_phy_by_wwn(pmcs_hw_t *, uint64_t); + +/* + * Find a PHY by sas_address + */ +pmcs_phy_t *pmcs_find_phy_by_sas_address(pmcs_hw_t *, pmcs_iport_t *, + pmcs_phy_t *, char *); + +/* + * Print out a FIS + */ +void pmcs_fis_dump(pmcs_hw_t *, fis_t); + +/* + * Print an IOMB + */ +void pmcs_print_entry(pmcs_hw_t *, int, char *, void *); + +void pmcs_spinup_release(pmcs_hw_t *, pmcs_phy_t *phyp); + +/* + * Handler for events - can be called from interrupt level or from worker thread + */ +void pmcs_ack_events(pmcs_hw_t *); + +/* + * This function does some initial setup and hardware validation + */ +int pmcs_setup(pmcs_hw_t *); + +/* + * These functions start and stop the MPI (message passing interface) + */ +int pmcs_start_mpi(pmcs_hw_t *); +int pmcs_stop_mpi(pmcs_hw_t *); + +/* + * This function checks firmware revisions against required revisions + * and attempts to flash new firmware (if possible). + */ +int pmcs_firmware_update(pmcs_hw_t *); + +/* + * This function runs ECHO commands to test both interrupts and queues + */ +int pmcs_echo_test(pmcs_hw_t *); + +/* + * These functions start, reset, and stop the physical chip PHYs + */ +int pmcs_start_phy(pmcs_hw_t *, int, int, int); +int pmcs_start_phys(pmcs_hw_t *); +void pmcs_stop_phy(pmcs_hw_t *, int); +void pmcs_stop_phys(pmcs_hw_t *); + +/* + * These functions setup/teardown iport tgtmap + */ +int pmcs_iport_tgtmap_create(pmcs_iport_t *); +int pmcs_iport_tgtmap_destroy(pmcs_iport_t *); + +/* + * Utility and wrapper functions for SAS_DIAG_EXECUTE + */ +int pmcs_sas_diag_execute(pmcs_hw_t *, uint32_t, uint32_t, uint8_t); +int pmcs_get_diag_report(pmcs_hw_t *, uint32_t, uint8_t); +int pmcs_clear_diag_counters(pmcs_hw_t *, uint8_t); + +/* + * Get current firmware timestamp + */ +int pmcs_get_time_stamp(pmcs_hw_t *, uint64_t *); + +/* + * Register Dump (including "internal" registers) + */ +void pmcs_register_dump(pmcs_hw_t *); +void pmcs_iqp_trace(pmcs_hw_t *, uint32_t); +void pmcs_register_dump_int(pmcs_hw_t *); +int pmcs_dump_binary(pmcs_hw_t *, uint32_t *, uint32_t, + uint32_t, caddr_t, uint32_t); +int pmcs_dump_feregs(pmcs_hw_t *, uint32_t *, uint8_t, + caddr_t, uint32_t); + +/* + * This function perform a soft reset. + * Hard reset is platform specific. + */ +int pmcs_soft_reset(pmcs_hw_t *, boolean_t); + +/* + * Some more reset functions + */ +int pmcs_reset_dev(pmcs_hw_t *, pmcs_phy_t *, uint64_t); +int pmcs_reset_phy(pmcs_hw_t *, pmcs_phy_t *, uint8_t); + +/* + * These functions do topology configuration changes + */ +void pmcs_discover(pmcs_hw_t *); +void pmcs_set_changed(pmcs_hw_t *, pmcs_phy_t *, boolean_t, int); +void pmcs_kill_changed(pmcs_hw_t *, pmcs_phy_t *, int); +void pmcs_clear_phy(pmcs_hw_t *, pmcs_phy_t *); +int pmcs_kill_device(pmcs_hw_t *, pmcs_phy_t *); + +/* + * Firmware flash function + */ +int pmcs_fw_flash(pmcs_hw_t *, pmcs_fw_hdr_t *, uint32_t); + +/* + * Set a new value for the interrupt coalescing timer. If it's being set + * to zero (disabling), then re-enable auto clear if necessary. If it's + * being changed from zero, turn off auto clear if it was on. + */ +typedef enum { + DECREASE_TIMER = 0, + INCREASE_TIMER +} pmcs_coal_timer_adj_t; + +void pmcs_check_intr_coal(void *arg); +void pmcs_set_intr_coal_timer(pmcs_hw_t *pwp, pmcs_coal_timer_adj_t adj); + +/* + * Misc supporting routines + */ +void pmcs_check_iomb_status(pmcs_hw_t *pwp, uint32_t *iomb); +void pmcs_clear_xp(pmcs_hw_t *, pmcs_xscsi_t *); + +int pmcs_run_sata_cmd(pmcs_hw_t *, pmcs_phy_t *, fis_t, uint32_t, + uint32_t, uint32_t); +int pmcs_sata_identify(pmcs_hw_t *, pmcs_phy_t *); +void pmcs_sata_work(pmcs_hw_t *); +boolean_t pmcs_dma_setup(pmcs_hw_t *pwp, ddi_dma_attr_t *dma_attr, + ddi_acc_handle_t *acch, ddi_dma_handle_t *dmah, size_t length, + caddr_t *kvp, uint64_t *dma_addr); +void pmcs_fm_ereport(pmcs_hw_t *pwp, char *detail); +int pmcs_check_dma_handle(ddi_dma_handle_t handle); +int pmcs_check_acc_handle(ddi_acc_handle_t handle); +int pmcs_check_acc_dma_handle(pmcs_hw_t *pwp); +int pmcs_get_nvmd(pmcs_hw_t *pwp, pmcs_nvmd_type_t nvmd_type, uint8_t nvmd, + uint32_t offset, char *buf, uint32_t size_left); +boolean_t pmcs_set_nvmd(pmcs_hw_t *pwp, pmcs_nvmd_type_t nvmd_type, + uint8_t *buf, size_t len); +void pmcs_complete_work_impl(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb, + size_t amt); +void pmcs_flush_target_queues(pmcs_hw_t *, pmcs_xscsi_t *, uint8_t); +boolean_t pmcs_iport_has_targets(pmcs_hw_t *, pmcs_iport_t *); +void pmcs_free_dma_chunklist(pmcs_hw_t *); +int pmcs_get_dev_state(pmcs_hw_t *, pmcs_xscsi_t *, uint8_t *); +int pmcs_set_dev_state(pmcs_hw_t *, pmcs_xscsi_t *, uint8_t); +void pmcs_dev_state_recovery(pmcs_hw_t *, pmcs_phy_t *); +int pmcs_send_err_recovery_cmd(pmcs_hw_t *, uint8_t, pmcs_xscsi_t *); +void pmcs_start_ssp_event_recovery(pmcs_hw_t *pwp, pmcwork_t *pwrk, + uint32_t *iomb, size_t amt); +void pmcs_ssp_event_recovery(pmcs_hw_t *); + +pmcs_iport_t *pmcs_get_iport_by_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr); +void pmcs_rele_iport(pmcs_iport_t *iport); +int pmcs_iport_configure_phys(pmcs_iport_t *iport); + +void pmcs_lock_phy(pmcs_phy_t *); +void pmcs_unlock_phy(pmcs_phy_t *); + +void pmcs_destroy_target(pmcs_xscsi_t *); +void pmcs_phymap_activate(void *, char *, void **); +void pmcs_phymap_deactivate(void *, char *, void *); +void pmcs_add_phy_to_iport(pmcs_iport_t *, pmcs_phy_t *); +void pmcs_remove_phy_from_iport(pmcs_iport_t *, pmcs_phy_t *); +void pmcs_free_all_phys(pmcs_hw_t *, pmcs_phy_t *); +void pmcs_free_phys(pmcs_hw_t *, pmcs_phy_t *); + +int pmcs_phy_constructor(void *, void *, int); +void pmcs_phy_destructor(void *, void *); + +void pmcs_inc_phy_ref_count(pmcs_phy_t *); +void pmcs_dec_phy_ref_count(pmcs_phy_t *); + +/* Worker thread */ +void pmcs_worker(void *); + +pmcs_phy_t *pmcs_get_root_phy(pmcs_phy_t *); +pmcs_xscsi_t *pmcs_get_target(pmcs_iport_t *, char *); + +void pmcs_fatal_handler(pmcs_hw_t *); + +/* + * Schedule device state recovery for this device immediately + */ +void pmcs_start_dev_state_recovery(pmcs_xscsi_t *, pmcs_phy_t *); + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_PROTO_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_reg.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_reg.h new file mode 100644 index 0000000000..dd85718f7e --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_reg.h @@ -0,0 +1,378 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * PMC 8x6G register definitions + */ +#ifndef _PMCS_REG_H +#define _PMCS_REG_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * PCI Constants + */ +#define PMCS_VENDOR_ID 0x11F8 +#define PMCS_DEVICE_ID 0x8001 + +#define PMCS_PM8001_REV_A 0 +#define PMCS_PM8001_REV_B 1 +#define PMCS_PM8001_REV_C 2 + +#define PMCS_REGSET_0 1 +#define PMCS_REGSET_1 2 +#define PMCS_REGSET_2 3 +#define PMCS_REGSET_3 4 + + +/* + * PCIe BARs - 4 64KB memory regions + * + * BAR0-1 64KiB + * BAR2-3 64KiB + * BAR4 64KiB + * BAR5 64KiB + */ + +/* + * The PMC 8x6G registers are defined by BARs in PCIe space. + * + * Four memory region BARS are used. + * + * The first is for the Messaging Unit. + * + * The second 64KiB region contains the PCS/PMA registers and some of the + * Top-Level registers. + * + * The third 64KiB region is a 64KiB window on the rest of the chip registers + * which can be shifted by writing a register in the second region. + * + * The fourth 64KiB region is for the message passing area. + */ + +/* + * Messaging Unit Register Offsets + */ +#define PMCS_MSGU_IBDB 0x04 /* Inbound Doorbell */ +#define PMCS_MSGU_IBDB_CLEAR 0x20 /* InBound Doorbell Clear */ +#define PMCS_MSGU_OBDB 0x3c /* OutBound Doorbell */ +#define PMCS_MSGU_OBDB_CLEAR 0x40 /* OutBound Doorbell Clear */ +#define PMCS_MSGU_SCRATCH0 0x44 /* Scratchpad 0 */ +#define PMCS_MSGU_SCRATCH1 0x48 /* Scratchpad 1 */ +#define PMCS_MSGU_SCRATCH2 0x4C /* Scratchpad 2 */ +#define PMCS_MSGU_SCRATCH3 0x50 /* Scratchpad 3 */ +#define PMCS_MSGU_HOST_SCRATCH0 0x54 /* Host Scratchpad 0 */ +#define PMCS_MSGU_HOST_SCRATCH1 0x58 /* Host Scratchpad 1 */ +#define PMCS_MSGU_HOST_SCRATCH2 0x5C /* Host Scratchpad 2 */ +#define PMCS_MSGU_HOST_SCRATCH3 0x60 /* Host Scratchpad 3 */ +#define PMCS_MSGU_HOST_SCRATCH4 0x64 /* Host Scratchpad 4 */ +#define PMCS_MSGU_HOST_SCRATCH5 0x68 /* Host Scratchpad 5 */ +#define PMCS_MSGU_HOST_SCRATCH6 0x6C /* Host Scratchpad 6 */ +#define PMCS_MSGU_HOST_SCRATCH7 0x70 /* Host Scratchpad 7 */ +#define PMCS_MSGU_OBDB_MASK 0x74 /* Outbound Doorbell Mask */ + +/* + * Inbound Doorbell and Doorbell Clear Definitions + * NB: The Doorbell Clear register is only used on RevA/8000 parts. + */ +#define PMCS_MSGU_IBDB_MPIIU 0x08 /* Initiate Unfreeze */ +#define PMCS_MSGU_IBDB_MPIIF 0x04 /* Initiate Freeze */ +#define PMCS_MSGU_IBDB_MPICTU 0x02 /* Initiate MPI Termination */ +#define PMCS_MSGU_IBDB_MPIINI 0x01 /* Initiate MPI */ + +/* + * Outbound Doorbell and Doorbell Clear Register + * + * The Doorbell Clear register is only used on RevA/8000 parts. + * + * Each bit of the ODR is mapped 1-to-1 to a MSI or MSI-X vector + * table entry. There are 32 MSI and 16 MSI-X entries. The top + * 16 bits are mapped to the low 16 bits for MSI-X. For legacy + * INT-X, any bit will generate a host interrupt. + * + * Each bit in the Outbound Doorbell Clear is used to clear the + * corresponding bit in the ODR. For INT-X it also then deasserts + * any interrupt condition. + */ +#define PMCS_MSI_INTS 32 +#define PMCS_MSIX_INTS 16 + +/* + * Scratchpad 0 Definitions + * + * When the AAP is ready state (see Scratchpad 1), bits 31:26 is the offset + * within PCIe space for another BAR that, when mapped, will point to a region + * that conains the MPI Configuration table (the offset of which is in bits + * 25:0 of this register) + * + * When the AAP is in error state, this register contains additional error + * information. + */ +#define PMCS_MSGU_MPI_BAR_SHIFT 26 +#define PMCS_MSGU_MPI_OFFSET_MASK ((1 << PMCS_MSGU_MPI_BAR_SHIFT) - 1) + +/* + * Scratchpad 1 Definitions + * + * The bottom two bits are the AAP state of the 8x6G. + * + * When the AAP is in error state, bits 31:10 contain the error indicator. + * + */ +#define PMCS_MSGU_AAP_STATE_MASK 0x03 +#define PMCS_MSGU_AAP_STATE_POR 0 +#define PMCS_MSGU_AAP_STATE_SOFT_RESET 1 +#define PMCS_MSGU_AAP_STATE_ERROR 2 +#define PMCS_MSGU_AAP_STATE_READY 3 +#define PMCS_MSGU_AAP_SFR_PROGRESS 0x04 +#define PMCS_MSGU_AAP_ERROR_MASK 0xfffffc00 + +/* + * Scratchpad 2 Definitions + * + * Bits 31:10 contain error information if the IOP is in error state. + */ +#define PMCS_MSGU_IOP_STATE_MASK 0x03 +#define PMCS_MSGU_IOP_STATE_POR 0 +#define PMCS_MSGU_IOP_STATE_SOFT_RESET 1 +#define PMCS_MSGU_IOP_STATE_ERROR 2 +#define PMCS_MSGU_IOP_STATE_READY 3 + +#define PMCS_MSGU_HOST_SOFT_RESET_READY 0x04 +#define PMCS_MSGU_CPU_SOFT_RESET_READY 0x08 + +/* + * Scratchpad 3 Definitions + * + * Contains additional error information if the IOP is in error state + * (see Scratchpad 2) + */ + +/* + * Host Scratchpad 0 + * Soft Reset Signature + */ +#define HST_SFT_RESET_SIG 0x252ACBCD + +/* + * Host Scratchpad 1 + * + * This is a bit mask for freeze or unfreeze operations for IQs 0..31 + */ + +/* + * Host Scratchpad 2 + * + * This is a bit mask for freeze or unfreeze operations for IQs 32..63 + */ + +/* + * Outbound Doorbell Mask Register + * + * Each bit set here masks bits and interrupt assertion for the corresponding + * bit (and vector) in the ODR. + */ + +/* + * GSM Registers + */ +#define GSM_BASE_MASK 0x00ffff +#define NMI_EN_VPE0_IOP 0x60418 +#define NMI_EN_VPE0_AAP1 0x70418 +#define RB6_ACCESS 0x6A80C0 +#define GSM_CFG_AND_RESET 0x700000 +#define RAM_ECC_DOUBLE_ERROR_INDICATOR 0x700018 +#define READ_ADR_PARITY_CHK_EN 0x700038 +#define WRITE_ADR_PARITY_CHK_EN 0x700040 +#define WRITE_DATA_PARITY_CHK_EN 0x700048 +#define READ_ADR_PARITY_ERROR_INDICATOR 0x700058 +#define WRITE_ADR_PARITY_ERROR_INDICATOR 0x700060 +#define WRITE_DATA_PARITY_ERROR_INDICATOR 0x700068 + +/* + * GSM Share Memory, IO Status Table and Ring Buffer + */ +#define GSM_SM_BLKSZ 0x10000 +#define GSM_SM_BASE 0x400000 +#define IO_STATUS_TABLE_BASE 0x640000 +#define RING_BUF_STORAGE_0 0x680000 +#define RING_BUF_STORAGE_1 0x690000 +#define RING_BUF_PTR_ACC_BASE 0x6A0000 + +#define IO_STATUS_TABLE_BLKNM 0x4 +#define GSM_SM_BLKNM 0x10 +#define RING_BUF_PTR_OFF 0x1000 +#define RING_BUF_PTR_SIZE 0xFF8 +#define RING_BUF_ACC_OFF 0x8000 +#define RING_BUF_ACC_SIZE 0xFF8 + +/* + * GSM Configuration and Reset Bits + */ +#define MST_XCBI_SW_RSTB (1 << 14) +#define COM_SLV_SW_RSTB (1 << 13) +#define QSSP_SW_RSTB (1 << 12) +#define RAAE_SW_RSTB (1 << 11) +#define RB_1_SW_RSTB (1 << 9) +#define SM_SW_RSTB (1 << 8) + +#define COHERENCY_GAP_SHIFT 4 +#define COHERENCY_GAP_MASK 0xf0 +#define COHERENCY_GAP_DEFAULT (8 << COHERENCY_GAP_SHIFT) + +#define COHERENCY_MODE (1 << 3) +#define RB_WSTRB_ERRCHK_EN (1 << 2) +#define RAAE_PORT2_EN (1 << 1) +#define GSM_WCI_MODE (1 << 0) +#define PMCS_SOFT_RESET_BITS \ + (COM_SLV_SW_RSTB|QSSP_SW_RSTB|RAAE_SW_RSTB|RB_1_SW_RSTB|SM_SW_RSTB) + +#define RB6_NMI_SIGNATURE 0x00001234 + +/* + * PMCS PCI Configuration Registers + */ +#define PMCS_PCI_PMC 0x40 +#define PMCS_PCI_PMCSR 0x44 +#define PMCS_PCI_MSI 0x50 +#define PMCS_PCI_MAL 0x54 +#define PMCS_PCI_MAU 0x58 +#define PMCS_PCI_MD 0x5C +#define PMCS_PCI_PCIE 0x70 +#define PMCS_PCI_DEV_CAP 0x74 +#define PMCS_PCI_DEV_CTRL 0x78 +#define PMCS_PCI_LINK_CAP 0x7C +#define PMCS_PCI_LINK_CTRL 0x80 +#define PMCS_PCI_MSIX_CAP 0xAC +#define PMCS_PCI_TBL_OFFSET 0xB0 +#define PMCS_PCI_PBA_OFFSET 0xB4 +#define PMCS_PCI_PCIE_CAP_HD 0x100 +#define PMCS_PCI_UE_STAT 0x104 +#define PMCS_PCI_UE_MASK 0x108 +#define PMCS_PCI_UE_SEV 0x10C +#define PMCS_PCI_CE_STAT 0x110 +#define PMCS_PCI_CE_MASK 0x114 +#define PMCS_PCI_ADV_ERR_CTRL 0x118 +#define PMCS_PCI_HD_LOG_DW 0x11C + +/* + * Top Level Registers + */ +/* these registers are in MEMBASE-III */ +#define PMCS_SPC_RESET 0x0 +#define PMCS_SPC_BOOT_STRAP 0x8 +#define PMCS_SPC_DEVICE_ID 0x20 +#define PMCS_DEVICE_REVISION 0x24 +/* these registers are in MEMBASE-II */ +#define PMCS_EVENT_INT_ENABLE 0x3040 +#define PMCS_EVENT_INT_STAT 0x3044 +#define PMCS_ERROR_INT_ENABLE 0x3048 +#define PMCS_ERROR_INT_STAT 0x304C +#define PMCS_AXI_TRANS 0x3258 +#define PMCS_OBDB_AUTO_CLR 0x335C +#define PMCS_INT_COALESCING_TIMER 0x33C0 +#define PMCS_INT_COALESCING_CONTROL 0x33C4 + + +/* + * Chip Reset Register Bits (PMCS_SPC_RESET) + * + * NB: all bits are inverted. That is, the normal state is '1'. + * When '0' is set, the action is taken. + */ +#define PMCS_SPC_HARD_RESET 0x00 +#define PMCS_SPC_HARD_RESET_CLR 0xffffffff + + +#define SW_DEVICE_RSTB (1 << 31) +#define PCIE_PC_SXCBI_ARESETN (1 << 26) +#define PMIC_CORE_RSTB (1 << 25) +#define PMIC_SXCBI_ARESETN (1 << 24) +#define LMS_SXCBI_ARESETN (1 << 23) +#define PCS_SXCBI_ARESETN (1 << 22) +#define PCIE_SFT_RSTB (1 << 21) +#define PCIE_PWR_RSTB (1 << 20) +#define PCIE_AL_SXCBI_ARESETN (1 << 19) +#define BDMA_SXCBI_ARESETN (1 << 18) +#define BDMA_CORE_RSTB (1 << 17) +#define DDR2_RSTB (1 << 16) +#define GSM_RSTB (1 << 8) +#define PCS_RSTB (1 << 7) +#define PCS_LM_RSTB (1 << 6) +#define PCS_AAP2_SS_RSTB (1 << 5) +#define PCS_AAP1_SS_RSTB (1 << 4) +#define PCS_IOP_SS_RSTB (1 << 3) +#define PCS_SPBC_RSTB (1 << 2) +#define RAAE_RSTB (1 << 1) +#define OSSP_RSTB (1 << 0) + + +/* + * Timer Enables Register + */ +#define PMCS_TENABLE_WINDOW_OFFSET 0x30000 +#define PMCS_TENABLE_BASE 0x0209C +#define PMCS_TENABLE_MULTIPLIER 0x04000 + +/* + * Special register (MEMBASE-III) for Step 5.5 in soft reset sequence to set + * GPIO into tri-state mode (temporary workaround for 1.07.xx beta firmware) + */ +#define PMCS_GPIO_TRISTATE_MODE_ADDR 0x9010C +#define PMCS_GPIO_TSMODE_BIT0 (1 << 0) +#define PMCS_GPIO_TSMODE_BIT1 (1 << 1) + + +/* + * Register Access Inline Functions + */ +uint32_t pmcs_rd_msgunit(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_gsm_reg(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_topunit(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_mpi_tbl(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_gst_tbl(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_iqc_tbl(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_oqc_tbl(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_iqci(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_iqpi(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_oqci(pmcs_hw_t *, uint32_t); +uint32_t pmcs_rd_oqpi(pmcs_hw_t *, uint32_t); + +void pmcs_wr_msgunit(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_gsm_reg(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_topunit(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_mpi_tbl(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_gst_tbl(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_iqc_tbl(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_oqc_tbl(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_iqci(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_iqpi(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_oqci(pmcs_hw_t *, uint32_t, uint32_t); +void pmcs_wr_oqpi(pmcs_hw_t *, uint32_t, uint32_t); + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_REG_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_scsa.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_scsa.h new file mode 100644 index 0000000000..19db949654 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_scsa.h @@ -0,0 +1,92 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * SCSI (SCSA) midlayer interface for PMC drier. + */ +#ifndef _PMCS_SCSA_H +#define _PMCS_SCSA_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scsi/scsi_types.h> + +#define ADDR2TRAN(ap) ((ap)->a_hba_tran) +#define ADDR2PMC(ap) (ITRAN2PMC(ADDR2TRAN(ap))) + +#define CMD2TRAN(cmd) (CMD2PKT(cmd)->pkt_address.a_hba_tran) +#define CMD2PMC(cmd) (ITRAN2PMC(CMD2TRAN(cmd))) + +#define PKT2ADDR(pkt) (&((pkt)->pkt_address)) +#define PKT2CMD(pkt) ((pmcs_cmd_t *)(pkt->pkt_ha_private)) +#define CMD2PKT(sp) (sp->cmd_pkt) +#define PMCS_STATUS_LEN 264 + +#define TRAN2PMC(tran) ((pmcs_hw_t *)(tran)->tran_hba_private) +#define ITRAN2PMC(tran) \ + (((pmcs_iport_t *)(tran)->tran_hba_private)->pwp) +#define ITRAN2IPORT(tran) \ + ((pmcs_iport_t *)(tran)->tran_hba_private) + +/* + * Wrapper around scsi_pkt. + */ +struct pmcs_cmd { + struct scsi_pkt *cmd_pkt; /* actual SCSI Packet */ + STAILQ_ENTRY(pmcs_cmd) cmd_next; /* linked list */ + pmcs_dmachunk_t *cmd_clist; /* list of dma chunks */ + pmcs_xscsi_t *cmd_target; /* Pointer to target */ + pmcs_lun_t *cmd_lun; /* Pointer to LU */ + uint32_t cmd_tag; /* PMC htag */ + uint8_t cmd_satltag; /* SATL tag */ +}; + +#define SCSA_CDBLEN(sp) sp->cmd_pkt->pkt_cdblen +#define SCSA_STSLEN(sp) sp->cmd_pkt->pkt_scblen +#define SCSA_TGTLEN(sp) sp->cmd_pkt->pkt_tgtlen + +#define PMCS_WQ_RUN_SUCCESS 0 +#define PMCS_WQ_RUN_FAIL_RES 1 /* Failed to alloc rsrcs (e.g. DMA chunks) */ +#define PMCS_WQ_RUN_FAIL_OTHER 2 /* Any other failure */ + +int pmcs_scsa_init(pmcs_hw_t *, const ddi_dma_attr_t *); + +void pmcs_latch_status(pmcs_hw_t *, pmcs_cmd_t *, uint8_t, uint8_t *, + size_t, char *); +size_t pmcs_set_resid(struct scsi_pkt *, size_t, uint32_t); +boolean_t pmcs_scsa_wq_run_one(pmcs_hw_t *, pmcs_xscsi_t *); +void pmcs_scsa_wq_run(pmcs_hw_t *); +void pmcs_scsa_cq_run(void *); + +int pmcs_config_one(pmcs_hw_t *, uint64_t, int, long, dev_info_t **); + +dev_info_t *pmcs_find_child_smp(pmcs_hw_t *, char *); +int pmcs_config_one_smp(pmcs_hw_t *, uint64_t, dev_info_t **); + +int pmcs_run_sata_special(pmcs_hw_t *, pmcs_xscsi_t *); +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_SCSA_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_sgl.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_sgl.h new file mode 100644 index 0000000000..e604ed751c --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_sgl.h @@ -0,0 +1,86 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _PMCS_SGL_H +#define _PMCS_SGL_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This is the strict physical representation of an external + * S/G list entry that the PMCS hardware uses. We manage them + * in chunks. + */ +typedef struct { + uint32_t sglal; /* Low 32 bit DMA address */ + uint32_t sglah; /* High 32 bit DMA address */ + uint32_t sglen; /* Length */ + uint32_t flags; +} pmcs_dmasgl_t; + +/* + * If this is bit is set in flags, then the address + * described by this structure is an array of SGLs, + * the last of which may contain *another* flag + * to continue the list. + */ +#define PMCS_DMASGL_EXTENSION (1U << 31) + +#define PMCS_SGL_CHUNKSZ (PMCS_SGL_NCHUNKS * (sizeof (pmcs_dmasgl_t))) + +/* + * This is how we keep track of chunks- we have a linked list of + * chunk pointers that are either on the free list or are tagged + * off of a SCSA command. We used to maintain offsets indices + * within the sglen area of the lest element of a chunk, but this + * is marked reserved and may not be reliably used future firmware + * revisions. + */ +typedef struct pmcs_dmachunk pmcs_dmachunk_t; +struct pmcs_dmachunk { + pmcs_dmachunk_t *nxt; + pmcs_dmasgl_t *chunks; + unsigned long addr; + ddi_acc_handle_t acc_handle; + ddi_dma_handle_t dma_handle; +}; + +/* + * DMA related functions + */ +int pmcs_dma_load(pmcs_hw_t *, pmcs_cmd_t *, uint32_t *); +void pmcs_dma_unload(pmcs_hw_t *, pmcs_cmd_t *); + +/* + * After allocating some DMA chunks, insert them + * into the free list and set them up for use. + */ +void pmcs_idma_chunks(pmcs_hw_t *, pmcs_dmachunk_t *, + pmcs_chunk_t *, unsigned long); + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_SGL_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_smhba.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_smhba.h new file mode 100644 index 0000000000..f952a34060 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_smhba.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * SM-HBA interfaces/definitions for PMC-S driver. + */ +#ifndef _PMCS_SMHBA_H +#define _PMCS_SMHBA_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Leverage definition of data_type_t in nvpair.h */ +#include <sys/nvpair.h> + +#define PMCS_NUM_PHYS "num-phys" +#define PMCS_NUM_PHYS_HBA "num-phys-hba" +#define PMCS_SMHBA_SUPPORTED "sm-hba-supported" +#define PMCS_DRV_VERSION "driver-version" +#define PMCS_HWARE_VERSION "hardware-version" +#define PMCS_FWARE_VERSION "firmware-version" +#define PMCS_SUPPORTED_PROTOCOL "supported-protocol" + +#define PMCS_MANUFACTURER "Manufacturer" +#define PMCS_SERIAL_NUMBER "SerialNumber" +#define PMCS_MODEL_NAME "ModelName" + +/* + * Interfaces to add properties required for SM-HBA + * + * _add_xxx_prop() interfaces add only 1 prop that is specified in the args. + * _set_xxx_props() interfaces add more than 1 prop for a set of phys/devices. + */ +void pmcs_smhba_add_hba_prop(pmcs_hw_t *, data_type_t, char *, void *); +void pmcs_smhba_add_iport_prop(pmcs_iport_t *, data_type_t, char *, void *); +void pmcs_smhba_add_tgt_prop(pmcs_xscsi_t *, data_type_t, char *, void *); + +void pmcs_smhba_set_scsi_device_props(pmcs_hw_t *, pmcs_phy_t *, + struct scsi_device *); +void pmcs_smhba_set_phy_props(pmcs_iport_t *); + +/* + * Misc routines supporting SM-HBA + */ +void pmcs_smhba_log_sysevent(pmcs_hw_t *, char *, char *, pmcs_phy_t *); + + +#ifdef __cplusplus +} +#endif +#endif /* _PMCS_SMHBA_H */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/smp_defs.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/smp_defs.h new file mode 100644 index 0000000000..508d316bf2 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/smp_defs.h @@ -0,0 +1,1100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This header file will only be used for pmcs driver temporarily. + * Will be deleted after smp_frames.h is updated. + */ + +#ifndef _SYS_SCSI_GENERIC_SMP_FRAMES_H +#define _SYS_SCSI_GENERIC_SMP_FRAMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/sysmacros.h> + +/* + * The definitions of smp frame types and functions conforming to SAS-1.1 and + * SAS-2. Consumers are expected to determine protocol support by examining + * the response to the REPORT GENERAL function. + */ + +/* Redefinition conflict with smp_frames.h. */ + +/* + * typedef enum smp_frame_type { + * SMP_FRAME_TYPE_REQUEST = 0x40, + * SMP_FRAME_TYPE_RESPONSE = 0x41 + * } smp_frame_type_t; + */ + +typedef enum smp_function { + SMP_FUNC_REPORT_GENERAL = 0x00, + SMP_FUNC_REPORT_MANUFACTURER_INFO = 0x01, + SMP_FUNC_READ_GPIO_REGISTER = 0x02, + SMP_FUNC_REPORT_SELF_CONFIG_STATUS = 0x03, + SMP_FUNC_REPORT_ZONE_PERM_TABLE = 0x04, + SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD = 0x05, + SMP_FUNC_REPORT_BROADCAST = 0x06, + SMP_FUNC_DISCOVER = 0x10, + SMP_FUNC_REPORT_PHY_ERROR_LOG = 0x11, + SMP_FUNC_REPORT_PHY_SATA = 0x12, + SMP_FUNC_REPORT_ROUTE_INFO = 0x13, + SMP_FUNC_REPORT_PHY_EVENT = 0x14, + SMP_FUNC_DISCOVER_LIST = 0x20, + SMP_FUNC_REPORT_PHY_EVENT_LIST = 0x21, + SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST = 0x22, + SMP_FUNC_CONFIG_GENERAL = 0x80, + SMP_FUNC_ENABLE_DISABLE_ZONING = 0x81, + SMP_FUNC_WRITE_GPIO_REGISTER = 0x82, + SMP_FUNC_ZONED_BROADCAST = 0x85, + SMP_FUNC_ZONE_LOCK = 0x86, + SMP_FUNC_ZONE_ACTIVATE = 0x87, + SMP_FUNC_ZONE_UNLOCK = 0x88, + SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD = 0x89, + SMP_FUNC_CONFIG_ZONE_PHY_INFO = 0x8A, + SMP_FUNC_CONFIG_ZONE_PERM_TABLE = 0x8B, + SMP_FUNC_CONFIG_ROUTE_INFO = 0x90, + SMP_FUNC_PHY_CONTROL = 0x91, + SMP_FUNC_PHY_TEST_FUNCTION = 0x92, + SMP_FUNC_CONFIG_PHY_EVENT = 0x93 +} smp_function_t; + +typedef enum smp_result { + SMP_RES_FUNCTION_ACCEPTED = 0x00, + SMP_RES_UNKNOWN_FUNCTION = 0x01, + SMP_RES_FUNCTION_FAILED = 0x02, + SMP_RES_INVALID_REQUEST_FRAME_LENGTH = 0x03, + SMP_RES_INVALID_EXPANDER_CHANGE_COUNT = 0x04, + SMP_RES_BUSY = 0x05, + SMP_RES_INCOMPLETE_DESCRIPTOR_LIST = 0x06, + SMP_RES_PHY_DOES_NOT_EXIST = 0x10, + SMP_RES_INDEX_DOES_NOT_EXIST = 0x11, + SMP_RES_PHY_DOES_NOT_SUPPORT_SATA = 0x12, + SMP_RES_UNKNOWN_PHY_OPERATION = 0x13, + SMP_RES_UNKNOWN_PHY_TEST_FUNCTION = 0x14, + SMP_RES_PHY_TEST_IN_PROGRESS = 0x15, + SMP_RES_PHY_VACANT = 0x16, + SMP_RES_UNKNOWN_PHY_EVENT_SOURCE = 0x17, + SMP_RES_UNKNOWN_DESCRIPTOR_TYPE = 0x18, + SMP_RES_UNKNOWN_PHY_FILTER = 0x19, + SMP_RES_AFFILIATION_VIOLATION = 0x1A, + SMP_RES_ZONE_VIOLATION = 0x20, + SMP_RES_NO_MANAGEMENT_ACCESS_RIGHTS = 0x21, + SMP_RES_UNKNOWN_ENABLE_DISABLE_ZONING = 0x22, + SMP_RES_ZONE_LOCK_VIOLATION = 0x23, + SMP_RES_NOT_ACTIVATED = 0x24, + SMP_RES_ZONE_GROUP_OUT_OF_RANGE = 0x25, + SMP_RES_NO_PHYSICAL_PRESENCE = 0x26, + SMP_RES_SAVING_NOT_SUPPORTED = 0x27, + SMP_RES_SOURCE_ZONE_GROUP_DNE = 0x28, + SMP_RES_NONE = -1 +} smp_result_t; + +/* + * SAS-2 10.4.3.2 request frame format + */ +typedef struct smp_request_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_allocated_response_len; /* reserved in SAS-1 */ + uint8_t srf_request_len; + uint8_t srf_data[1]; +} smp_request_frame_t; + +/* + * SAS-2 10.4.3.3 response frame format + */ +typedef struct smp_response_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_result; + uint8_t srf_response_len; /* reserved in SAS-1 */ + uint8_t srf_data[1]; +} smp_response_frame_t; + +typedef uint8_t smp_crc_t[4]; + +#ifdef offsetof +#define SMP_REQ_MINLEN \ + (offsetof(smp_request_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#define SMP_RESP_MINLEN \ + (offsetof(smp_response_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#endif /* offsetof */ + +#pragma pack(1) + +/* + * SAS-2 10.4.3.4 REPORT GENERAL (no additional request bytes) + */ +typedef struct smp_report_general_resp { + uint16_t srgr_exp_change_count; + uint16_t srgr_exp_route_indexes; + DECL_BITFIELD2( + _reserved1 :7, + srgr_long_response :1); + uint8_t srgr_number_of_phys; + DECL_BITFIELD7( + srgr_externally_configurable_route_table :1, + srgr_configuring :1, + srgr_configures_others :1, + srgr_open_reject_retry_supported :1, + srgr_stp_continue_awt :1, + _reserved2 :2, + srgr_table_to_table_supported :1); + uint8_t _reserved3; + uint64_t srgr_enclosure_logical_identifier; + uint8_t _reserved4[8]; + uint8_t _reserved5[2]; + uint16_t srgr_stp_bus_inactivity_time_limit; + uint16_t srgr_stp_maximum_connect_time_limit; + uint16_t srgr_stp_smp_nexus_loss_time; + DECL_BITFIELD7( + srgr_zoning_enabled :1, + srgr_zoning_supported :1, + srgr_physical_presence_asserted :1, + srgr_physical_presence_supported :1, + srgr_zone_locked :1, + _reserved6 :1, + srgr_number_of_zone_grps :2); + DECL_BITFIELD6( + srgr_saving_zoning_enabled_supported :1, + srgr_saving_zone_perm_table_supported :1, + srgr_saving_zone_phy_info_supported :1, + srgr_saving_zone_mgr_password_supported :1, + srgr_saving :1, + _reserved7 :4); + uint16_t srgr_max_routed_sas_addrs; + uint64_t srgr_active_zm_sas_addr; + uint16_t srgr_zone_lock_inactivity_limit; + uint8_t _reserved8[2]; + uint8_t _reserved9; + uint8_t srgr_first_encl_conn_elem_idx; + uint8_t srgr_number_encl_conn_elem_idxs; + uint8_t _reserved10; + DECL_BITFIELD2( + _reserved11 :7, + srgr_reduced_functionality :1); + uint8_t srgr_time_to_reduced_functionality; + uint8_t srgr_initial_time_to_reduced_functionality; + uint8_t srgr_max_reduced_functionality_time; + uint16_t srgr_last_self_conf_status_descr_idx; + uint16_t srgr_max_stored_self_config_status_descrs; + uint16_t srgr_last_phy_event_list_descr_idx; + uint16_t srgr_max_stored_phy_event_list_descrs; + uint16_t srgr_stp_reject_to_open_limit; + uint8_t _reserved12[2]; +} smp_report_general_resp_t; + +typedef enum smp_n_zone_grps { + SMP_ZONE_GROUPS_128 = 0x0, + SMP_ZONE_GROUPS_256 = 0x1 +} smp_n_zone_grps_t; + +/* + * SAS-2 10.4.3.5 REPORT MANUFACTURER INFORMATION (no additional request bytes) + */ +typedef struct smp_report_manufacturer_info_resp { + uint16_t srmir_exp_change_count; + uint8_t _reserved1[2]; + DECL_BITFIELD2( + srmir_sas_1_1_format :1, + _reserved2 :7); + uint8_t _reserved3[3]; + char srmir_vendor_identification[8]; + char srmir_product_identification[16]; + char srmir_product_revision_level[4]; + char srmir_component_vendor_identification[8]; + uint16_t srmir_component_id; + uint8_t srmir_component_revision_level; + uint8_t _reserved4; + uint8_t srmir_vs_52[8]; +} smp_report_manufacturer_info_resp_t; + +/* + * SAS-2 10.4.3.6 REPORT SELF_CONFIGURATION STATUS + */ +typedef struct smp_report_self_config_status_req { + uint8_t _reserved1[2]; + uint16_t srscsr_starting_self_config_status_descr_idx; +} smp_report_self_config_status_req_t; + +typedef struct smp_report_self_config_status_resp { + uint16_t srscsr_exp_change_count; + uint16_t srscsr_starting_self_config_status_descr_idx; + uint16_t srscsr_number_self_config_status_descrs; + uint16_t srscsr_last_self_config_status_descr_idx; + uint8_t srscsr_self_config_status_descr_len; + uint8_t _reserved1[3]; + uint8_t srscsr_descrs[1]; +} smp_report_self_config_status_resp_t; + +typedef struct smp_self_config_status_descr { + uint8_t sscsd_status_type; + DECL_BITFIELD2( + sscsd_final :1, + _reserved1 :7); + uint8_t _reserved2; + uint8_t sscsd_phy_identifier; + uint8_t _reserved3[4]; + uint64_t sscsd_sas_addr; +} smp_self_config_status_descr_t; + +typedef enum smp_self_config_status_type { + SMP_SCST_NONSPECIFIC_ERROR = 0x01, + SMP_SCST_CONNECTION = 0x02, + SMP_SCST_ROUTE_TABLE_FULL = 0x03, + SMP_SCST_NOMEM = 0x04, + SMP_SCST_PHY_LAYER_ERROR = 0x20, + SMP_SCST_LOST_SYNC = 0x21, + SMP_SCST_LINK_LAYER_ERROR = 0x40, + SMP_SCST_OPEN_TIMEOUT = 0x41, + SMP_SCST_ABANDON_OPEN_REJECT = 0x42, + SMP_SCST_RETRY_OPEN_REJECTS = 0x43, + SMP_SCST_NEXUS_LOSS = 0x44, + SMP_SCST_BREAK = 0x45, + SMP_SCST_CRC_ERROR = 0x46, + SMP_SCST_PORT_LAYER_ERROR = 0x60, + SMP_SCST_RESPONSE_TIMEOUT = 0x61, + SMP_SCST_TRANSPORT_LAYER_ERROR = 0x80, + SMP_SCST_APP_LAYER_ERROR = 0xA0, + SMP_SCST_RESPONSE_TOO_SHORT = 0xA1, + SMP_SCST_UNSUPPORTED_VALUES = 0xA2, + SMP_SCST_INCONSISTENT = 0xA3, + SMP_SCST_CONFIGURING = 0xA4 +} smp_self_config_status_type_t; + +/* + * SAS-2 10.4.3.7 REPORT ZONE PERMISSION TABLE + */ +typedef struct smp_report_zone_perm_table_req { + DECL_BITFIELD2( + srzptr_report_type :2, + _reserved1 :6); + uint8_t _reserved2; + uint8_t srzptr_starting_src_zone_grp; + uint8_t srzptr_max_zone_perm_descrs; +} smp_report_zone_perm_table_req_t; + +typedef enum smp_zone_perm_table_report_type { + SMP_ZPTRT_CURRENT = 0x0, + SMP_ZPTRT_SHADOW = 0x1, + SMP_ZPTRT_SAVED = 0x2, + SMP_ZPTRT_DEFAULT = 0x3 +} smp_zone_perm_table_report_type_t; + +typedef struct smp_report_zone_perm_table_resp { + uint16_t srzptr_exp_change_count; + DECL_BITFIELD3( + srzptr_report_type :2, + _reserved1 :5, + srzptr_zone_locked :1); + DECL_BITFIELD2( + _reserved2 :6, + srzptr_number_zone_grps :2); + uint8_t _reserved3[6]; + uint8_t srzptr_starting_src_zone_grp; + uint8_t srzptr_number_zone_perm_descrs; + uint8_t srzptr_descrs[1]; +} smp_report_zone_perm_table_resp_t; + +typedef uint8_t smp_zone_perm_descr128_t[16]; +typedef uint8_t smp_zone_perm_descr256_t[32]; + +#define SMP_ZONE_PERM_BIT128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] & (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_SET128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] |= (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_CLR128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] &= ~(1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_BIT256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] & (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_SET256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] |= (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_CLR256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] &= ~(1 << ((__z) & 7))) + +/* + * SAS-2 10.4.3.8 REPORT ZONE MANAGER PASSWORD (no additional request bytes) + */ +typedef struct smp_report_zone_mgr_password_resp { + uint16_t srzmpr_exp_change_count; + uint8_t _reserved1[2]; + uint8_t srzmpr_zone_mgr_password[32]; +} smp_report_zone_mgr_password_resp_t; + +/* + * SAS-2 10.4.3.9 REPORT BROADCAST + */ +typedef struct smp_report_broadcast_req { + DECL_BITFIELD2( + srbr_broadcast_type :4, + _reserved1 :4); + uint8_t _reserved2[3]; +} smp_report_broadcast_req_t; + +typedef enum smp_broadcast_type { + SMP_BROADCAST_CHANGE = 0x0, + SMP_BROADCAST_RESERVED_CHANGE_0 = 0x1, + SMP_BROADCAST_RESERVED_CHANGE_1 = 0x2, + SMP_BROADCAST_SES = 0x3, + SMP_BROADCAST_EXPANDER = 0x4, + SMP_BROADCAST_ASYNC_EVENT = 0x5, + SMP_BROADCAST_RESERVED_3 = 0x6, + SMP_BROADCAST_RESERVED_4 = 0x7, + SMP_BROADCAST_ZONE_ACTIVATE = 0x8 +} smp_broadcast_type_t; + +typedef struct smp_broadcast_descr { + DECL_BITFIELD2( + sbd_broadcast_type :4, + _reserved1 :4); + uint8_t sbd_phy_identifier; + DECL_BITFIELD2( + sbd_broadcast_reason :4, + _reserved2 :4); + uint16_t sbd_broadcast_count; + uint8_t _reserved3[10]; +} smp_broadcast_descr_t; + +typedef struct smp_report_broadcast_resp { + uint16_t srbr_exp_change_count; + DECL_BITFIELD2( + srbr_broadcast_type :4, + _reserved1 :4); + uint8_t srbr_number_broadcast_descrs; + smp_broadcast_descr_t srbr_descrs[1]; +} smp_report_broadcast_resp_t; + +/* + * SAS-2 10.4.3.10 DISCOVER + */ +typedef struct smp_discover_req { + uint8_t _reserved1[4]; + DECL_BITFIELD2( + sdr_ignore_zone_grp :1, + _reserved2 :7); + uint8_t sdr_phy_identifier; + uint8_t _reserved3[2]; +} smp_discover_req_t; + +typedef struct smp_snw3_phy_cap { + DECL_BITFIELD4( + sspc_requested_logical_link_rate :4, /* smp_link_rate_t */ + _reserved1 :2, + sspc_tx_ssc_type :1, + sspc_start :1); + DECL_BITFIELD7( + _reserved2 :2, + sspc_g3_ssc :1, + sspc_g3_no_ssc :1, + sspc_g2_ssc :1, + sspc_g2_no_ssc :1, + sspc_g1_ssc :1, + sspc_g1_no_ssc :1); + uint8_t _reserved3; + DECL_BITFIELD2( + sspc_parity :1, + _reserved4 :7); +} smp_snw3_phy_cap_t; + +typedef struct smp_discover_resp { + uint16_t sdr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t sdr_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD3( + sdr_attached_reason :4, + sdr_attached_device_type :3, + _reserved3 :1); + DECL_BITFIELD2( + sdr_negotiated_logical_link_rate :4, /* smp_link_rate_t */ + _reserved4 :4); + DECL_BITFIELD5( + sdr_attached_sata_host :1, + sdr_attached_smp_initiator :1, + sdr_attached_stp_initiator :1, + sdr_attached_ssp_initiator :1, + _reserved5 :4); + DECL_BITFIELD6( + sdr_attached_sata_device :1, + sdr_attached_smp_target :1, + sdr_attached_stp_target :1, + sdr_attached_ssp_target :1, + _reserved6 :3, + sdr_attached_sata_port_selector :1); + uint64_t sdr_sas_addr; + uint64_t sdr_attached_sas_addr; + uint8_t sdr_attached_phy_identifier; + DECL_BITFIELD4( + sdr_attached_break_reply_capable :1, + sdr_attached_requested_inside_zpsds :1, + sdr_attached_inside_zpsds_persistent :1, + _reserved7 :5); + uint8_t _reserved8[6]; + DECL_BITFIELD2( + sdr_hw_min_phys_link_rate :4, /* smp_link_rate_t */ + sdr_prog_min_phys_link_rate :4); /* smp_link_rate_t */ + DECL_BITFIELD2( + sdr_hw_max_phys_link_rate :4, /* smp_link_rate_t */ + sdr_prog_max_phys_link_rate :4); /* smp_link_rate_t */ + uint8_t sdr_phy_change_count; + DECL_BITFIELD3( + sdr_partial_pwy_timeout :4, + _reserved9 :3, + sdr_virtual_phy :1); + DECL_BITFIELD2( + sdr_routing_attr :4, /* smp_routing_attr_t */ + _reserved10 :4); + DECL_BITFIELD2( + sdr_connector_type :7, + _reserved11 :1); + uint8_t sdr_connector_element_index; + uint8_t sdr_connector_physical_link; + uint8_t _reserved12[2]; + uint8_t sdr_vendor[2]; + uint64_t sdr_attached_device_name; + DECL_BITFIELD8( + sdr_zoning_enabled :1, + sdr_inside_zpsds :1, + sdr_zone_group_persistent :1, + _reserved13 :1, + sdr_requested_inside_zpsds :1, + sdr_inside_zpsds_persistent :1, + sdr_requested_inside_zpsds_changed_by_exp :1, + _reserved14 :1); + uint8_t _reserved15[2]; + uint8_t sdr_zone_group; + uint8_t sdr_self_config_status; + uint8_t sdr_self_config_levels_completed; + uint8_t _reserved16[2]; + uint64_t sdr_self_config_sas_addr; + smp_snw3_phy_cap_t sdr_prog_phy_cap; + smp_snw3_phy_cap_t sdr_current_phy_cap; + smp_snw3_phy_cap_t sdr_attached_phy_cap; + uint8_t _reserved17[6]; + DECL_BITFIELD2( + sdr_negotiated_phys_link_rate :4, /* smp_link_rate_t */ + sdr_reason :4); + DECL_BITFIELD3( + sdr_hw_muxing_supported :1, + sdr_negotiated_ssc :1, + _reserved18 :6); + DECL_BITFIELD7( + sdr_default_zoning_enabled :1, + _reserved19 :1, + sdr_default_zone_group_persistent :1, + _reserved20 :1, + sdr_default_requested_inside_zpsds :1, + sdr_default_inside_zpsds_persistent :1, + _reserved21 :2); + uint8_t _reserved22[2]; + uint8_t sdr_default_zone_group; + DECL_BITFIELD7( + sdr_saved_zoning_enabled :1, + _reserved23 :1, + sdr_saved_zone_group_persistent :1, + _reserved24 :1, + sdr_saved_requested_inside_zpsds :1, + sdr_saved_inside_zpsds_persistent :1, + _reserved25 :2); + uint8_t _reserved26[2]; + uint8_t saved_zone_group; + DECL_BITFIELD6( + _reserved27 :2, + sdr_shadow_zone_group_persistent :1, + _reserved28 :1, + sdr_shadow_requested_inside_zpsds :1, + sdr_shadow_inside_zpsds_persistent :1, + _reserved29 :2); + uint8_t _reserved30[2]; + uint8_t sdr_shadow_zone_group; +} smp_discover_resp_t; + +typedef enum smp_link_rate { + SMP_LINK_RATE_NO_CHANGE = 0x0, + SMP_LINK_RATE_DISABLED = 0x1, + SMP_LINK_RATE_RESET_PROBLEM = 0x2, + SMP_LINK_RATE_SPINUP_HOLD = 0x3, + SMP_LINK_RATE_PORT_SELECTOR = 0x4, + SMP_LINK_RATE_RESET = 0x5, + SMP_LINK_RATE_UNSUPPORTED = 0x6, + SMP_LINK_RATE_1_5 = 0x8, + SMP_LINK_RATE_3 = 0x9, + SMP_LINK_RATE_6 = 0xA +} smp_link_rate_t; + +typedef enum smp_device_type { + SMP_DEV_NONE = 0x0, + SMP_DEV_SAS_SATA = 0x1, + SMP_DEV_EXPANDER = 0x2, + SMP_DEV_EXPANDER_OLD = 0x3 +} smp_device_type_t; + +typedef enum smp_routing_attr { + SMP_ROUTING_DIRECT = 0x0, + SMP_ROUTING_SUBTRACTIVE = 0x1, + SMP_ROUTING_TABLE = 0x2 +} smp_routing_attr_t; + +/* + * SAS-2 10.4.3.11 REPORT PHY ERROR LOG + */ +typedef struct smp_report_phy_error_log_req { + uint8_t _reserved1[5]; + uint8_t srpelr_phy_identifier; + uint8_t _reserved2[2]; +} smp_report_phy_error_log_req_t; + +typedef struct smp_report_phy_error_log_resp { + uint16_t srpelr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srpelr_phy_identifier; + uint8_t _reserved2[2]; + uint32_t srpelr_invalid_dword_count; + uint32_t srpelr_running_disparity_error_count; + uint32_t srpelr_loss_dword_sync_count; + uint32_t srpelr_phy_reset_problem_count; +} smp_report_phy_error_log_resp_t; + +/* + * SAS-2 10.4.3.12 REPORT PHY SATA + */ +typedef struct smp_report_phy_sata_req { + uint8_t _reserved1[5]; + uint8_t srpsr_phy_identifier; + uint8_t srpsr_affiliation_context; + uint8_t _reserved2; +} smp_report_phy_sata_req_t; + +typedef struct smp_report_phy_sata_resp { + uint16_t srpsr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srpsr_phy_identifier; + uint8_t _reserved2; + DECL_BITFIELD4( + srpsr_affiliation_valid :1, + srpsr_affiliations_supported :1, + srpsr_stp_nexus_loss :1, + _reserved3 :5); + uint8_t _reserved4[4]; + uint64_t srpsr_stp_sas_addr; + uint8_t srpsr_register_device_host_fis[20]; + uint8_t _reserved5[4]; + uint64_t srpsr_affiliated_stp_init_sas_addr; + uint64_t srpsr_stp_nexus_loss_sas_addr; + uint8_t _reserved6; + uint8_t srpsr_affiliation_context; + uint8_t srpsr_current_affiliation_contexts; + uint8_t srpsr_max_affiliation_contexts; +} smp_report_phy_sata_resp_t; + +/* + * SAS-2 10.4.3.13 REPORT ROUTE INFORMATION + */ +typedef struct smp_report_route_info_req { + uint8_t _reserved1[2]; + uint16_t srrir_exp_route_index; + uint8_t _reserved2; + uint8_t srrir_phy_identifier; + uint8_t _reserved3[2]; +} smp_report_route_info_req_t; + +typedef struct smp_report_route_info_resp { + uint16_t srrir_exp_change_count; + uint16_t srrir_exp_route_index; + uint8_t _reserved1; + uint8_t srrir_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD2( + _reserved3 :7, + srrir_exp_route_entry_disabled :1); + uint8_t _reserved4[3]; + uint64_t srrir_routed_sas_addr; + uint8_t _reserved5[16]; +} smp_report_route_info_resp_t; + +/* + * SAS-2 10.4.3.14 SAS-2 REPORT PHY EVENT + */ +typedef struct smp_report_phy_event_req { + uint8_t _reserved1; + uint8_t _reserved2[4]; + uint8_t srper_phy_identifier; + uint8_t _reserved3[2]; +} smp_report_phy_event_req_t; + +typedef struct smp_phy_event_report_descr { + uint8_t _reserved1[3]; + uint8_t sped_phy_event_source; + uint32_t sped_phy_event; + uint32_t sped_peak_detector_threshold; +} smp_phy_event_report_descr_t; + +typedef struct smp_report_phy_event_resp { + uint16_t srper_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srper_phy_identifier; + uint8_t _reserved2[5]; + uint8_t srper_n_phy_event_descrs; + smp_phy_event_report_descr_t srper_phy_event_descrs[1]; +} smp_report_phy_event_resp_t; + +/* + * SAS-2 10.4.3.15 SAS-2 DISCOVER LIST + */ +typedef struct smp_discover_list_req { + uint8_t _reserved1[4]; + uint8_t sdlr_starting_phy_identifier; + uint8_t sdlr_max_descrs; + DECL_BITFIELD3( + sdlr_phy_filter :4, + _reserved2 :3, + sdlr_ignore_zone_group :1); + DECL_BITFIELD2( + sdlr_descr_type :4, + _reserved3 :4); + uint8_t _reserved4[4]; + uint8_t sdlr_vendor[12]; +} smp_discover_list_req_t; + +typedef struct smp_discover_short_descr { + uint8_t sdsd_phy_identifier; + uint8_t sdsd_function_result; + DECL_BITFIELD3( + sdsd_attached_reason :4, + sdsd_attached_device_type :3, + _restricted1 :1); + DECL_BITFIELD2( + sdsd_negotiated_logical_link_rate :4, /* smp_link_rate_t */ + _restricted2 :4); + DECL_BITFIELD5( + sdsd_attached_sata_host :1, + sdsd_attached_smp_initiator :1, + sdsd_attached_stp_initiator :1, + sdsd_attached_ssp_initiator :1, + _restricted3 :4); + DECL_BITFIELD6( + sdsd_attached_sata_device :1, + sdsd_attached_smp_target :1, + sdsd_attached_stp_target :1, + sdsd_attached_ssp_target :1, + _restricted4 :3, + sdsd_attached_sata_port_selector :1); + DECL_BITFIELD3( + sdsd_routing_attribute :4, /* smp_routing_attr_t */ + _reserved1 :3, + sdsd_virtual_phy :1); + DECL_BITFIELD2( + _reserved2 :4, + sdsd_reason :4); + uint8_t sdsd_zone_group; + DECL_BITFIELD7( + _reserved3 :1, + sdsd_inside_zpsds :1, + sdsd_zone_group_persistent :1, + _reserved4 :1, + sdsd_requested_insize_zpsds :1, + sdsd_inside_zpsds_persistent :1, + _restricted5 :2); + uint8_t sdsd_attached_phy_identifier; + uint8_t sdsd_phy_change_count; + uint64_t sdsd_attached_sas_addr; + uint8_t _reserved5[4]; +} smp_discover_short_descr_t; + +typedef struct smp_discover_long_descr { + uint8_t _reserved1[2]; + uint8_t sdld_function_result; + uint8_t _reserved2[1]; + smp_discover_resp_t sdld_response; +} smp_discover_long_descr_t; + +#define SMP_DISCOVER_RESP(_ld) \ + (((smp_discover_long_descr_t *)(_ld))->sdld_function_result == \ + SMP_FUNCTION_ACCEPTED ? \ + &((smp_discover_long_descr_t *)(_ld))->sdld_response : \ + NULL) + +typedef struct smp_discover_list_resp { + uint16_t sdlr_exp_change_count; + uint8_t _reserved1[2]; + uint8_t sdlr_starting_phy_identifier; + uint8_t sdlr_n_descrs; + DECL_BITFIELD2( + sdlr_phy_filter :4, + _reserved2 :4); + DECL_BITFIELD2( + sdlr_descr_type :4, + _reserved3 :4); + uint8_t sdlr_descr_length; + uint8_t _reserved4[3]; + DECL_BITFIELD5( + sdlr_externally_configurable_route_table :1, + sdlr_configuring :1, + _reserved5 :4, + sdlr_zoning_enabled :1, + sdlr_zoning_supported :1); + uint8_t _reserved6; + uint16_t sdlr_last_sc_status_descr_index; + uint16_t sdlr_last_phy_event_list_descr_index; + uint8_t _reserved7[10]; + uint8_t sdlr_vendor[16]; + uint8_t sdlr_descrs[1]; /* short or long format */ +} smp_discover_list_resp_t; + +/* + * SAS-2 10.4.3.16 REPORT PHY EVENT LIST + */ +typedef struct smp_report_phy_event_list_req { + uint8_t _reserved1[2]; + uint16_t srpelr_starting_descr_index; +} smp_report_phy_event_list_req_t; + +typedef struct smp_phy_event_list_descr { + uint8_t _reserved1[2]; + uint8_t speld_phy_identifier; + uint8_t speld_phy_event_source; + uint32_t speld_phy_event; + uint32_t speld_peak_detector_threshold; +} smp_phy_event_list_descr_t; + +typedef struct smp_report_phy_event_list_resp { + uint16_t srpelr_exp_change_count; + uint16_t srpelr_starting_descr_index; + uint16_t srpelr_last_descr_index; + uint8_t srpelr_phy_event_list_descr_length; + uint8_t _reserved1[3]; + uint8_t srpelr_n_descrs; + smp_phy_event_list_descr_t srpelr_descrs[1]; +} smp_report_phy_event_list_resp_t; + +/* + * SAS-2 10.4.3.17 REPORT EXPANDER ROUTE TABLE LIST + */ +typedef struct smp_report_exp_route_table_list_req { + uint8_t _reserved1[4]; + uint16_t srertlr_max_descrs; + uint16_t srertlr_starting_routed_sas_addr_index; + uint8_t _reserved2[7]; + uint8_t srertlr_starting_phy_identifier; + uint8_t _reserved3[8]; +} smp_report_exp_route_table_list_req_t; + +typedef struct smp_route_table_descr { + uint64_t srtd_routed_sas_addr; + uint8_t srtd_phy_bitmap[6]; + DECL_BITFIELD2( + _reserved1 :7, + srtd_zone_group_valid :1); + uint8_t srtd_zone_group; +} smp_route_table_descr_t; + +#define SMP_ROUTE_PHY(_d, _s, _i) \ + ((_d)->srtd_phy_bitmap[(48 - (_i) + (_s)) >> 3] & \ + (1 << ((48 - (_i) + (_s)) & 7))) + +typedef struct smp_report_exp_route_table_list_resp { + uint16_t srertlr_exp_change_count; + uint16_t srertlr_route_table_change_count; + DECL_BITFIELD3( + _reserved1 :1, + srertlr_configuring :1, + _reserved2 :6); + uint8_t _reserved3; + uint16_t srertlr_n_descrs; + uint16_t srertlr_first_routed_sas_addr_index; + uint16_t srertlr_last_routed_sas_addr_index; + uint8_t _reserved4[3]; + uint8_t srertlr_starting_phy_identifier; + uint8_t _reserved5[12]; + smp_route_table_descr_t srertlr_descrs[1]; +} smp_report_exp_route_table_list_resp_t; + +/* + * SAS-2 10.4.3.18 CONFIGURE GENERAL (no additional response) + */ +typedef struct smp_config_general_req { + uint16_t scgr_expected_exp_change_count; + uint8_t _reserved1[2]; + DECL_BITFIELD6( + scgr_update_stp_bus_inactivity :1, + scgr_update_stp_max_conn :1, + scgr_update_stp_smp_nexus_loss :1, + scgr_update_initial_time_to_reduced_functionality :1, + scgr_update_stp_reject_to_open :1, + _reserved2 :3); + uint8_t _reserved3; + uint16_t scgr_stp_bus_inactivity; + uint16_t scgr_stp_max_conn; + uint16_t scgr_stp_smp_nexus_loss; + uint8_t scgr_initial_time_to_reduced_functionality; + uint8_t _reserved4; + uint16_t scgr_stp_reject_to_open; +} smp_config_general_req_t; + +/* + * SAS-2 10.4.3.19 ENABLE DISABLE ZONING (no additional response) + */ +typedef struct smp_enable_disable_zoning_req { + uint16_t sedzr_expected_exp_change_count; + DECL_BITFIELD2( + sedzr_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t _reserved2; + DECL_BITFIELD2( + sedzr_enable_disable_zoning :2, + _reserved3 :6); + uint8_t _reserved4[3]; +} smp_enable_disable_zoning_req_t; + +typedef enum smp_zoning_save { + SMP_ZONING_SAVE_CURRENT = 0x0, + SMP_ZONING_SAVE_SAVED = 0x1, + SMP_ZONING_SAVE_BOTH_IF_SUPP = 0x2, + SMP_ZONING_SAVE_BOTH = 0x3 +} smp_zoning_save_t; + +typedef enum smp_zoning_enable_op { + SMP_ZONING_ENABLE_OP_NONE = 0x0, + SMP_ZONING_ENABLE_OP_ENABLE = 0x1, + SMP_ZONING_ENABLE_OP_DISABLE = 0x2 +} smp_zoning_enable_op_t; + +/* + * SAS-2 10.4.3.20 ZONED BROADCAST (no additional response) + */ +typedef struct smp_zoned_broadcast_req { + uint8_t _restricted1[2]; + DECL_BITFIELD2( + szbr_broadcast_type :4, + _reserved :4); + uint8_t szbr_n_broadcast_source_zone_groups; + uint8_t szbr_broadcast_source_zone_groups[1]; +} smp_zoned_broadcast_req_t; + +/* + * SAS-2 10.4.3.21 ZONE LOCK + */ +typedef struct smp_zone_lock_req { + uint16_t szlr_expected_exp_change_count; + uint16_t szlr_zone_lock_inactivity_timeout; + uint8_t szlr_zone_manager_password[32]; +} smp_zone_lock_req_t; + +typedef struct smp_zone_lock_resp { + uint8_t _reserved1[4]; + uint64_t szlr_active_zone_manager_sas_addr; +} smp_zone_lock_resp_t; + +/* + * SAS-2 10.4.3.22 ZONE ACTIVATE (no additional response) + */ +typedef struct smp_zone_activate_req { + uint16_t szar_expected_exp_change_count; + uint8_t _reserved1[2]; +} smp_zone_activate_req_t; + +/* + * SAS-2 10.4.3.23 ZONE UNLOCK (no additional response) + */ +typedef struct smp_zone_unlock_req { + uint8_t _restricted1[2]; + DECL_BITFIELD2( + szur_activate_required :1, + _reserved1 :7); + uint8_t _reserved2; +} smp_zone_unlock_req_t; + +/* + * SAS-2 10.4.3.24 CONFIGURE ZONE MANAGER PASSWORD (no additional response) + */ +typedef struct smp_config_zone_manager_password_req { + uint16_t sczmpr_expected_exp_change_count; + DECL_BITFIELD2( + sczmpr_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t _reserved2; + uint8_t sczmpr_zone_manager_password[32]; + uint8_t sczmpr_new_zone_manager_password[32]; +} smp_config_zone_manager_password_req_t; + +/* + * SAS-2 10.4.3.25 CONFIGURE ZONE PHY INFORMATION (no additional response) + */ +typedef struct smp_zone_phy_config_descr { + uint8_t szpcd_phy_identifier; + DECL_BITFIELD6( + _reserved1 :2, + szpcd_zone_group_persistent :1, + _reserved2 :1, + szpcd_requested_inside_zpsds :1, + szpcd_inside_zpsds_persistent :1, + _reserved3 :2); + uint8_t _reserved4; + uint8_t szpcd_zone_group; +} smp_zone_phy_config_descr_t; + +typedef struct smp_config_zone_phy_info_req { + uint16_t sczpir_expected_exp_change_count; + DECL_BITFIELD2( + sczpir_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t sczpir_n_descrs; + smp_zone_phy_config_descr_t sczpir_descrs[1]; +} smp_config_zone_phy_info_req_t; + +/* + * SAS-2 10.4.3.26 CONFIGURE ZONE PERMISSION TABLE (no additional response) + */ +typedef struct smp_config_zone_perm_table_req { + uint16_t sczptr_expected_exp_change_count; + uint8_t sczptr_starting_source_zone_group; + uint8_t sczptr_n_descrs; + DECL_BITFIELD3( + sczptr_save :2, /* smp_zoning_save_t */ + _reserved1 :4, + sczptr_n_zone_groups :2); /* smp_n_zone_grps_t */ + uint8_t _reserved2[7]; + uint8_t sczptr_descrs[1]; /* smp_zone_perm_descrXXX_t */ +} smp_config_zone_perm_table_req_t; + +/* + * SAS-2 10.4.3.27 CONFIGURE ROUTE INFORMATION (no additional response) + */ +typedef struct smp_config_route_info_req { + uint16_t scrir_expected_exp_change_count; + uint16_t scrir_exp_route_index; + uint8_t _reserved1; + uint8_t scrir_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD2( + _reserved3 :7, + scrir_disable_exp_route_entry :1); + uint8_t _reserved4[3]; + uint64_t scrir_routed_sas_addr; + uint8_t _reserved5[16]; +} smp_config_route_info_req_t; + +/* + * SAS-2 10.4.3.28 PHY CONTROL (no additional response) + */ +typedef struct smp_phy_control_req { + uint16_t spcr_expected_exp_change_count; + uint8_t _reserved1[3]; + uint8_t spcr_phy_identifier; + uint8_t spcr_phy_operation; + DECL_BITFIELD2( + spcr_update_partial_pwy_timeout :1, + _reserved2 :7); + uint8_t _reserved3[12]; + uint64_t spcr_attached_device_name; + DECL_BITFIELD2( + _reserved4 :4, + spcr_prog_min_phys_link_rate :4); /* smp_link_rate_t */ + DECL_BITFIELD2( + _reserved5 :4, + spcr_prog_max_phys_link_rate :4); /* smp_link_rate_t */ + uint8_t _reserved6[2]; + DECL_BITFIELD2( + spcr_partial_pwy_timeout :4, + _reserved7 :4); + uint8_t _reserved8[3]; +} smp_phy_control_req_t; + +typedef enum smp_phy_op { + SMP_PHY_OP_NOP = 0x00, + SMP_PHY_OP_LINK_RESET = 0x01, + SMP_PHY_OP_HARD_RESET = 0x02, + SMP_PHY_OP_DISABLE = 0x03, + SMP_PHY_OP_CLEAR_ERROR_LOG = 0x05, + SMP_PHY_OP_CLEAR_AFFILIATION = 0x06, + SMP_PHY_OP_TRANSMIT_SATA_PORT_SELECTION_SIGNAL = 0x07, + SMP_PHY_OP_CLEAR_STP_NEXUS_LOSS = 0x08, + SMP_PHY_OP_SET_ATTACHED_DEVICE_NAME = 0x09 +} smp_phy_op_t; + +/* + * SAS-2 10.4.3.29 PHY TEST FUNCTION (no additional response) + */ +typedef struct smp_phy_test_function_req { + uint16_t sptfr_expected_exp_change_count; + uint8_t _reserved1[3]; + uint8_t sptfr_phy_identifier; + uint8_t sptfr_phy_test_function; + uint8_t sptfr_phy_test_pattern; /* smp_phy_test_function_t */ + uint8_t _reserved2[3]; + DECL_BITFIELD4( + sptfr_test_pattern_phys_link_rate :4, /* smp_link_rate_t */ + sptfr_test_pattern_ssc :2, + sptfr_test_pattern_sata :1, + _reserved3 :1); + uint8_t _reserved4[3]; + uint8_t sptfr_phy_test_pattern_dwords_ctl; + uint8_t sptfr_phy_test_pattern_dwords[8]; + uint8_t _reserved5[12]; +} smp_phy_test_function_req_t; + +typedef enum smp_phy_test_function { + SMP_PHY_TEST_FN_STOP = 0x00, + SMP_PHY_TEST_FN_TRANSMIT_PATTERN = 0x01 +} smp_phy_test_function_t; + +/* + * SAS-2 10.4.3.30 CONFIGURE PHY EVENT (no additional response) + */ +typedef struct smp_phy_event_config_descr { + uint8_t _reserved1[3]; + uint8_t specd_phy_event_source; + uint32_t specd_peak_value_detector_threshold; +} smp_phy_event_config_descr_t; + +typedef struct smp_config_phy_event_req { + uint16_t scper_expected_exp_change_count; + DECL_BITFIELD2( + scper_clear_peaks :1, + _reserved1 :7); + uint8_t _reserved2[2]; + uint8_t scper_phy_identifier; + uint8_t _reserved3; + uint8_t scper_n_descrs; + smp_phy_event_config_descr_t scper_descrs[1]; +} smp_config_phy_event_req_t; + +#pragma pack() + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SCSI_GENERIC_SMP_FRAMES_H */ diff --git a/usr/src/uts/common/sys/scsi/conf/autoconf.h b/usr/src/uts/common/sys/scsi/conf/autoconf.h index 757732cb09..8d0903dee5 100644 --- a/usr/src/uts/common/sys/scsi/conf/autoconf.h +++ b/usr/src/uts/common/sys/scsi/conf/autoconf.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_CONF_AUTOCONF_H #define _SYS_SCSI_CONF_AUTOCONF_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -75,6 +73,9 @@ extern "C" { #define SCSI_OPTIONS_NLUNS_8 0x20000 #define SCSI_OPTIONS_NLUNS_16 0x30000 #define SCSI_OPTIONS_NLUNS_32 0x40000 +#define SCSI_OPTIONS_NLUNS_64 0x50000 +#define SCSI_OPTIONS_NLUNS_128 0x60000 +#define SCSI_OPTIONS_NLUNS_256 0x70000 #define SCSI_OPTIONS_NLUNS(n) ((n) & SCSI_OPTIONS_NLUNS_MASK) @@ -153,14 +154,41 @@ extern "C" { #define SCSI_DEFAULT_SELECTION_TIMEOUT 250 /* - * Kernel references + * SCSI subsystem scsi_enumeration options. + * + * Knob for SPI (SCSI Parallel Intrconnect) enumeration. Unless an HBA defines + * it's own tran_bus_config, SPI enumeration is used. The "scsi_enumeration" + * knob determines how SPI enumeration is performed. + * + * The global variable "scsi_enumeration" is used as the default value of the + * "scsi-enumeration" property. In addition to enabling/disabling enumeration + * (bit 0), target and lun threading can be specified. Having things + * multi-threaded does not guarantee reduce configuration time, however when + * the bus is marginal multi-threading can substaintaly reduce configuration + * time because targets negotiate to stable transfer speeds in parallel - so + * all targets have stabalized by the time the sequential attach(9E) operations + * begin. Running multi-threaded also helps verification of framework and HBA + * locking: a BUS_CONFIG_ALL is equivalent to every target and lun combination + * getting a BUS_CONFIG_ONE from a separate thread at the same time. A disable + * mechanism is provided to accomidate buggy HBAs (set scsi-enumeration=7 + * driver.conf). Values are: + * + * 0 driver.conf enumeration + * 1 dynamic enumeration with target and lun multi-threading. + * 3 dynamic enumeration with lun multi-threading disabled. + * 5 dynamic enumeration with target multi-threading disabled; + * 7 dynamic enumeration with target/lun multi-threading disabled. */ +#define SCSI_ENUMERATION_ENABLE 0x1 +#define SCSI_ENUMERATION_MT_LUN_DISABLE 0x2 +#define SCSI_ENUMERATION_MT_TARGET_DISABLE 0x4 #ifdef _KERNEL /* * Global SCSI config variables / options */ extern int scsi_options; +extern int scsi_enumeration; extern unsigned int scsi_reset_delay; /* specified in milli seconds */ extern int scsi_tag_age_limit; extern int scsi_watchdog_tick; diff --git a/usr/src/uts/common/sys/scsi/conf/device.h b/usr/src/uts/common/sys/scsi/conf/device.h index 305e595807..9fce4669d8 100644 --- a/usr/src/uts/common/sys/scsi/conf/device.h +++ b/usr/src/uts/common/sys/scsi/conf/device.h @@ -141,6 +141,13 @@ struct scsi_device { void *sd_pathinfo; /* + * Counter that prevents demotion of DS_INITIALIZED node (esp loss of + * devi_addr) by causing DDI_CTLOPS_UNINITCHILD failure - devi_ref + * will not protect demotion of DS_INITIALIZED node. + */ + int sd_uninit_prevent; + + /* * The 'sd_tran_safe' field is a grotty hack that allows direct-access * (non-scsa) drivers (like chs, ata, and mlx - which all make cmdk * children) to *illegally* put their own vector in the scsi_address(9S) diff --git a/usr/src/uts/common/sys/scsi/generic/sas.h b/usr/src/uts/common/sys/scsi/generic/sas.h new file mode 100644 index 0000000000..61ba710e19 --- /dev/null +++ b/usr/src/uts/common/sys/scsi/generic/sas.h @@ -0,0 +1,199 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * SAS Common Structures and Definitions + * sas2r14, simplified/reduced + */ +#ifndef _SAS_H +#define _SAS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/sysmacros.h> +/* + * SAS Address Frames + * Trailing 4 byte CRC not included. + */ +typedef struct { + DECL_BITFIELD3( + address_frame_type :4, + device_type :3, + reserved0 :1); + DECL_BITFIELD2( + reason :4, + reserved1 :4); + DECL_BITFIELD5( + restricted0 :1, + smp_ini_port :1, + stp_ini_port :1, + ssp_ini_port :1, + reserved2 :4); + DECL_BITFIELD5( + restricted1 :1, + smp_tgt_port :1, + stp_tgt_port :1, + ssp_tgt_port :1, + reserved3 :4); + uint8_t device_name[8]; + uint8_t sas_address[8]; + uint8_t phy_identifier; + DECL_BITFIELD4( + break_reply_capable :1, + requested_inside_zpsds :1, + inside_zpsds_persistent :1, + reserved4 :5); + uint8_t reserved5[6]; +} sas_identify_af_t; + +typedef struct { + DECL_BITFIELD3( + address_frame_type :4, + protocol :3, + ini_port :1); + DECL_BITFIELD2( + connection_rate :4, + features :4); + uint16_t itag; /* initiator connection tag */ + uint8_t sas_dst[8]; /* destination sas address */ + uint8_t sas_src[8]; /* source sas address */ + uint8_t src_zone_group; /* source zone group */ + uint8_t path_block_count; /* pathway blocked count */ + uint16_t arb_wait_time; /* arbitration wait time */ + uint8_t compat[4]; /* 'more' compatible features */ +} sas_open_af_t; + +#define SAS_AF_IDENTIFY 0 +#define SAS_AF_OPEN 1 + +#define SAS_IF_DTYPE_ENDPOINT 1 +#define SAS_IF_DTYPE_EDGE 2 +#define SAS_IF_DTYPE_FANOUT 3 /* obsolete */ + +#define SAS_OF_PROTO_SMP 0 +#define SAS_OF_PROTO_SSP 1 +#define SAS_OF_PROTO_STP 2 + +#define SAS_SSP_SUPPORT 0x8 +#define SAS_STP_SUPPORT 0x4 +#define SAS_SMP_SUPPORT 0x2 + + +#define SAS_CONNRATE_1_5_GBPS 0x8 +#define SAS_CONNRATE_3_0_GBPS 0x9 +#define SAS_CONNRATE_6_0_GBPS 0xA + +#define SAS_SATA_SUPPORT 0x1 +#define SAS_ATTACHED_NAME_OFFSET 52 /* SAS-2 only */ + +/* + * SSP Definitions + */ +typedef struct { + uint8_t lun[8]; + uint8_t reserved0; + DECL_BITFIELD3( + task_attribute :2, + command_priority :4, + enable_first_burst :1); + uint8_t reserved1; + DECL_BITFIELD2( + reserved2 :2, + addi_cdb_len :6); + uint8_t cdb[16]; + /* additional cdb bytes go here, followed by 4 byte CRC */ +} sas_ssp_cmd_iu_t; + +#define SAS_CMD_TASK_ATTR_SIMPLE 0x00 +#define SAS_CMD_TASK_ATTR_HEAD 0x01 +#define SAS_CMD_TASK_ATTR_ORDERED 0x02 +#define SAS_CMD_TASK_ATTR_ACA 0x04 + +typedef struct { + uint8_t reserved0[8]; + uint16_t status_qualifier; + DECL_BITFIELD2( + datapres :2, + reserved1 :6); + uint8_t status; + uint8_t reserved2[4]; + uint32_t sense_data_length; + uint32_t response_data_length; + uint8_t rspd[]; + /* response data followed by sense data goes here */ +} sas_ssp_rsp_iu_t; + +/* length of bytes up to response data */ +#define SAS_RSP_HDR_SIZE 24 + +#define SAS_RSP_DATAPRES_NO_DATA 0x00 +#define SAS_RSP_DATAPRES_RESPONSE_DATA 0x01 +#define SAS_RSP_DATAPRES_SENSE_DATA 0x02 + +/* + * When the RSP IU is type RESPONSE_DATA, + * the first 4 bytes of response data should + * be a Big Endian representation of one of + * these codes. + */ +#define SAS_RSP_TMF_COMPLETE 0x00 +#define SAS_RSP_INVALID_FRAME 0x02 +#define SAS_RSP_TMF_NOT_SUPPORTED 0x04 +#define SAS_RSP_TMF_FAILED 0x05 +#define SAS_RSP_TMF_SUCCEEDED 0x08 +#define SAS_RSP_TMF_INCORRECT_LUN 0x09 +#define SAS_RSP_OVERLAPPED_OIPTTA 0x0A + +/* + * Task Management Functions- should be in a SAM definition file + */ +#define SAS_ABORT_TASK 0x01 +#define SAS_ABORT_TASK_SET 0x02 +#define SAS_CLEAR_TASK_SET 0x04 +#define SAS_LOGICAL_UNIT_RESET 0x08 +#define SAS_I_T_NEXUS_RESET 0x10 +#define SAS_CLEAR_ACA 0x40 +#define SAS_QUERY_TASK 0x80 +#define SAS_QUERY_TASK_SET 0x81 +#define SAS_QUERY_UNIT_ATTENTION 0x82 + +/* + * PHY size changed from SAS1.1 to SAS2. + */ +#define SAS_PHYNUM_MAX 127 +#define SAS_PHYNUM_MASK 0x7f + +#define SAS2_PHYNUM_MAX 254 +#define SAS2_PHYNUM_MASK 0xff + + +/* + * Maximum SMP payload size, including CRC + */ +#define SAS_SMP_MAX_PAYLOAD 1032 +#ifdef __cplusplus +} +#endif +#endif /* _SAS_H */ diff --git a/usr/src/uts/common/sys/scsi/generic/smp_frames.h b/usr/src/uts/common/sys/scsi/generic/smp_frames.h index 5c2fa17d9f..dd79a19b33 100644 --- a/usr/src/uts/common/sys/scsi/generic/smp_frames.h +++ b/usr/src/uts/common/sys/scsi/generic/smp_frames.h @@ -20,14 +20,12 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SYS_SCSI_IMPL_SMP_FRAME_H -#define _SYS_SCSI_IMPL_SMP_FRAME_H - -#pragma ident "%Z%%M% %I% %E% SMI" +#ifndef _SYS_SCSI_GENERIC_SMP_FRAMES_H +#define _SYS_SCSI_GENERIC_SMP_FRAMES_H #ifdef __cplusplus extern "C" { @@ -36,86 +34,1058 @@ extern "C" { #include <sys/sysmacros.h> /* - * The definitions of smp frame types and functions conforming to SAS v1.1. - * The SAS v2.0 will be supported in the future when it is publicly released. + * The definitions of smp frame types and functions conforming to SAS-1.1 and + * SAS-2. Consumers are expected to determine protocol support by examining + * the response to the REPORT GENERAL function. */ -typedef enum { +typedef enum smp_frame_type { SMP_FRAME_TYPE_REQUEST = 0x40, SMP_FRAME_TYPE_RESPONSE = 0x41 -} smp_frame_types; +} smp_frame_type_t; + +typedef enum smp_function { + SMP_FUNC_REPORT_GENERAL = 0x00, + SMP_FUNC_REPORT_MANUFACTURER_INFO = 0x01, + SMP_FUNC_READ_GPIO_REGISTER = 0x02, + SMP_FUNC_REPORT_SELF_CONFIG_STATUS = 0x03, + SMP_FUNC_REPORT_ZONE_PERM_TABLE = 0x04, + SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD = 0x05, + SMP_FUNC_REPORT_BROADCAST = 0x06, + SMP_FUNC_DISCOVER = 0x10, + SMP_FUNC_REPORT_PHY_ERROR_LOG = 0x11, + SMP_FUNC_REPORT_PHY_SATA = 0x12, + SMP_FUNC_REPORT_ROUTE_INFO = 0x13, + SMP_FUNC_REPORT_PHY_EVENT = 0x14, + SMP_FUNC_DISCOVER_LIST = 0x20, + SMP_FUNC_REPORT_PHY_EVENT_LIST = 0x21, + SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST = 0x22, + SMP_FUNC_CONFIG_GENERAL = 0x80, + SMP_FUNC_ENABLE_DISABLE_ZONING = 0x81, + SMP_FUNC_WRITE_GPIO_REGISTER = 0x82, + SMP_FUNC_ZONED_BROADCAST = 0x85, + SMP_FUNC_ZONE_LOCK = 0x86, + SMP_FUNC_ZONE_ACTIVATE = 0x87, + SMP_FUNC_ZONE_UNLOCK = 0x88, + SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD = 0x89, + SMP_FUNC_CONFIG_ZONE_PHY_INFO = 0x8A, + SMP_FUNC_CONFIG_ZONE_PERM_TABLE = 0x8B, + SMP_FUNC_CONFIG_ROUTE_INFO = 0x90, + SMP_FUNC_PHY_CONTROL = 0x91, + SMP_FUNC_PHY_TEST_FUNCTION = 0x92, + SMP_FUNC_CONFIG_PHY_EVENT = 0x93 +} smp_function_t; -typedef enum { - SMP_REPORT_GENERAL = 0x00, - SMP_REPORT_MANUFACTURER_INFO = 0x01, - SMP_DISCOVER = 0x10, - SMP_REPORT_PHY_ERROR_LOG = 0x11, - SMP_PHY_SATA = 0x12, - SMP_REPORT_ROUTE_INFORMATION = 0x13, - SMP_CONFIG_ROUTE_INFORMATION = 0x90, - SMP_PHY_CONTROL = 0x91, - SMP_PHY_TEST_FUNCTION = 0x92 -} smp_func_types; +typedef enum smp_result { + SMP_RES_FUNCTION_ACCEPTED = 0x00, + SMP_RES_UNKNOWN_FUNCTION = 0x01, + SMP_RES_FUNCTION_FAILED = 0x02, + SMP_RES_INVALID_REQUEST_FRAME_LENGTH = 0x03, + SMP_RES_INVALID_EXPANDER_CHANGE_COUNT = 0x04, + SMP_RES_BUSY = 0x05, + SMP_RES_INCOMPLETE_DESCRIPTOR_LIST = 0x06, + SMP_RES_PHY_DOES_NOT_EXIST = 0x10, + SMP_RES_INDEX_DOES_NOT_EXIST = 0x11, + SMP_RES_PHY_DOES_NOT_SUPPORT_SATA = 0x12, + SMP_RES_UNKNOWN_PHY_OPERATION = 0x13, + SMP_RES_UNKNOWN_PHY_TEST_FUNCTION = 0x14, + SMP_RES_PHY_TEST_IN_PROGRESS = 0x15, + SMP_RES_PHY_VACANT = 0x16, + SMP_RES_UNKNOWN_PHY_EVENT_SOURCE = 0x17, + SMP_RES_UNKNOWN_DESCRIPTOR_TYPE = 0x18, + SMP_RES_UNKNOWN_PHY_FILTER = 0x19, + SMP_RES_AFFILIATION_VIOLATION = 0x1A, + SMP_RES_ZONE_VIOLATION = 0x20, + SMP_RES_NO_MANAGEMENT_ACCESS_RIGHTS = 0x21, + SMP_RES_UNKNOWN_ENABLE_DISABLE_ZONING = 0x22, + SMP_RES_ZONE_LOCK_VIOLATION = 0x23, + SMP_RES_NOT_ACTIVATED = 0x24, + SMP_RES_ZONE_GROUP_OUT_OF_RANGE = 0x25, + SMP_RES_NO_PHYSICAL_PRESENCE = 0x26, + SMP_RES_SAVING_NOT_SUPPORTED = 0x27, + SMP_RES_SOURCE_ZONE_GROUP_DNE = 0x28, + SMP_RES_NONE = -1 +} smp_result_t; + +#pragma pack(1) /* - * The reqsize and rspsize in usmp_req and usmp_rsp are reserved in - * SAS v1.1, and the fields should be zero if target device is SAS v1.1 - * compliant. + * SAS-2 10.4.3.2 request frame format */ +typedef struct smp_request_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_allocated_response_len; /* reserved in SAS-1 */ + uint8_t srf_request_len; + uint8_t srf_data[1]; +} smp_request_frame_t; -#pragma pack(1) -typedef struct usmp_req { - uint8_t smpo_frametype; - uint8_t smpo_function; - uint8_t smpo_reserved; - uint8_t smpo_reqsize; - uint8_t smpo_msgframe[1]; -} usmp_req_t; - -typedef struct usmp_rsp { - uint8_t smpi_frametype; - uint8_t smpi_function; - uint8_t smpi_result; - uint8_t smpi_rspsize; - uint8_t smpi_msgframe[1]; -} usmp_rsp_t; - -struct smp_crc { - uint8_t code[4]; -}; - -struct smp_report_general_req { - uint8_t frametype; - uint8_t function; - uint8_t reserved_byte2; - uint8_t reqsize; - struct smp_crc crc; -}; - -struct smp_report_general_rsp { - uint8_t frametype; - uint8_t function; - uint8_t result; - uint8_t rspsize; - uint8_t expand_change_count1; - uint8_t expand_change_count0; - uint8_t expand_route_index1; - uint8_t expand_route_index0; - uint8_t reserved_byte8; - uint8_t num_of_phy; +/* + * SAS-2 10.4.3.3 response frame format + */ +typedef struct smp_response_frame { + uint8_t srf_frame_type; + uint8_t srf_function; + uint8_t srf_result; + uint8_t srf_response_len; /* reserved in SAS-1 */ + uint8_t srf_data[1]; +} smp_response_frame_t; + +typedef uint8_t smp_crc_t[4]; + +#ifdef offsetof +#define SMP_REQ_MINLEN \ + (offsetof(smp_request_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#define SMP_RESP_MINLEN \ + (offsetof(smp_response_frame_t, srf_data[0]) + sizeof (smp_crc_t)) +#endif /* offsetof */ + +/* + * SAS-2 10.4.3.4 REPORT GENERAL (no additional request bytes) + */ +typedef struct smp_report_general_resp { + uint16_t srgr_exp_change_count; + uint16_t srgr_exp_route_indexes; + DECL_BITFIELD2( + _reserved1 :7, + srgr_long_response :1); + uint8_t srgr_number_of_phys; + DECL_BITFIELD7( + srgr_externally_configurable_route_table :1, + srgr_configuring :1, + srgr_configures_others :1, + srgr_open_reject_retry_supported :1, + srgr_stp_continue_awt :1, + _reserved2 :2, + srgr_table_to_table_supported :1); + uint8_t _reserved3; + uint64_t srgr_enclosure_logical_identifier; + uint8_t _reserved4[8]; + uint8_t _reserved5[2]; + uint16_t srgr_stp_bus_inactivity_time_limit; + uint16_t srgr_stp_maximum_connect_time_limit; + uint16_t srgr_stp_smp_nexus_loss_time; + DECL_BITFIELD7( + srgr_zoning_enabled :1, + srgr_zoning_supported :1, + srgr_physical_presence_asserted :1, + srgr_physical_presence_supported :1, + srgr_zone_locked :1, + _reserved6 :1, + srgr_number_of_zone_grps :2); + DECL_BITFIELD6( + srgr_saving_zoning_enabled_supported :1, + srgr_saving_zone_perm_table_supported :1, + srgr_saving_zone_phy_info_supported :1, + srgr_saving_zone_mgr_password_supported :1, + srgr_saving :1, + _reserved7 :4); + uint16_t srgr_max_routed_sas_addrs; + uint64_t srgr_active_zm_sas_addr; + uint16_t srgr_zone_lock_inactivity_limit; + uint8_t _reserved8[2]; + uint8_t _reserved9; + uint8_t srgr_first_encl_conn_elem_idx; + uint8_t srgr_number_encl_conn_elem_idxs; + uint8_t _reserved10; + DECL_BITFIELD2( + _reserved11 :7, + srgr_reduced_functionality :1); + uint8_t srgr_time_to_reduced_functionality; + uint8_t srgr_initial_time_to_reduced_functionality; + uint8_t srgr_max_reduced_functionality_time; + uint16_t srgr_last_self_conf_status_descr_idx; + uint16_t srgr_max_stored_self_config_status_descrs; + uint16_t srgr_last_phy_event_list_descr_idx; + uint16_t srgr_max_stored_phy_event_list_descrs; + uint16_t srgr_stp_reject_to_open_limit; + uint8_t _reserved12[2]; +} smp_report_general_resp_t; + +typedef enum smp_n_zone_grps { + SMP_ZONE_GROUPS_128 = 0x0, + SMP_ZONE_GROUPS_256 = 0x1 +} smp_n_zone_grps_t; + +/* + * SAS-2 10.4.3.5 REPORT MANUFACTURER INFORMATION (no additional request bytes) + */ +typedef struct smp_report_manufacturer_info_resp { + uint16_t srmir_exp_change_count; + uint8_t _reserved1[2]; + DECL_BITFIELD2( + srmir_sas_1_1_format :1, + _reserved2 :7); + uint8_t _reserved3[3]; + char srmir_vendor_identification[8]; + char srmir_product_identification[16]; + char srmir_product_revision_level[4]; + char srmir_component_vendor_identification[8]; + uint16_t srmir_component_id; + uint8_t srmir_component_revision_level; + uint8_t _reserved4; + uint8_t srmir_vs_52[8]; +} smp_report_manufacturer_info_resp_t; + +/* + * SAS-2 10.4.3.6 REPORT SELF_CONFIGURATION STATUS + */ +typedef struct smp_report_self_config_status_req { + uint8_t _reserved1[2]; + uint16_t srscsr_starting_self_config_status_descr_idx; +} smp_report_self_config_status_req_t; + +typedef struct smp_report_self_config_status_resp { + uint16_t srscsr_exp_change_count; + uint16_t srscsr_starting_self_config_status_descr_idx; + uint16_t srscsr_number_self_config_status_descrs; + uint16_t srscsr_last_self_config_status_descr_idx; + uint8_t srscsr_self_config_status_descr_len; + uint8_t _reserved1[3]; + uint8_t srscsr_descrs[1]; +} smp_report_self_config_status_resp_t; + +typedef struct smp_self_config_status_descr { + uint8_t sscsd_status_type; + DECL_BITFIELD2( + sscsd_final :1, + _reserved1 :7); + uint8_t _reserved2; + uint8_t sscsd_phy_identifier; + uint8_t _reserved3[4]; + uint64_t sscsd_sas_addr; +} smp_self_config_status_descr_t; + +typedef enum smp_self_config_status_type { + SMP_SCST_NONSPECIFIC_ERROR = 0x01, + SMP_SCST_CONNECTION = 0x02, + SMP_SCST_ROUTE_TABLE_FULL = 0x03, + SMP_SCST_NOMEM = 0x04, + SMP_SCST_PHY_LAYER_ERROR = 0x20, + SMP_SCST_LOST_SYNC = 0x21, + SMP_SCST_LINK_LAYER_ERROR = 0x40, + SMP_SCST_OPEN_TIMEOUT = 0x41, + SMP_SCST_ABANDON_OPEN_REJECT = 0x42, + SMP_SCST_RETRY_OPEN_REJECTS = 0x43, + SMP_SCST_NEXUS_LOSS = 0x44, + SMP_SCST_BREAK = 0x45, + SMP_SCST_CRC_ERROR = 0x46, + SMP_SCST_PORT_LAYER_ERROR = 0x60, + SMP_SCST_RESPONSE_TIMEOUT = 0x61, + SMP_SCST_TRANSPORT_LAYER_ERROR = 0x80, + SMP_SCST_APP_LAYER_ERROR = 0xA0, + SMP_SCST_RESPONSE_TOO_SHORT = 0xA1, + SMP_SCST_UNSUPPORTED_VALUES = 0xA2, + SMP_SCST_INCONSISTENT = 0xA3, + SMP_SCST_CONFIGURING = 0xA4 +} smp_self_config_status_type_t; + +/* + * SAS-2 10.4.3.7 REPORT ZONE PERMISSION TABLE + */ +typedef struct smp_report_zone_perm_table_req { + DECL_BITFIELD2( + srzptr_report_type :2, + _reserved1 :6); + uint8_t _reserved2; + uint8_t srzptr_starting_src_zone_grp; + uint8_t srzptr_max_zone_perm_descrs; +} smp_report_zone_perm_table_req_t; + +typedef enum smp_zone_perm_table_report_type { + SMP_ZPTRT_CURRENT = 0x0, + SMP_ZPTRT_SHADOW = 0x1, + SMP_ZPTRT_SAVED = 0x2, + SMP_ZPTRT_DEFAULT = 0x3 +} smp_zone_perm_table_report_type_t; + +typedef struct smp_report_zone_perm_table_resp { + uint16_t srzptr_exp_change_count; DECL_BITFIELD3( - crt :1, - configuring :1, - reserved_byte10 :6); - uint8_t reserved_byte11; - uint64_t identifier; - uint8_t reserved_byte20[8]; - struct smp_crc crc; -}; + srzptr_report_type :2, + _reserved1 :5, + srzptr_zone_locked :1); + DECL_BITFIELD2( + _reserved2 :6, + srzptr_number_zone_grps :2); + uint8_t _reserved3[6]; + uint8_t srzptr_starting_src_zone_grp; + uint8_t srzptr_number_zone_perm_descrs; + uint8_t srzptr_descrs[1]; +} smp_report_zone_perm_table_resp_t; + +typedef uint8_t smp_zone_perm_descr128_t[16]; +typedef uint8_t smp_zone_perm_descr256_t[32]; + +#define SMP_ZONE_PERM_BIT128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] & (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_SET128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] |= (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_CLR128(__d, __z) \ + ((__d)[15 - ((__z) >> 3)] &= ~(1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_BIT256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] & (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_SET256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] |= (1 << ((__z) & 7))) + +#define SMP_ZONE_PERM_CLR256(__d, __z) \ + ((__d)[31 - ((__z) >> 3)] &= ~(1 << ((__z) & 7))) + +/* + * SAS-2 10.4.3.8 REPORT ZONE MANAGER PASSWORD (no additional request bytes) + */ +typedef struct smp_report_zone_mgr_password_resp { + uint16_t srzmpr_exp_change_count; + uint8_t _reserved1[2]; + uint8_t srzmpr_zone_mgr_password[32]; +} smp_report_zone_mgr_password_resp_t; + +/* + * SAS-2 10.4.3.9 REPORT BROADCAST + */ +typedef struct smp_report_broadcast_req { + DECL_BITFIELD2( + srbr_broadcast_type :4, + _reserved1 :4); + uint8_t _reserved2[3]; +} smp_report_broadcast_req_t; + +typedef enum smp_broadcast_type { + SMP_BROADCAST_CHANGE = 0x0, + SMP_BROADCAST_RESERVED_CHANGE_0 = 0x1, + SMP_BROADCAST_RESERVED_CHANGE_1 = 0x2, + SMP_BROADCAST_SES = 0x3, + SMP_BROADCAST_EXPANDER = 0x4, + SMP_BROADCAST_ASYNC_EVENT = 0x5, + SMP_BROADCAST_RESERVED_3 = 0x6, + SMP_BROADCAST_RESERVED_4 = 0x7, + SMP_BROADCAST_ZONE_ACTIVATE = 0x8 +} smp_broadcast_type_t; + +typedef struct smp_broadcast_descr { + DECL_BITFIELD2( + sbd_broadcast_type :4, + _reserved1 :4); + uint8_t sbd_phy_identifier; + DECL_BITFIELD2( + sbd_broadcast_reason :4, + _reserved2 :4); + uint16_t sbd_broadcast_count; + uint8_t _reserved3[10]; +} smp_broadcast_descr_t; + +typedef struct smp_report_broadcast_resp { + uint16_t srbr_exp_change_count; + DECL_BITFIELD2( + srbr_broadcast_type :4, + _reserved1 :4); + uint8_t srbr_number_broadcast_descrs; + smp_broadcast_descr_t srbr_descrs[1]; +} smp_report_broadcast_resp_t; + +/* + * SAS-2 10.4.3.10 DISCOVER + */ +typedef struct smp_discover_req { + uint8_t _reserved1[4]; + DECL_BITFIELD2( + sdr_ignore_zone_grp :1, + _reserved2 :7); + uint8_t sdr_phy_identifier; + uint8_t _reserved3[2]; +} smp_discover_req_t; + +typedef struct smp_snw3_phy_cap { + DECL_BITFIELD4( + sspc_requested_logical_link_rate :4, /* smp_link_rate_t */ + _reserved1 :2, + sspc_tx_ssc_type :1, + sspc_start :1); + DECL_BITFIELD7( + _reserved2 :2, + sspc_g3_ssc :1, + sspc_g3_no_ssc :1, + sspc_g2_ssc :1, + sspc_g2_no_ssc :1, + sspc_g1_ssc :1, + sspc_g1_no_ssc :1); + uint8_t _reserved3; + DECL_BITFIELD2( + sspc_parity :1, + _reserved4 :7); +} smp_snw3_phy_cap_t; + +typedef struct smp_discover_resp { + uint16_t sdr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t sdr_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD3( + sdr_attached_reason :4, + sdr_attached_device_type :3, + _reserved3 :1); + DECL_BITFIELD2( + sdr_negotiated_logical_link_rate :4, /* smp_link_rate_t */ + _reserved4 :4); + DECL_BITFIELD5( + sdr_attached_sata_host :1, + sdr_attached_smp_initiator :1, + sdr_attached_stp_initiator :1, + sdr_attached_ssp_initiator :1, + _reserved5 :4); + DECL_BITFIELD6( + sdr_attached_sata_device :1, + sdr_attached_smp_target :1, + sdr_attached_stp_target :1, + sdr_attached_ssp_target :1, + _reserved6 :3, + sdr_attached_sata_port_selector :1); + uint64_t sdr_sas_addr; + uint64_t sdr_attached_sas_addr; + uint8_t sdr_attached_phy_identifier; + DECL_BITFIELD4( + sdr_attached_break_reply_capable :1, + sdr_attached_requested_inside_zpsds :1, + sdr_attached_inside_zpsds_persistent :1, + _reserved7 :5); + uint8_t _reserved8[6]; + DECL_BITFIELD2( + sdr_hw_min_phys_link_rate :4, /* smp_link_rate_t */ + sdr_prog_min_phys_link_rate :4); /* smp_link_rate_t */ + DECL_BITFIELD2( + sdr_hw_max_phys_link_rate :4, /* smp_link_rate_t */ + sdr_prog_max_phys_link_rate :4); /* smp_link_rate_t */ + uint8_t sdr_phy_change_count; + DECL_BITFIELD3( + sdr_partial_pwy_timeout :4, + _reserved9 :3, + sdr_virtual_phy :1); + DECL_BITFIELD2( + sdr_routing_attr :4, /* smp_routing_attr_t */ + _reserved10 :4); + DECL_BITFIELD2( + sdr_connector_type :7, + _reserved11 :1); + uint8_t sdr_connector_element_index; + uint8_t sdr_connector_physical_link; + uint8_t _reserved12[2]; + uint8_t sdr_vendor[2]; + uint64_t sdr_attached_device_name; + DECL_BITFIELD8( + sdr_zoning_enabled :1, + sdr_inside_zpsds :1, + sdr_zone_group_persistent :1, + _reserved13 :1, + sdr_requested_inside_zpsds :1, + sdr_inside_zpsds_persistent :1, + sdr_requested_inside_zpsds_changed_by_exp :1, + _reserved14 :1); + uint8_t _reserved15[2]; + uint8_t sdr_zone_group; + uint8_t sdr_self_config_status; + uint8_t sdr_self_config_levels_completed; + uint8_t _reserved16[2]; + uint64_t sdr_self_config_sas_addr; + smp_snw3_phy_cap_t sdr_prog_phy_cap; + smp_snw3_phy_cap_t sdr_current_phy_cap; + smp_snw3_phy_cap_t sdr_attached_phy_cap; + uint8_t _reserved17[6]; + DECL_BITFIELD2( + sdr_negotiated_phys_link_rate :4, /* smp_link_rate_t */ + sdr_reason :4); + DECL_BITFIELD3( + sdr_hw_muxing_supported :1, + sdr_negotiated_ssc :1, + _reserved18 :6); + DECL_BITFIELD7( + sdr_default_zoning_enabled :1, + _reserved19 :1, + sdr_default_zone_group_persistent :1, + _reserved20 :1, + sdr_default_requested_inside_zpsds :1, + sdr_default_inside_zpsds_persistent :1, + _reserved21 :2); + uint8_t _reserved22[2]; + uint8_t sdr_default_zone_group; + DECL_BITFIELD7( + sdr_saved_zoning_enabled :1, + _reserved23 :1, + sdr_saved_zone_group_persistent :1, + _reserved24 :1, + sdr_saved_requested_inside_zpsds :1, + sdr_saved_inside_zpsds_persistent :1, + _reserved25 :2); + uint8_t _reserved26[2]; + uint8_t saved_zone_group; + DECL_BITFIELD6( + _reserved27 :2, + sdr_shadow_zone_group_persistent :1, + _reserved28 :1, + sdr_shadow_requested_inside_zpsds :1, + sdr_shadow_inside_zpsds_persistent :1, + _reserved29 :2); + uint8_t _reserved30[2]; + uint8_t sdr_shadow_zone_group; +} smp_discover_resp_t; + +typedef enum smp_link_rate { + SMP_LINK_RATE_NO_CHANGE = 0x0, + SMP_LINK_RATE_DISABLED = 0x1, + SMP_LINK_RATE_RESET_PROBLEM = 0x2, + SMP_LINK_RATE_SPINUP_HOLD = 0x3, + SMP_LINK_RATE_PORT_SELECTOR = 0x4, + SMP_LINK_RATE_RESET = 0x5, + SMP_LINK_RATE_UNSUPPORTED = 0x6, + SMP_LINK_RATE_1_5 = 0x8, + SMP_LINK_RATE_3 = 0x9, + SMP_LINK_RATE_6 = 0xA +} smp_link_rate_t; + +typedef enum smp_device_type { + SMP_DEV_NONE = 0x0, + SMP_DEV_SAS_SATA = 0x1, + SMP_DEV_EXPANDER = 0x2, + SMP_DEV_EXPANDER_OLD = 0x3 +} smp_device_type_t; + +typedef enum smp_routing_attr { + SMP_ROUTING_DIRECT = 0x0, + SMP_ROUTING_SUBTRACTIVE = 0x1, + SMP_ROUTING_TABLE = 0x2 +} smp_routing_attr_t; + +/* + * SAS-2 10.4.3.11 REPORT PHY ERROR LOG + */ +typedef struct smp_report_phy_error_log_req { + uint8_t _reserved1[5]; + uint8_t srpelr_phy_identifier; + uint8_t _reserved2[2]; +} smp_report_phy_error_log_req_t; + +typedef struct smp_report_phy_error_log_resp { + uint16_t srpelr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srpelr_phy_identifier; + uint8_t _reserved2[2]; + uint32_t srpelr_invalid_dword_count; + uint32_t srpelr_running_disparity_error_count; + uint32_t srpelr_loss_dword_sync_count; + uint32_t srpelr_phy_reset_problem_count; +} smp_report_phy_error_log_resp_t; + +/* + * SAS-2 10.4.3.12 REPORT PHY SATA + */ +typedef struct smp_report_phy_sata_req { + uint8_t _reserved1[5]; + uint8_t srpsr_phy_identifier; + uint8_t srpsr_affiliation_context; + uint8_t _reserved2; +} smp_report_phy_sata_req_t; + +typedef struct smp_report_phy_sata_resp { + uint16_t srpsr_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srpsr_phy_identifier; + uint8_t _reserved2; + DECL_BITFIELD4( + srpsr_affiliation_valid :1, + srpsr_affiliations_supported :1, + srpsr_stp_nexus_loss :1, + _reserved3 :5); + uint8_t _reserved4[4]; + uint64_t srpsr_stp_sas_addr; + uint8_t srpsr_register_device_host_fis[20]; + uint8_t _reserved5[4]; + uint64_t srpsr_affiliated_stp_init_sas_addr; + uint64_t srpsr_stp_nexus_loss_sas_addr; + uint8_t _reserved6; + uint8_t srpsr_affiliation_context; + uint8_t srpsr_current_affiliation_contexts; + uint8_t srpsr_max_affiliation_contexts; +} smp_report_phy_sata_resp_t; + +/* + * SAS-2 10.4.3.13 REPORT ROUTE INFORMATION + */ +typedef struct smp_report_route_info_req { + uint8_t _reserved1[2]; + uint16_t srrir_exp_route_index; + uint8_t _reserved2; + uint8_t srrir_phy_identifier; + uint8_t _reserved3[2]; +} smp_report_route_info_req_t; + +typedef struct smp_report_route_info_resp { + uint16_t srrir_exp_change_count; + uint16_t srrir_exp_route_index; + uint8_t _reserved1; + uint8_t srrir_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD2( + _reserved3 :7, + srrir_exp_route_entry_disabled :1); + uint8_t _reserved4[3]; + uint64_t srrir_routed_sas_addr; + uint8_t _reserved5[16]; +} smp_report_route_info_resp_t; + +/* + * SAS-2 10.4.3.14 SAS-2 REPORT PHY EVENT + */ +typedef struct smp_report_phy_event_req { + uint8_t _reserved1; + uint8_t _reserved2[4]; + uint8_t srper_phy_identifier; + uint8_t _reserved3[2]; +} smp_report_phy_event_req_t; + +typedef struct smp_phy_event_report_descr { + uint8_t _reserved1[3]; + uint8_t sped_phy_event_source; + uint32_t sped_phy_event; + uint32_t sped_peak_detector_threshold; +} smp_phy_event_report_descr_t; + +typedef struct smp_report_phy_event_resp { + uint16_t srper_exp_change_count; + uint8_t _reserved1[3]; + uint8_t srper_phy_identifier; + uint8_t _reserved2[5]; + uint8_t srper_n_phy_event_descrs; + smp_phy_event_report_descr_t srper_phy_event_descrs[1]; +} smp_report_phy_event_resp_t; + +/* + * SAS-2 10.4.3.15 SAS-2 DISCOVER LIST + */ +typedef struct smp_discover_list_req { + uint8_t _reserved1[4]; + uint8_t sdlr_starting_phy_identifier; + uint8_t sdlr_max_descrs; + DECL_BITFIELD3( + sdlr_phy_filter :4, + _reserved2 :3, + sdlr_ignore_zone_group :1); + DECL_BITFIELD2( + sdlr_descr_type :4, + _reserved3 :4); + uint8_t _reserved4[4]; + uint8_t sdlr_vendor[12]; +} smp_discover_list_req_t; + +typedef struct smp_discover_short_descr { + uint8_t sdsd_phy_identifier; + uint8_t sdsd_function_result; + DECL_BITFIELD3( + sdsd_attached_reason :4, + sdsd_attached_device_type :3, + _restricted1 :1); + DECL_BITFIELD2( + sdsd_negotiated_logical_link_rate :4, /* smp_link_rate_t */ + _restricted2 :4); + DECL_BITFIELD5( + sdsd_attached_sata_host :1, + sdsd_attached_smp_initiator :1, + sdsd_attached_stp_initiator :1, + sdsd_attached_ssp_initiator :1, + _restricted3 :4); + DECL_BITFIELD6( + sdsd_attached_sata_device :1, + sdsd_attached_smp_target :1, + sdsd_attached_stp_target :1, + sdsd_attached_ssp_target :1, + _restricted4 :3, + sdsd_attached_sata_port_selector :1); + DECL_BITFIELD3( + sdsd_routing_attribute :4, /* smp_routing_attr_t */ + _reserved1 :3, + sdsd_virtual_phy :1); + DECL_BITFIELD2( + _reserved2 :4, + sdsd_reason :4); + uint8_t sdsd_zone_group; + DECL_BITFIELD7( + _reserved3 :1, + sdsd_inside_zpsds :1, + sdsd_zone_group_persistent :1, + _reserved4 :1, + sdsd_requested_insize_zpsds :1, + sdsd_inside_zpsds_persistent :1, + _restricted5 :2); + uint8_t sdsd_attached_phy_identifier; + uint8_t sdsd_phy_change_count; + uint64_t sdsd_attached_sas_addr; + uint8_t _reserved5[4]; +} smp_discover_short_descr_t; + +typedef struct smp_discover_long_descr { + uint8_t _reserved1[2]; + uint8_t sdld_function_result; + uint8_t _reserved2[1]; + smp_discover_resp_t sdld_response; +} smp_discover_long_descr_t; + +#define SMP_DISCOVER_RESP(_ld) \ + (((smp_discover_long_descr_t *)(_ld))->sdld_function_result == \ + SMP_FUNCTION_ACCEPTED ? \ + &((smp_discover_long_descr_t *)(_ld))->sdld_response : \ + NULL) + +typedef struct smp_discover_list_resp { + uint16_t sdlr_exp_change_count; + uint8_t _reserved1[2]; + uint8_t sdlr_starting_phy_identifier; + uint8_t sdlr_n_descrs; + DECL_BITFIELD2( + sdlr_phy_filter :4, + _reserved2 :4); + DECL_BITFIELD2( + sdlr_descr_type :4, + _reserved3 :4); + uint8_t sdlr_descr_length; + uint8_t _reserved4[3]; + DECL_BITFIELD5( + sdlr_externally_configurable_route_table :1, + sdlr_configuring :1, + _reserved5 :4, + sdlr_zoning_enabled :1, + sdlr_zoning_supported :1); + uint8_t _reserved6; + uint16_t sdlr_last_sc_status_descr_index; + uint16_t sdlr_last_phy_event_list_descr_index; + uint8_t _reserved7[10]; + uint8_t sdlr_vendor[16]; + uint8_t sdlr_descrs[1]; /* short or long format */ +} smp_discover_list_resp_t; + +/* + * SAS-2 10.4.3.16 REPORT PHY EVENT LIST + */ +typedef struct smp_report_phy_event_list_req { + uint8_t _reserved1[2]; + uint16_t srpelr_starting_descr_index; +} smp_report_phy_event_list_req_t; + +typedef struct smp_phy_event_list_descr { + uint8_t _reserved1[2]; + uint8_t speld_phy_identifier; + uint8_t speld_phy_event_source; + uint32_t speld_phy_event; + uint32_t speld_peak_detector_threshold; +} smp_phy_event_list_descr_t; + +typedef struct smp_report_phy_event_list_resp { + uint16_t srpelr_exp_change_count; + uint16_t srpelr_starting_descr_index; + uint16_t srpelr_last_descr_index; + uint8_t srpelr_phy_event_list_descr_length; + uint8_t _reserved1[3]; + uint8_t srpelr_n_descrs; + smp_phy_event_list_descr_t srpelr_descrs[1]; +} smp_report_phy_event_list_resp_t; + +/* + * SAS-2 10.4.3.17 REPORT EXPANDER ROUTE TABLE LIST + */ +typedef struct smp_report_exp_route_table_list_req { + uint8_t _reserved1[4]; + uint16_t srertlr_max_descrs; + uint16_t srertlr_starting_routed_sas_addr_index; + uint8_t _reserved2[7]; + uint8_t srertlr_starting_phy_identifier; + uint8_t _reserved3[8]; +} smp_report_exp_route_table_list_req_t; + +typedef struct smp_route_table_descr { + uint64_t srtd_routed_sas_addr; + uint8_t srtd_phy_bitmap[6]; + DECL_BITFIELD2( + _reserved1 :7, + srtd_zone_group_valid :1); + uint8_t srtd_zone_group; +} smp_route_table_descr_t; + +#define SMP_ROUTE_PHY(_d, _s, _i) \ + ((_d)->srtd_phy_bitmap[(48 - (_i) + (_s)) >> 3] & \ + (1 << ((48 - (_i) + (_s)) & 7))) + +typedef struct smp_report_exp_route_table_list_resp { + uint16_t srertlr_exp_change_count; + uint16_t srertlr_route_table_change_count; + DECL_BITFIELD3( + _reserved1 :1, + srertlr_configuring :1, + _reserved2 :6); + uint8_t _reserved3; + uint16_t srertlr_n_descrs; + uint16_t srertlr_first_routed_sas_addr_index; + uint16_t srertlr_last_routed_sas_addr_index; + uint8_t _reserved4[3]; + uint8_t srertlr_starting_phy_identifier; + uint8_t _reserved5[12]; + smp_route_table_descr_t srertlr_descrs[1]; +} smp_report_exp_route_table_list_resp_t; + +/* + * SAS-2 10.4.3.18 CONFIGURE GENERAL (no additional response) + */ +typedef struct smp_config_general_req { + uint16_t scgr_expected_exp_change_count; + uint8_t _reserved1[2]; + DECL_BITFIELD6( + scgr_update_stp_bus_inactivity :1, + scgr_update_stp_max_conn :1, + scgr_update_stp_smp_nexus_loss :1, + scgr_update_initial_time_to_reduced_functionality :1, + scgr_update_stp_reject_to_open :1, + _reserved2 :3); + uint8_t _reserved3; + uint16_t scgr_stp_bus_inactivity; + uint16_t scgr_stp_max_conn; + uint16_t scgr_stp_smp_nexus_loss; + uint8_t scgr_initial_time_to_reduced_functionality; + uint8_t _reserved4; + uint16_t scgr_stp_reject_to_open; +} smp_config_general_req_t; + +/* + * SAS-2 10.4.3.19 ENABLE DISABLE ZONING (no additional response) + */ +typedef struct smp_enable_disable_zoning_req { + uint16_t sedzr_expected_exp_change_count; + DECL_BITFIELD2( + sedzr_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t _reserved2; + DECL_BITFIELD2( + sedzr_enable_disable_zoning :2, + _reserved3 :6); + uint8_t _reserved4[3]; +} smp_enable_disable_zoning_req_t; + +typedef enum smp_zoning_save { + SMP_ZONING_SAVE_CURRENT = 0x0, + SMP_ZONING_SAVE_SAVED = 0x1, + SMP_ZONING_SAVE_BOTH_IF_SUPP = 0x2, + SMP_ZONING_SAVE_BOTH = 0x3 +} smp_zoning_save_t; + +typedef enum smp_zoning_enable_op { + SMP_ZONING_ENABLE_OP_NONE = 0x0, + SMP_ZONING_ENABLE_OP_ENABLE = 0x1, + SMP_ZONING_ENABLE_OP_DISABLE = 0x2 +} smp_zoning_enable_op_t; + +/* + * SAS-2 10.4.3.20 ZONED BROADCAST (no additional response) + */ +typedef struct smp_zoned_broadcast_req { + uint8_t _restricted1[2]; + DECL_BITFIELD2( + szbr_broadcast_type :4, + _reserved :4); + uint8_t szbr_n_broadcast_source_zone_groups; + uint8_t szbr_broadcast_source_zone_groups[1]; +} smp_zoned_broadcast_req_t; + +/* + * SAS-2 10.4.3.21 ZONE LOCK + */ +typedef struct smp_zone_lock_req { + uint16_t szlr_expected_exp_change_count; + uint16_t szlr_zone_lock_inactivity_timeout; + uint8_t szlr_zone_manager_password[32]; +} smp_zone_lock_req_t; + +typedef struct smp_zone_lock_resp { + uint8_t _reserved1[4]; + uint64_t szlr_active_zone_manager_sas_addr; +} smp_zone_lock_resp_t; + +/* + * SAS-2 10.4.3.22 ZONE ACTIVATE (no additional response) + */ +typedef struct smp_zone_activate_req { + uint16_t szar_expected_exp_change_count; + uint8_t _reserved1[2]; +} smp_zone_activate_req_t; + +/* + * SAS-2 10.4.3.23 ZONE UNLOCK (no additional response) + */ +typedef struct smp_zone_unlock_req { + uint8_t _restricted1[2]; + DECL_BITFIELD2( + szur_activate_required :1, + _reserved1 :7); + uint8_t _reserved2; +} smp_zone_unlock_req_t; + +/* + * SAS-2 10.4.3.24 CONFIGURE ZONE MANAGER PASSWORD (no additional response) + */ +typedef struct smp_config_zone_manager_password_req { + uint16_t sczmpr_expected_exp_change_count; + DECL_BITFIELD2( + sczmpr_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t _reserved2; + uint8_t sczmpr_zone_manager_password[32]; + uint8_t sczmpr_new_zone_manager_password[32]; +} smp_config_zone_manager_password_req_t; + +/* + * SAS-2 10.4.3.25 CONFIGURE ZONE PHY INFORMATION (no additional response) + */ +typedef struct smp_zone_phy_config_descr { + uint8_t szpcd_phy_identifier; + DECL_BITFIELD6( + _reserved1 :2, + szpcd_zone_group_persistent :1, + _reserved2 :1, + szpcd_requested_inside_zpsds :1, + szpcd_inside_zpsds_persistent :1, + _reserved3 :2); + uint8_t _reserved4; + uint8_t szpcd_zone_group; +} smp_zone_phy_config_descr_t; + +typedef struct smp_config_zone_phy_info_req { + uint16_t sczpir_expected_exp_change_count; + DECL_BITFIELD2( + sczpir_save :2, /* smp_zoning_save_t */ + _reserved1 :6); + uint8_t sczpir_n_descrs; + smp_zone_phy_config_descr_t sczpir_descrs[1]; +} smp_config_zone_phy_info_req_t; + +/* + * SAS-2 10.4.3.26 CONFIGURE ZONE PERMISSION TABLE (no additional response) + */ +typedef struct smp_config_zone_perm_table_req { + uint16_t sczptr_expected_exp_change_count; + uint8_t sczptr_starting_source_zone_group; + uint8_t sczptr_n_descrs; + DECL_BITFIELD3( + sczptr_save :2, /* smp_zoning_save_t */ + _reserved1 :4, + sczptr_n_zone_groups :2); /* smp_n_zone_grps_t */ + uint8_t _reserved2[7]; + uint8_t sczptr_descrs[1]; /* smp_zone_perm_descrXXX_t */ +} smp_config_zone_perm_table_req_t; + +/* + * SAS-2 10.4.3.27 CONFIGURE ROUTE INFORMATION (no additional response) + */ +typedef struct smp_config_route_info_req { + uint16_t scrir_expected_exp_change_count; + uint16_t scrir_exp_route_index; + uint8_t _reserved1; + uint8_t scrir_phy_identifier; + uint8_t _reserved2[2]; + DECL_BITFIELD2( + _reserved3 :7, + scrir_disable_exp_route_entry :1); + uint8_t _reserved4[3]; + uint64_t scrir_routed_sas_addr; + uint8_t _reserved5[16]; +} smp_config_route_info_req_t; + +/* + * SAS-2 10.4.3.28 PHY CONTROL (no additional response) + */ +typedef struct smp_phy_control_req { + uint16_t spcr_expected_exp_change_count; + uint8_t _reserved1[3]; + uint8_t spcr_phy_identifier; + uint8_t spcr_phy_operation; + DECL_BITFIELD2( + spcr_update_partial_pwy_timeout :1, + _reserved2 :7); + uint8_t _reserved3[12]; + uint64_t spcr_attached_device_name; + DECL_BITFIELD2( + _reserved4 :4, + spcr_prog_min_phys_link_rate :4); /* smp_link_rate_t */ + DECL_BITFIELD2( + _reserved5 :4, + spcr_prog_max_phys_link_rate :4); /* smp_link_rate_t */ + uint8_t _reserved6[2]; + DECL_BITFIELD2( + spcr_partial_pwy_timeout :4, + _reserved7 :4); + uint8_t _reserved8[3]; +} smp_phy_control_req_t; + +typedef enum smp_phy_op { + SMP_PHY_OP_NOP = 0x00, + SMP_PHY_OP_LINK_RESET = 0x01, + SMP_PHY_OP_HARD_RESET = 0x02, + SMP_PHY_OP_DISABLE = 0x03, + SMP_PHY_OP_CLEAR_ERROR_LOG = 0x05, + SMP_PHY_OP_CLEAR_AFFILIATION = 0x06, + SMP_PHY_OP_TRANSMIT_SATA_PORT_SELECTION_SIGNAL = 0x07, + SMP_PHY_OP_CLEAR_STP_NEXUS_LOSS = 0x08, + SMP_PHY_OP_SET_ATTACHED_DEVICE_NAME = 0x09 +} smp_phy_op_t; + +/* + * SAS-2 10.4.3.29 PHY TEST FUNCTION (no additional response) + */ +typedef struct smp_phy_test_function_req { + uint16_t sptfr_expected_exp_change_count; + uint8_t _reserved1[3]; + uint8_t sptfr_phy_identifier; + uint8_t sptfr_phy_test_function; + uint8_t sptfr_phy_test_pattern; /* smp_phy_test_function_t */ + uint8_t _reserved2[3]; + DECL_BITFIELD4( + sptfr_test_pattern_phys_link_rate :4, /* smp_link_rate_t */ + sptfr_test_pattern_ssc :2, + sptfr_test_pattern_sata :1, + _reserved3 :1); + uint8_t _reserved4[3]; + uint8_t sptfr_phy_test_pattern_dwords_ctl; + uint8_t sptfr_phy_test_pattern_dwords[8]; + uint8_t _reserved5[12]; +} smp_phy_test_function_req_t; + +typedef enum smp_phy_test_function { + SMP_PHY_TEST_FN_STOP = 0x00, + SMP_PHY_TEST_FN_TRANSMIT_PATTERN = 0x01 +} smp_phy_test_function_t; + +/* + * SAS-2 10.4.3.30 CONFIGURE PHY EVENT (no additional response) + */ +typedef struct smp_phy_event_config_descr { + uint8_t _reserved1[3]; + uint8_t specd_phy_event_source; + uint32_t specd_peak_value_detector_threshold; +} smp_phy_event_config_descr_t; + +typedef struct smp_config_phy_event_req { + uint16_t scper_expected_exp_change_count; + DECL_BITFIELD2( + scper_clear_peaks :1, + _reserved1 :7); + uint8_t _reserved2[2]; + uint8_t scper_phy_identifier; + uint8_t _reserved3; + uint8_t scper_n_descrs; + smp_phy_event_config_descr_t scper_descrs[1]; +} smp_config_phy_event_req_t; + #pragma pack() #ifdef __cplusplus } #endif -#endif /* _SYS_SCSI_IMPL_SMP_FRAME_H */ +#endif /* _SYS_SCSI_GENERIC_SMP_FRAMES_H */ diff --git a/usr/src/uts/common/sys/scsi/impl/sas_transport.h b/usr/src/uts/common/sys/scsi/impl/sas_transport.h index a592fe6308..43d55c28ad 100644 --- a/usr/src/uts/common/sys/scsi/impl/sas_transport.h +++ b/usr/src/uts/common/sys/scsi/impl/sas_transport.h @@ -67,7 +67,8 @@ typedef struct smp_pkt { size_t pkt_reqsize; size_t pkt_rspsize; int pkt_timeout; - uchar_t pkt_reason; /* code from errno.h */ + uchar_t pkt_reason; /* code from errno.h */ + uchar_t pkt_will_retry; /* will retry on EAGAIN */ sas_addr_t *pkt_address; } smp_pkt_t; @@ -87,22 +88,234 @@ struct sas_hba_tran { int (*tran_smp_start)( struct smp_pkt *pkt); + int (*tran_smp_init)( + dev_info_t *self, + dev_info_t *child, + sas_hba_tran_t *tran, + smp_device_t *smp); + + void (*tran_smp_free)( + dev_info_t *self, + dev_info_t *child, + sas_hba_tran_t *tran, + smp_device_t *smp); }; -extern sas_hba_tran_t *sas_hba_tran_alloc(dev_info_t *dip, int flags); +extern sas_hba_tran_t *sas_hba_tran_alloc(dev_info_t *dip); extern int sas_hba_attach_setup(dev_info_t *dip, sas_hba_tran_t *smp); extern int sas_hba_detach(dev_info_t *self); extern void sas_hba_tran_free(sas_hba_tran_t *smp); +extern int smp_hba_bus_config(dev_info_t *, char *, dev_info_t **); +extern int smp_hba_bus_config_taddr(dev_info_t *, char *); + + extern int sas_smp_transport(struct smp_pkt *pkt); extern int sas_ifgetcap(struct sas_addr *ap, char *cap); extern int sas_hba_probe_smp(struct smp_device *smp_devp); extern int sas_hba_lookup_capstr(char *capstr); +/* + * Phymap support + */ +typedef struct __sas_phymap sas_phymap_t; +typedef enum { PHYMAP_MODE_SIMPLE } sas_phymap_mode_t; +typedef void (*sas_phymap_activate_cb_t) + (void *phymap_priv, char *ua, void **ua_privp); +typedef void (*sas_phymap_deactivate_cb_t) + (void *phymap_priv, char *ua, void *ua_priv); + +extern int sas_phymap_create(dev_info_t *hba_dip, + clock_t settle_us, + sas_phymap_mode_t mode, + void *mode_argument, + void *phymap_priv, + sas_phymap_activate_cb_t activate_cb, + sas_phymap_deactivate_cb_t deactivate_cb, + sas_phymap_t **phymapp); + +void sas_phymap_destroy(sas_phymap_t *phymap); + +extern int sas_phymap_phy_add(sas_phymap_t *phymap, + int phy, + uint64_t local_sas_address, + uint64_t remote_sas_address); + +extern int sas_phymap_phy_rem(sas_phymap_t *phymap, + int phy); + +extern char *sas_phymap_lookup_ua(sas_phymap_t *phymap, + uint64_t local_sas_address, + uint64_t remote_sas_address); + +extern void *sas_phymap_lookup_uapriv(sas_phymap_t *phymap, + char *ua); + +extern int sas_phymap_uahasphys(sas_phymap_t *phymap, + char *ua); + +typedef struct __sas_phymap_phys sas_phymap_phys_t; +extern sas_phymap_phys_t *sas_phymap_ua2phys(sas_phymap_t *, char *ua); +extern int sas_phymap_phys_next(sas_phymap_phys_t *); +void sas_phymap_phys_free(sas_phymap_phys_t *); + +extern char *sas_phymap_phy2ua(sas_phymap_t *, int); +void sas_phymap_ua_free(char *); + + #endif /* defined(_KERNEL) */ +#define KSTAT_SAS_PHY_CLASS "SAS_phy_stat" + +/* + * Format of the ks_name field for SAS Phy Stat + * + * driver_name.initiator_port_SAS_address.initiator_port_instance_number.phyid + * Example: pmcs.5000c50000d756aa.2.0 + * + * driver_name: + * driver name from di_driver_name() on SAS initiator port devinfo node. + * initiator_port_SAS_address: + * SAS address of the initiator port that phy stat is reported for. + * initiator_port_instance_number: + * instance number of the initiator port that phy stat is reported for. + * phyid: + * prop phyIdentifier under initiator port node. + */ + +/* Port Protocol - kstat structure definition */ + +typedef struct sas_port_protocol_stats { + kstat_named_t seconds_since_last_reset; + kstat_named_t input_requests; + kstat_named_t output_requests; + kstat_named_t control_requests; + kstat_named_t input_megabytes; + kstat_named_t output_megabytes; +} sas_port_protocol_stats_t; + +/* Port - kstat structure definition */ + +typedef struct sas_port_stats { + kstat_named_t seconds_since_last_reset; + kstat_named_t tx_frames; + kstat_named_t tx_words; + kstat_named_t rx_frames; + kstat_named_t rx_words; +} sas_port_stats_t; + +/* PHY - kstat structure definition */ + +typedef struct sas_phy_stats { + kstat_named_t seconds_since_last_reset; + kstat_named_t tx_frames; + kstat_named_t tx_words; + kstat_named_t rx_frames; + kstat_named_t rx_words; + kstat_named_t invalid_dword_count; + kstat_named_t running_disparity_error_count; + kstat_named_t loss_of_dword_sync_count; + kstat_named_t phy_reset_problem_count; +} sas_phy_stats_t; + + +/* + * Supported Protocol property + */ +#define SAS_PROTOCOL_SSP 0x00000001 +#define SAS_PROTOCOL_STP 0x00000010 +#define SAS_PROTOCOL_SMP 0x00000100 +#define SAS_PROTOCOL_SATA 0x00001000 + + +/* + * Definition - Negotiated Physical Link Rate + * Based on Table 288 (Section 10.4.3.10) of the spec (SAS-2 r-15), these + * constants represent "Negotiated physical link rate" + * (and implicitly the State of the phy). + */ + +#define SAS_LINK_RATE_UNKNOWN 0x0 /* Phy is enabled. */ + /* Speed is unknown */ +#define SAS_LINK_RATE_DISABLED 0x1 /* Phy is disabled. */ + /* Speed is undefined */ +#define SAS_LINK_RATE_FAILED 0x2 /* Phy is enabled. */ + /* Failed speed negotiation. */ +#define SAS_LINK_RATE_SATASPINUP 0x3 /* Phy is enabled. */ + /* Detected a SATA device and */ + /* entered the SATA Spinup hold */ + /* state */ +#define SAS_LINK_RATE_SATAPORTSEL 0x4 /* Phy enabled. */ + /* The phy is attached to a */ + /* Port Selector (SATA-2.6). */ +#define SAS_LINK_RATE_RESET_IN_PROGRESS 0x5 /* Phy is enabled. */ + /* Expander is performing SMP */ + /* PHY CONTROL Link/Hard Reset */ +#define SAS_LINK_RATE_PHY_UNSUPPORTED 0x6 /* Phy is enabled. */ + /* Unsupported phy settings */ +#define SAS_LINK_RATE_RESERVED 0x7 /* Undefined. Reserved. */ +#define SAS_LINK_RATE_1_5GBIT 0x8 /* Phy enabled at 1.5 GBit/sec */ +#define SAS_LINK_RATE_3GBIT 0x9 /* Phy enabled at 3 GBit/sec */ +#define SAS_LINK_RATE_6GBIT 0xA /* Phy enabled at 6 GBit/sec. */ + + +/* + * Definition - "phy-info" property + * + * The property is an nvlist_array that represents an array of the + * nvlists on a per HBA basis. The individual elements of the array + * (the nvlists) represent the following properties for each phy of the HBA + */ +#define SAS_PHY_INFO "phy-info" /* Phy property name */ +#define SAS_PHY_INFO_NVL "phy-info-nvl" /* NVL array name */ + +#define SAS_PHY_ID "PhyIdentifier" /* DATA_TYPE_UINT8 */ +#define SAS_NEG_LINK_RATE "NegotiatedLinkRate" /* DATA_TYPE_INT8 */ +#define SAS_PROG_MIN_LINK_RATE "ProgrammedMinLinkRate" /* DATA_TYPE_INT8 */ +#define SAS_HW_MIN_LINK_RATE "HardwareMinLinkRate" /* DATA_TYPE_INT8 */ +#define SAS_PROG_MAX_LINK_RATE "ProgrammedMaxLinkRate" /* DATA_TYPE_INT8 */ +#define SAS_HW_MAX_LINK_RATE "HardwareMaxLinkRate" /* DATA_TYPE_INT8 */ + + +/* + * Event definitions + */ +/* Event Class */ +#define EC_HBA "EC_hba" + +/* Event Sub-Class */ +#define ESC_SAS_HBA_PORT_BROADCAST "ESC_sas_hba_port_broadcast" + +/* Event Types for above Subclass */ +#define SAS_PORT_BROADCAST_CHANGE "port_broadcast_change" +#define SAS_PORT_BROADCAST_SES "port_broadcast_ses" +#define SAS_PORT_BROADCAST_D24_0 "port_broadcast_d24_0" +#define SAS_PORT_BROADCAST_D27_4 "port_broadcast_d27_4" +#define SAS_PORT_BROADCAST_D01_4 "port_broadcast_d01_4" +#define SAS_PORT_BROADCAST_D04_7 "port_broadcast_d04_7" +#define SAS_PORT_BROADCAST_D16_7 "port_broadcast_d16_7" +#define SAS_PORT_BROADCAST_D29_7 "port_broadcast_d29_7" + +/* Event Sub-Class */ +#define ESC_SAS_PHY_EVENT "ESC_sas_phy_event" + +/* Event Types for above Subclass */ +#define SAS_PHY_ONLINE "port_online" +#define SAS_PHY_OFFLINE "port_offline" +#define SAS_PHY_REMOVE "port_remove" + +/* Event Payload Names */ +#define SAS_DRV_INST "driver_instance" +#define SAS_PORT_ADDR "port_address" +#define SAS_DEVFS_PATH "devfs_path" +#define SAS_EVENT_TYPE "event_type" +#define SAS_LINK_RATE "link_rate" +/* SAS_PHY_ID - Defined Above */ + + + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/scsi/impl/transport.h b/usr/src/uts/common/sys/scsi/impl/transport.h index 77820c9f43..7a7bb66590 100644 --- a/usr/src/uts/common/sys/scsi/impl/transport.h +++ b/usr/src/uts/common/sys/scsi/impl/transport.h @@ -39,6 +39,12 @@ extern "C" { #ifdef _KERNEL /* + * Opaque handles to address maps + */ +typedef struct __scsi_iportmap scsi_hba_iportmap_t; +typedef struct __scsi_tgtmap scsi_hba_tgtmap_t; + +/* * SCSI transport structures * * As each Host Adapter makes itself known to the system, @@ -54,7 +60,9 @@ typedef struct scsi_hba_tran scsi_hba_tran_t; struct scsi_hba_tran { /* - * Ptr to the device info structure for this particular HBA. + * Ptr to the device info structure for this particular HBA. If a SCSA + * HBA driver separates initiator port function from HBA function, + * this field still refers to the HBA and is used to manage DMA. */ dev_info_t *tran_hba_dip; @@ -64,8 +72,8 @@ struct scsi_hba_tran { void *tran_hba_private; /* HBA softstate */ /* - * The following two fields are only used in the SCSI_HBA_TRAN_CLONE - * case. Consider using SCSI_HBA_ADDR_COMPLEX instead. + * The following two fields are only used in the deprecated + * SCSI_HBA_TRAN_CLONE case. Use SCSI_HBA_ADDR_COMPLEX instead. */ void *tran_tgt_private; struct scsi_device *tran_sd; @@ -215,8 +223,7 @@ struct scsi_hba_tran { * open_flag: bit field indicating which minor nodes are open. * 0 = closed, 1 = shared open, all bits 1 = excl open. * - * XXX Unused if hba driver chooses to implement own - * xxopen(9e) entry point + * NOTE: Unused if HBA driver implements its own open(9e) entry point. */ kmutex_t tran_open_lock; uint64_t tran_open_flag; @@ -246,7 +253,7 @@ struct scsi_hba_tran { void *result); /* - * Inter-Connect type of trasnport as defined in + * Inter-Connect type of transport as defined in * usr/src/uts/common/sys/scsi/impl/services.h */ int tran_interconnect_type; @@ -286,6 +293,16 @@ struct scsi_hba_tran { */ dev_info_t *tran_iport_dip; + /* + * map of initiator ports below HBA + */ + scsi_hba_iportmap_t *tran_iportmap; + + /* + * map of targets below initiator + */ + scsi_hba_tgtmap_t *tran_tgtmap; + #ifdef SCSI_SIZE_CLEAN_VERIFY /* * Must be last: Building a driver with-and-without @@ -306,7 +323,7 @@ _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_hba_tran::tran_open_flag scsi_hba_tran::tran_pkt_cache_ptr)) /* - * we only modify the dma atributes (like dma_attr_granular) upon + * we only modify the dma attributes (like dma_attr_granular) upon * attach and in response to a setcap. It is also up to the target * driver to not have any outstanding I/Os when it is changing the * capabilities of the transport. @@ -373,7 +390,22 @@ int scsi_hba_probe( struct scsi_device *sd, int (*callback)(void)); -char *scsi_get_device_type_string( +int scsi_hba_probe_pi( + struct scsi_device *sd, + int (*callback)(void), + int pi); + +int scsi_hba_ua_get_reportdev( + struct scsi_device *sd, + char *ba, + int len); + +int scsi_hba_ua_get( + struct scsi_device *sd, + char *ua, + int len); + +char *scsi_get_device_type_string( char *prop_name, dev_info_t *hba_dip, struct scsi_device *sd); @@ -443,8 +475,7 @@ void scsi_hba_nodename_compatible_free( char *nodename, char **compatible); - -int scsi_hba_prop_update_inqstring( +int scsi_device_prop_update_inqstring( struct scsi_device *sd, char *name, char *data, @@ -453,8 +484,12 @@ int scsi_hba_prop_update_inqstring( void scsi_hba_pkt_comp( struct scsi_pkt *pkt); +int scsi_device_identity( + struct scsi_device *sd, + int (*callback)(void)); + char *scsi_hba_iport_unit_address( - dev_info_t *self); + dev_info_t *dip); int scsi_hba_iport_register( dev_info_t *dip, @@ -466,6 +501,8 @@ int scsi_hba_iport_exist( dev_info_t *scsi_hba_iport_find( dev_info_t *pdip, char *portnm); + + /* * Flags for scsi_hba_attach * @@ -496,8 +533,8 @@ dev_info_t *scsi_hba_iport_find( * same driver. The driver can distinguish context * by calling scsi_hba_iport_unit_address(). * - * SCSI_HBA_TRAN_CLONE Consider using SCSI_HBA_ADDR_COMPLEX instead. - * SCSI_HBA_TRAN_CLONE is a KLUDGE to address + * ::SCSI_HBA_TRAN_CLONE Deprecated: use SCSI_HBA_ADDR_COMPLEX instead. + * SCSI_HBA_TRAN_CLONE was a KLUDGE to address * limitations of the scsi_address(9S) structure * via duplication of scsi_hba_tran(9S) and * use of tran_tgt_private. @@ -507,10 +544,10 @@ dev_info_t *scsi_hba_iport_find( #define SCSI_HBA_TRAN_PHCI 0x02 /* treat HBA as mpxio 'pHCI' */ #define SCSI_HBA_TRAN_CDB 0x04 /* allocate cdb */ #define SCSI_HBA_TRAN_SCB 0x08 /* allocate sense */ +#define SCSI_HBA_HBA 0x10 /* all HBA children are iports */ #define SCSI_HBA_ADDR_SPI 0x20 /* scsi_address in SPI form */ #define SCSI_HBA_ADDR_COMPLEX 0x40 /* scsi_address is COMPLEX */ -#define SCSI_HBA_HBA 0x80 /* all HBA children are iport */ /* upper bits used to record SCSA configuration state */ #define SCSI_HBA_SCSA_PHCI 0x10000 /* need mdi_phci_unregister */ @@ -526,8 +563,8 @@ dev_info_t *scsi_hba_iport_find( * Support extra flavors for SCSA children */ #define SCSA_FLAVOR_SCSI_DEVICE NDI_FLAVOR_VANILLA -#define SCSA_FLAVOR_IPORT 1 -#define SCSA_FLAVOR_SMP 2 +#define SCSA_FLAVOR_SMP 1 +#define SCSA_FLAVOR_IPORT 2 #define SCSA_NFLAVORS 3 /* @@ -536,6 +573,80 @@ dev_info_t *scsi_hba_iport_find( #define SCSI_HBA_MAX_IPORTS 32 /* + * SCSI iport map interfaces + */ +int scsi_hba_iportmap_create( + dev_info_t *hba_dip, + clock_t stable_ms, + int n_entries, + scsi_hba_iportmap_t **iportmapp); + +int scsi_hba_iportmap_iport_add( + scsi_hba_iportmap_t *iportmap, + char *iport_addr, + void *iport_priv); + +int scsi_hba_iportmap_iport_remove( + scsi_hba_iportmap_t *iportmap, + char *iport_addr); + +void scsi_hba_iportmap_destroy(scsi_hba_iportmap_t *iportmap); + +/* + * SCSI target map interfaces + */ +typedef enum { SCSI_TM_FULLSET = 0, SCSI_TM_PERADDR } scsi_tgtmap_mode_t; +typedef enum { + SCSI_TGT_SCSI_DEVICE = 0, SCSI_TGT_SMP_DEVICE, SCSI_TGT_NTYPES +} scsi_tgtmap_tgt_type_t; + +typedef void (*scsi_tgt_activate_cb_t)( + void *tgtmap_priv, + char *tgt_addr, + scsi_tgtmap_tgt_type_t tgt_type, + void **tgt_privp); +typedef void (*scsi_tgt_deactivate_cb_t)( + void *tgtmap_priv, + char *tgt_addr, + scsi_tgtmap_tgt_type_t tgt_type, + void *tgt_priv); +int scsi_hba_tgtmap_create( + dev_info_t *iport_dip, + scsi_tgtmap_mode_t rpt_mode, + clock_t stable_ms, + int n_entries, + void *tgtmap_priv, + scsi_tgt_activate_cb_t activate_cb, + scsi_tgt_deactivate_cb_t deactivate_cb, + scsi_hba_tgtmap_t **tgtmapp); + +int scsi_hba_tgtmap_set_begin(scsi_hba_tgtmap_t *tgtmap); + +int scsi_hba_tgtmap_set_add( + scsi_hba_tgtmap_t *tgtmap, + scsi_tgtmap_tgt_type_t tgt_type, + char *tgt_addr, + void *tgt_priv); + +int scsi_hba_tgtmap_set_end( + scsi_hba_tgtmap_t *tgtmap, + uint_t flags); + +int scsi_hba_tgtmap_tgt_add( + scsi_hba_tgtmap_t *tgtmap, + scsi_tgtmap_tgt_type_t tgt_type, + char *tgt_addr, + void *tgt_priv); + +int scsi_hba_tgtmap_tgt_remove( + scsi_hba_tgtmap_t *tgtmap, + scsi_tgtmap_tgt_type_t tgt_type, + char *tgt_addr); + +void scsi_hba_tgtmap_destroy(scsi_hba_tgtmap_t *tgt_map); + + +/* * For minor nodes created by the SCSA framework, minor numbers are * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a * number less than 64. diff --git a/usr/src/uts/common/sys/scsi/scsi_address.h b/usr/src/uts/common/sys/scsi/scsi_address.h index ec70e72b78..36b5543dff 100644 --- a/usr/src/uts/common/sys/scsi/scsi_address.h +++ b/usr/src/uts/common/sys/scsi/scsi_address.h @@ -114,6 +114,10 @@ struct scsi_address { #define SCSI_ADDR_PROP_LUN64 "lun64" /* int64 */ #define SCSI_ADDR_PROP_SFUNC "sfunc" /* int */ +#define SCSI_ADDR_PROP_IPORTUA "scsi-iport" /* string */ + +#define SCSI_ADDR_PROP_SATA_PHY "sata-phy" /* int */ + /* * Addressing property names, values are in string form compatible * with the SCSI_ADDR_PROP_TARGET_PORT part of the related @@ -165,6 +169,7 @@ int scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp); char *scsi_wwn_to_wwnstr(uint64_t wwn, int unit_address_form, char *wwnstr); void scsi_wwnstr_hexcase(char *wwnstr, int lower_case); +const char *scsi_wwnstr_skip_ua_prefix(const char *wwnstr); void scsi_free_wwnstr(char *wwnstr); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/scsi/scsi_ctl.h b/usr/src/uts/common/sys/scsi/scsi_ctl.h index 0498c30d7c..32b6f54029 100644 --- a/usr/src/uts/common/sys/scsi/scsi_ctl.h +++ b/usr/src/uts/common/sys/scsi/scsi_ctl.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_SCSI_CTL_H #define _SYS_SCSI_SCSI_CTL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/scsi/scsi_types.h> #ifdef __cplusplus @@ -56,12 +53,6 @@ extern "C" { #define SCSI_RESET_CANCEL 0x02 /* cancel the reset notification */ /* - * Define for scsi_get_bus_addr/scsi_get_name first argument. - */ -#define SCSI_GET_INITIATOR_ID ((struct scsi_device *)NULL) - /* return initiator-id */ - -/* * Define for scsi_get_name string length. * This is needed because MAXNAMELEN is not part of DDI. */ @@ -98,9 +89,8 @@ int scsi_terminate_task(struct scsi_address *ap, struct scsi_pkt *pkt); * Other functions */ int scsi_clear_aca(struct scsi_address *ap); -int scsi_get_bus_addr(struct scsi_device *devp, char *name, int len); -int scsi_get_name(struct scsi_device *devp, char *name, int len); - +int scsi_ua_get_reportdev(struct scsi_device *sd, char *ba, int len); +int scsi_ua_get(struct scsi_device *sd, char *ua, int len); #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/scsi/scsi_pkt.h b/usr/src/uts/common/sys/scsi/scsi_pkt.h index f7890fc548..88f1b98602 100644 --- a/usr/src/uts/common/sys/scsi/scsi_pkt.h +++ b/usr/src/uts/common/sys/scsi/scsi_pkt.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_SCSI_PKT_H #define _SYS_SCSI_SCSI_PKT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/scsi/scsi_types.h> #ifdef __cplusplus @@ -106,6 +104,9 @@ struct scsi_pkt { /* private: iff scsi_pkt_allocated_correctly() */ int pkt_path_instance; /* pHCI transport path */ + /* stage-temporary: iff scsi_pkt_allocated_correctly() */ + void *pkt_stmp; /* temporary for current pkt stage */ + #ifdef SCSI_SIZE_CLEAN_VERIFY /* * Must be last: Building a driver with-and-without diff --git a/usr/src/uts/common/sys/scsi/scsi_types.h b/usr/src/uts/common/sys/scsi/scsi_types.h index 82328afbd4..6aeb2bc0c5 100644 --- a/usr/src/uts/common/sys/scsi/scsi_types.h +++ b/usr/src/uts/common/sys/scsi/scsi_types.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -57,6 +57,11 @@ typedef void *opaque_t; #include <sys/cmn_err.h> #include <sys/debug.h> #include <sys/devops.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/stat.h> +#include <sys/sunndi.h> +#include <sys/devctl.h> #endif /* _KERNEL */ /* @@ -87,22 +92,9 @@ typedef void *opaque_t; #include <sys/scsi/generic/message.h> #include <sys/scsi/generic/mode.h> - /* * Sun SCSI type definitions */ #include <sys/scsi/impl/types.h> -/* - * For drivers which do not include these - must be last - */ -#ifdef _KERNEL -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/stat.h> -#include <sys/sunndi.h> -#include <sys/devctl.h> -#include <sys/ddifm.h> -#endif /* _KERNEL */ - #endif /* _SYS_SCSI_SCSI_TYPES_H */ diff --git a/usr/src/uts/common/sys/scsi/targets/smp.h b/usr/src/uts/common/sys/scsi/targets/smp.h index 9412662fd6..7ccfb7803f 100644 --- a/usr/src/uts/common/sys/scsi/targets/smp.h +++ b/usr/src/uts/common/sys/scsi/targets/smp.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_TARGETS_SMP_H #define _SYS_SCSI_TARGETS_SMP_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/scsi/scsi.h> @@ -47,17 +45,19 @@ extern "C" { #define SMP_EXOPENED 2 typedef struct smp_state { - struct smp_device *smp_dev; /* pointer to smp_device */ - kmutex_t smp_mutex; /* mutex */ - uint32_t smp_open_flag; /* open flag */ + struct smp_device *smp_dev; /* pointer to smp_device */ + kmutex_t smp_mutex; /* mutex */ + uint32_t smp_open_flag; /* open flag */ + kcondvar_t smp_cv; /* condition variable */ + uint32_t smp_busy; /* busy */ } smp_state_t; #define SMP_ESTIMATED_NUM_DEVS 4 /* for soft-state allocation */ -#define SMP_DEFAULT_RETRY_TIMES 3 +#define SMP_DEFAULT_RETRY_TIMES 5 #define SMP_FLAG_REQBUF 0x1 #define SMP_FLAG_RSPBUF 0x2 -#define SMP_FLAG_XFER 0x4 +#define SMP_FLAG_XFER 0x4 #endif /* defined(_KERNEL) */ diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h index 5a390b4180..601601eaa6 100644 --- a/usr/src/uts/common/sys/sunddi.h +++ b/usr/src/uts/common/sys/sunddi.h @@ -116,6 +116,8 @@ extern "C" { #define DEVI_PSEUDO_NODEID ((int)-1) #define DEVI_SID_NODEID ((int)-2) #define DEVI_SID_HIDDEN_NODEID ((int)-3) +#define DEVI_SID_HP_NODEID ((int)-4) +#define DEVI_SID_HP_HIDDEN_NODEID ((int)-5) #define DEVI_PSEUDO_NEXNAME "pseudo" #define DEVI_ISA_NEXNAME "isa" @@ -1556,43 +1558,84 @@ int ddi_fls(long mask); /* - * The next five routines comprise generic storage management utilities - * for driver soft state structures. + * The ddi_soft_state* routines comprise generic storage management utilities + * for driver soft state structures. Two types of soft_state indexes are + * supported: 'integer index', and 'string index'. */ +typedef struct __ddi_soft_state_bystr ddi_soft_state_bystr; /* - * Allocate a set of pointers to 'n_items' objects of size 'size' - * bytes. Each pointer is initialized to nil. 'n_items' is a hint i.e. - * zero is allowed. + * Initialize a soft_state set, establishing the 'size' of soft state objects + * in the set. + * + * For an 'integer indexed' soft_state set, the initial set will accommodate + * 'n_items' objects - 'n_items' is a hint (i.e. zero is allowed), allocations + * that exceed 'n_items' have additional overhead. + * + * For a 'string indexed' soft_state set, 'n_items' should be the typical + * number of soft state objects in the set - 'n_items' is a hint, there may + * be additional overhead if the hint is too small (and wasted memory if the + * hint is too big). */ int ddi_soft_state_init(void **state_p, size_t size, size_t n_items); +int +ddi_soft_state_bystr_init(ddi_soft_state_bystr **state_p, + size_t size, int n_items); /* - * Allocate a state structure of size 'size' to be associated - * with item 'item'. + * Allocate a soft state object associated with either 'integer index' or + * 'string index' from a soft_state set. */ int ddi_soft_state_zalloc(void *state, int item); +int +ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr *state, const char *str); /* - * Fetch a pointer to the allocated soft state structure - * corresponding to 'item.' + * Get the pointer to the allocated soft state object associated with + * either 'integer index' or 'string index'. */ void * ddi_get_soft_state(void *state, int item); +void * +ddi_soft_state_bystr_get(ddi_soft_state_bystr *state, const char *str); /* - * Free the state structure corresponding to 'item.' + * Free the soft state object associated with either 'integer index' + * or 'string index'. */ void ddi_soft_state_free(void *state, int item); +void +ddi_soft_state_bystr_free(ddi_soft_state_bystr *state, const char *str); /* - * Free the handle, and any associated soft state structures. + * Free the soft state set and any associated soft state objects. */ void ddi_soft_state_fini(void **state_p); +void +ddi_soft_state_bystr_fini(ddi_soft_state_bystr **state_p); + +/* + * The ddi_strid_* routines provide string-to-index management utilities. + */ +typedef struct __ddi_strid ddi_strid; +int +ddi_strid_init(ddi_strid **strid_p, int n_items); +id_t +ddi_strid_alloc(ddi_strid *strid, char *str); +id_t +ddi_strid_fixed_alloc(ddi_strid *strid, char *str); +id_t +ddi_strid_str2id(ddi_strid *strid, char *str); +char * +ddi_strid_id2str(ddi_strid *strid, id_t id); +void +ddi_strid_free(ddi_strid *strid, id_t id); +void +ddi_strid_fini(ddi_strid **strid_p); /* * Set the addr field of the name in dip to name diff --git a/usr/src/uts/common/sys/sunmdi.h b/usr/src/uts/common/sys/sunmdi.h index 4aa687efa8..a670d0b2b8 100644 --- a/usr/src/uts/common/sys/sunmdi.h +++ b/usr/src/uts/common/sys/sunmdi.h @@ -87,7 +87,11 @@ typedef enum { #define MDI_COMPONENT_CLIENT 0x4 /* - * mdi_pathinfo node state utility definitions + * mdi_pathinfo node state utility definitions (bits in mdi_pathinfo_state_t) + * + * NOTE: having mdi_pathinfo_state_t contain both state and flags is error + * prone. For new flags, please consider using MDI_PATHINFO_FLAG_ (and + * moving existing EXT_STATE_MASK flags over would be good too). */ #define MDI_PATHINFO_STATE_TRANSIENT 0x00010000 #define MDI_PATHINFO_STATE_USER_DISABLE 0x00100000 @@ -96,6 +100,12 @@ typedef enum { #define MDI_PATHINFO_STATE_MASK 0x0000FFFF #define MDI_PATHINFO_EXT_STATE_MASK 0xFFF00000 +/* + * mdi_pathinfo flags definitions + */ +#define MDI_PATHINFO_FLAGS_HIDDEN 0x00000001 +#define MDI_PATHINFO_FLAGS_DEVICE_REMOVED 0x00000002 + #define USER_DISABLE 1 #define DRIVER_DISABLE 2 #define DRIVER_DISABLE_TRANSIENT 3 @@ -191,6 +201,12 @@ int mdi_pi_enable(dev_info_t *, dev_info_t *, int); int mdi_pi_disable_path(mdi_pathinfo_t *, int); int mdi_pi_enable_path(mdi_pathinfo_t *, int); +int mdi_pi_ishidden(mdi_pathinfo_t *); + +int mdi_pi_device_isremoved(mdi_pathinfo_t *); +int mdi_pi_device_remove(mdi_pathinfo_t *); +int mdi_pi_device_insert(mdi_pathinfo_t *); + /* * MPxIO-PM stuff */ @@ -228,11 +244,14 @@ dev_info_t *mdi_pi_get_phci(mdi_pathinfo_t *); char *mdi_pi_get_node_name(mdi_pathinfo_t *); char *mdi_pi_get_addr(mdi_pathinfo_t *); mdi_pathinfo_state_t mdi_pi_get_state(mdi_pathinfo_t *); +uint_t mdi_pi_get_flags(mdi_pathinfo_t *); int mdi_pi_get_path_instance(mdi_pathinfo_t *); -char *mdi_pi_pathname_by_instance(int path_instance); +char *mdi_pi_pathname_by_instance(int); char *mdi_pi_pathname(mdi_pathinfo_t *); char *mdi_pi_pathname_obp(mdi_pathinfo_t *, char *); int mdi_pi_pathname_obp_set(mdi_pathinfo_t *, char *); +char *mdi_pi_spathname_by_instance(int); +char *mdi_pi_spathname(mdi_pathinfo_t *); /* * mdi_pathinfo Property handling functions diff --git a/usr/src/uts/common/sys/sunndi.h b/usr/src/uts/common/sys/sunndi.h index 80bbdca329..22e61db408 100644 --- a/usr/src/uts/common/sys/sunndi.h +++ b/usr/src/uts/common/sys/sunndi.h @@ -318,6 +318,7 @@ ndi_irm_destroy(ddi_irm_pool_t *poolp); #define NDI_DRV_CONF_REPROBE 0x04000000 /* reprobe conf-enum'd nodes only */ #define NDI_DETACH_DRIVER 0x08000000 /* performing driver_detach */ #define NDI_MTC_OFF 0x10000000 /* disable multi-threading */ +#define NDI_USER_REQ 0x20000000 /* user requested operation */ /* ndi interface flag values */ #define NDI_SLEEP 0x000000 @@ -342,6 +343,26 @@ dev_info_t * ndi_devi_findchild(dev_info_t *p, char *devname); /* + * Find the child dev_info node of parent nexus 'p' whose name + * matches "dname"@"ua". If a child doesn't have a "ua" + * value, it calls the function "make_ua" to create it. + */ +dev_info_t * +ndi_devi_findchild_by_callback(dev_info_t *p, char *dname, char *ua, + int (*make_ua)(dev_info_t *, char *, int)); + +/* + * Maintain DEVI_DEVICE_REMOVED hotplug devi_state for remove/reinsert hotplug + * of open devices. + */ +int +ndi_devi_device_isremoved(dev_info_t *dip); +int +ndi_devi_device_remove(dev_info_t *dip); +int +ndi_devi_device_insert(dev_info_t *dip); + +/* * generate debug msg via NDI_DEVI_DEBUG flag */ #define NDI_DEBUG(flags, args) \ @@ -462,10 +483,10 @@ typedef struct ndi_event_definition { } ndi_event_definition_t; typedef struct ndi_event_cookie { - ndi_event_definition_t *definition; /* Event Description */ + ndi_event_definition_t *definition; /* Event Description */ dev_info_t *ddip; /* Devi defining this event */ ndi_event_callbacks_t *callback_list; /* Cb's reg'd to w/ this evt */ - struct ndi_event_cookie *next_cookie; /* Next cookie def'd in hdl */ + struct ndi_event_cookie *next_cookie; /* Next cookie def'd in hdl */ } ndi_event_cookie_t; @@ -522,7 +543,7 @@ ndi_event_unbind_set(ndi_event_hdl_t handle, * get an event cookie */ int -ndi_event_retrieve_cookie(ndi_event_hdl_t handle, +ndi_event_retrieve_cookie(ndi_event_hdl_t handle, dev_info_t *child_dip, char *eventname, ddi_eventcookie_t *cookiep, @@ -532,7 +553,7 @@ ndi_event_retrieve_cookie(ndi_event_hdl_t handle, * add an event callback info to the ndi event handle */ int -ndi_event_add_callback(ndi_event_hdl_t handle, +ndi_event_add_callback(ndi_event_hdl_t handle, dev_info_t *child_dip, ddi_eventcookie_t cookie, void (*event_callback) @@ -591,7 +612,7 @@ ndi_event_cookie_to_name(ndi_event_hdl_t handle, * name given an event_tag */ char * -ndi_event_tag_to_name(ndi_event_hdl_t handle, int event_tag); +ndi_event_tag_to_name(ndi_event_hdl_t handle, int event_tag); dev_info_t * ndi_devi_config_vhci(char *, int); @@ -635,9 +656,9 @@ typedef struct ndi_ra_request { /* restricted to */ uint64_t ra_boundlen; /* Length of the area, starting */ - /* from ra_boundbase, for the */ + /* from ra_boundbase, for the */ /* allocated resource to be */ - /* restricted to. */ + /* restricted to. */ uint64_t ra_align_mask; /* Alignment mask used for */ /* allocated base address */ @@ -728,6 +749,11 @@ int ndi_dev_is_pseudo_node(dev_info_t *); int ndi_dev_is_persistent_node(dev_info_t *); /* + * ndi_dev_is_hotplug_node: Return non-zero if the node was created by hotplug. + */ +int ndi_dev_is_hotplug_node(dev_info_t *); + +/* * ndi_dev_is_hidden_node: Return non-zero if the node is hidden. */ int ndi_dev_is_hidden_node(dev_info_t *); @@ -761,8 +787,8 @@ void ndi_set_dma_fault(ddi_dma_handle_t dh); void ndi_clr_dma_fault(ddi_dma_handle_t dh); /* Driver.conf property merging */ -int ndi_merge_node(dev_info_t *, int (*)(dev_info_t *, char *, int)); -void ndi_merge_wildcard_node(dev_info_t *); +int ndi_merge_node(dev_info_t *, int (*)(dev_info_t *, char *, int)); +void ndi_merge_wildcard_node(dev_info_t *); /* * Ndi 'flavor' support: These interfaces are to support a nexus driver diff --git a/usr/src/uts/common/sys/systm.h b/usr/src/uts/common/sys/systm.h index 5963460441..4e529b9cce 100644 --- a/usr/src/uts/common/sys/systm.h +++ b/usr/src/uts/common/sys/systm.h @@ -175,6 +175,7 @@ hrtime_t untimeout_generic(callout_id_t, int); clock_t untimeout_default(callout_id_t, int); void delay(clock_t); int delay_sig(clock_t); +void delay_random(clock_t); int nodev(); int nulldev(); major_t getudev(void); |
