162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci=========
462306a36Sopenharmony_ciSAS Layer
562306a36Sopenharmony_ci=========
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciThe SAS Layer is a management infrastructure which manages
862306a36Sopenharmony_ciSAS LLDDs.  It sits between SCSI Core and SAS LLDDs.  The
962306a36Sopenharmony_cilayout is as follows: while SCSI Core is concerned with
1062306a36Sopenharmony_ciSAM/SPC issues, and a SAS LLDD+sequencer is concerned with
1162306a36Sopenharmony_ciphy/OOB/link management, the SAS layer is concerned with:
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci      * SAS Phy/Port/HA event management (LLDD generates,
1462306a36Sopenharmony_ci        SAS Layer processes),
1562306a36Sopenharmony_ci      * SAS Port management (creation/destruction),
1662306a36Sopenharmony_ci      * SAS Domain discovery and revalidation,
1762306a36Sopenharmony_ci      * SAS Domain device management,
1862306a36Sopenharmony_ci      * SCSI Host registration/unregistration,
1962306a36Sopenharmony_ci      * Device registration with SCSI Core (SAS) or libata
2062306a36Sopenharmony_ci        (SATA), and
2162306a36Sopenharmony_ci      * Expander management and exporting expander control
2262306a36Sopenharmony_ci        to user space.
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciA SAS LLDD is a PCI device driver.  It is concerned with
2562306a36Sopenharmony_ciphy/OOB management, and vendor specific tasks and generates
2662306a36Sopenharmony_cievents to the SAS layer.
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciThe SAS Layer does most SAS tasks as outlined in the SAS 1.1
2962306a36Sopenharmony_cispec.
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciThe sas_ha_struct describes the SAS LLDD to the SAS layer.
3262306a36Sopenharmony_ciMost of it is used by the SAS Layer but a few fields need to
3362306a36Sopenharmony_cibe initialized by the LLDDs.
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciAfter initializing your hardware, from the probe() function
3662306a36Sopenharmony_ciyou call sas_register_ha(). It will register your LLDD with
3762306a36Sopenharmony_cithe SCSI subsystem, creating a SCSI host and it will
3862306a36Sopenharmony_ciregister your SAS driver with the sysfs SAS tree it creates.
3962306a36Sopenharmony_ciIt will then return.  Then you enable your phys to actually
4062306a36Sopenharmony_cistart OOB (at which point your driver will start calling the
4162306a36Sopenharmony_cinotify_* event callbacks).
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciStructure descriptions
4462306a36Sopenharmony_ci======================
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci``struct sas_phy``
4762306a36Sopenharmony_ci------------------
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciNormally this is statically embedded to your driver's
5062306a36Sopenharmony_ciphy structure::
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci    struct my_phy {
5362306a36Sopenharmony_ci	    blah;
5462306a36Sopenharmony_ci	    struct sas_phy sas_phy;
5562306a36Sopenharmony_ci	    bleh;
5662306a36Sopenharmony_ci    };
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciAnd then all the phys are an array of my_phy in your HA
5962306a36Sopenharmony_cistruct (shown below).
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciThen as you go along and initialize your phys you also
6262306a36Sopenharmony_ciinitialize the sas_phy struct, along with your own
6362306a36Sopenharmony_ciphy structure.
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciIn general, the phys are managed by the LLDD and the ports
6662306a36Sopenharmony_ciare managed by the SAS layer.  So the phys are initialized
6762306a36Sopenharmony_ciand updated by the LLDD and the ports are initialized and
6862306a36Sopenharmony_ciupdated by the SAS layer.
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciThere is a scheme where the LLDD can RW certain fields,
7162306a36Sopenharmony_ciand the SAS layer can only read such ones, and vice versa.
7262306a36Sopenharmony_ciThe idea is to avoid unnecessary locking.
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cienabled
7562306a36Sopenharmony_ci    - must be set (0/1)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciid
7862306a36Sopenharmony_ci    - must be set [0,MAX_PHYS)]
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciclass, proto, type, role, oob_mode, linkrate
8162306a36Sopenharmony_ci    - must be set
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cioob_mode
8462306a36Sopenharmony_ci    - you set this when OOB has finished and then notify
8562306a36Sopenharmony_ci      the SAS Layer.
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cisas_addr
8862306a36Sopenharmony_ci    - this normally points to an array holding the sas
8962306a36Sopenharmony_ci      address of the phy, possibly somewhere in your my_phy
9062306a36Sopenharmony_ci      struct.
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciattached_sas_addr
9362306a36Sopenharmony_ci    - set this when you (LLDD) receive an
9462306a36Sopenharmony_ci      IDENTIFY frame or a FIS frame, _before_ notifying the SAS
9562306a36Sopenharmony_ci      layer.  The idea is that sometimes the LLDD may want to fake
9662306a36Sopenharmony_ci      or provide a different SAS address on that phy/port and this
9762306a36Sopenharmony_ci      allows it to do this.  At best you should copy the sas
9862306a36Sopenharmony_ci      address from the IDENTIFY frame or maybe generate a SAS
9962306a36Sopenharmony_ci      address for SATA directly attached devices.  The Discover
10062306a36Sopenharmony_ci      process may later change this.
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciframe_rcvd
10362306a36Sopenharmony_ci    - this is where you copy the IDENTIFY/FIS frame
10462306a36Sopenharmony_ci      when you get it; you lock, copy, set frame_rcvd_size and
10562306a36Sopenharmony_ci      unlock the lock, and then call the event.  It is a pointer
10662306a36Sopenharmony_ci      since there's no way to know your hw frame size _exactly_,
10762306a36Sopenharmony_ci      so you define the actual array in your phy struct and let
10862306a36Sopenharmony_ci      this pointer point to it.  You copy the frame from your
10962306a36Sopenharmony_ci      DMAable memory to that area holding the lock.
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cisas_prim
11262306a36Sopenharmony_ci    - this is where primitives go when they're
11362306a36Sopenharmony_ci      received.  See sas.h. Grab the lock, set the primitive,
11462306a36Sopenharmony_ci      release the lock, notify.
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciport
11762306a36Sopenharmony_ci    - this points to the sas_port if the phy belongs
11862306a36Sopenharmony_ci      to a port -- the LLDD only reads this. It points to the
11962306a36Sopenharmony_ci      sas_port this phy is part of.  Set by the SAS Layer.
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciha
12262306a36Sopenharmony_ci    - may be set; the SAS layer sets it anyway.
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cilldd_phy
12562306a36Sopenharmony_ci    - you should set this to point to your phy so you
12662306a36Sopenharmony_ci      can find your way around faster when the SAS layer calls one
12762306a36Sopenharmony_ci      of your callbacks and passes you a phy.  If the sas_phy is
12862306a36Sopenharmony_ci      embedded you can also use container_of -- whatever you
12962306a36Sopenharmony_ci      prefer.
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci``struct sas_port``
13362306a36Sopenharmony_ci-------------------
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciThe LLDD doesn't set any fields of this struct -- it only
13662306a36Sopenharmony_cireads them.  They should be self explanatory.
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciphy_mask is 32 bit, this should be enough for now, as I
13962306a36Sopenharmony_cihaven't heard of a HA having more than 8 phys.
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cilldd_port
14262306a36Sopenharmony_ci    - I haven't found use for that -- maybe other
14362306a36Sopenharmony_ci      LLDD who wish to have internal port representation can make
14462306a36Sopenharmony_ci      use of this.
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci``struct sas_ha_struct``
14762306a36Sopenharmony_ci------------------------
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciIt normally is statically declared in your own LLDD
15062306a36Sopenharmony_cistructure describing your adapter::
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci    struct my_sas_ha {
15362306a36Sopenharmony_ci	blah;
15462306a36Sopenharmony_ci	struct sas_ha_struct sas_ha;
15562306a36Sopenharmony_ci	struct my_phy phys[MAX_PHYS];
15662306a36Sopenharmony_ci	struct sas_port sas_ports[MAX_PHYS]; /* (1) */
15762306a36Sopenharmony_ci	bleh;
15862306a36Sopenharmony_ci    };
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci    (1) If your LLDD doesn't have its own port representation.
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciWhat needs to be initialized (sample function given below).
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cipcidev
16562306a36Sopenharmony_ci^^^^^^
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cisas_addr
16862306a36Sopenharmony_ci       - since the SAS layer doesn't want to mess with
16962306a36Sopenharmony_ci	 memory allocation, etc, this points to statically
17062306a36Sopenharmony_ci	 allocated array somewhere (say in your host adapter
17162306a36Sopenharmony_ci	 structure) and holds the SAS address of the host
17262306a36Sopenharmony_ci	 adapter as given by you or the manufacturer, etc.
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cisas_port
17562306a36Sopenharmony_ci^^^^^^^^
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cisas_phy
17862306a36Sopenharmony_ci      - an array of pointers to structures. (see
17962306a36Sopenharmony_ci	note above on sas_addr).
18062306a36Sopenharmony_ci	These must be set.  See more notes below.
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cinum_phys
18362306a36Sopenharmony_ci       - the number of phys present in the sas_phy array,
18462306a36Sopenharmony_ci	 and the number of ports present in the sas_port
18562306a36Sopenharmony_ci	 array.  There can be a maximum num_phys ports (one per
18662306a36Sopenharmony_ci	 port) so we drop the num_ports, and only use
18762306a36Sopenharmony_ci	 num_phys.
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciThe event interface::
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* LLDD calls these to notify the class of an event. */
19262306a36Sopenharmony_ci	void sas_notify_port_event(struct sas_phy *, enum port_event, gfp_t);
19362306a36Sopenharmony_ci	void sas_notify_phy_event(struct sas_phy *, enum phy_event, gfp_t);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ciThe port notification::
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* The class calls these to notify the LLDD of an event. */
19862306a36Sopenharmony_ci	void (*lldd_port_formed)(struct sas_phy *);
19962306a36Sopenharmony_ci	void (*lldd_port_deformed)(struct sas_phy *);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciIf the LLDD wants notification when a port has been formed
20262306a36Sopenharmony_cior deformed it sets those to a function satisfying the type.
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciA SAS LLDD should also implement at least one of the Task
20562306a36Sopenharmony_ciManagement Functions (TMFs) described in SAM::
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Task Management Functions. Must be called from process context. */
20862306a36Sopenharmony_ci	int (*lldd_abort_task)(struct sas_task *);
20962306a36Sopenharmony_ci	int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
21062306a36Sopenharmony_ci	int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
21162306a36Sopenharmony_ci	int (*lldd_I_T_nexus_reset)(struct domain_device *);
21262306a36Sopenharmony_ci	int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
21362306a36Sopenharmony_ci	int (*lldd_query_task)(struct sas_task *);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciFor more information please read SAM from T10.org.
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ciPort and Adapter management::
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Port and Adapter management */
22062306a36Sopenharmony_ci	int (*lldd_clear_nexus_port)(struct sas_port *);
22162306a36Sopenharmony_ci	int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciA SAS LLDD should implement at least one of those.
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciPhy management::
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* Phy management */
22862306a36Sopenharmony_ci	int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cilldd_ha
23162306a36Sopenharmony_ci    - set this to point to your HA struct. You can also
23262306a36Sopenharmony_ci      use container_of if you embedded it as shown above.
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciA sample initialization and registration function
23562306a36Sopenharmony_cican look like this (called last thing from probe())
23662306a36Sopenharmony_ci*but* before you enable the phys to do OOB::
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci    static int register_sas_ha(struct my_sas_ha *my_ha)
23962306a36Sopenharmony_ci    {
24062306a36Sopenharmony_ci	    int i;
24162306a36Sopenharmony_ci	    static struct sas_phy   *sas_phys[MAX_PHYS];
24262306a36Sopenharmony_ci	    static struct sas_port  *sas_ports[MAX_PHYS];
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	    my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	    for (i = 0; i < MAX_PHYS; i++) {
24762306a36Sopenharmony_ci		    sas_phys[i] = &my_ha->phys[i].sas_phy;
24862306a36Sopenharmony_ci		    sas_ports[i] = &my_ha->sas_ports[i];
24962306a36Sopenharmony_ci	    }
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	    my_ha->sas_ha.sas_phy  = sas_phys;
25262306a36Sopenharmony_ci	    my_ha->sas_ha.sas_port = sas_ports;
25362306a36Sopenharmony_ci	    my_ha->sas_ha.num_phys = MAX_PHYS;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_port_formed = my_port_formed;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_dev_found = my_dev_found;
25862306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_execute_task = my_execute_task;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_abort_task     = my_abort_task;
26362306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
26462306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
26562306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
26662306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_lu_reset       = my_lu_reset;
26762306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_query_task     = my_query_task;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
27062306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	    my_ha->sas_ha.lldd_control_phy = my_control_phy;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	    return sas_register_ha(&my_ha->sas_ha);
27562306a36Sopenharmony_ci    }
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci(2) SAS 1.1 does not define I_T Nexus Reset TMF.
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciEvents
28062306a36Sopenharmony_ci======
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ciEvents are **the only way** a SAS LLDD notifies the SAS layer
28362306a36Sopenharmony_ciof anything.  There is no other method or way a LLDD to tell
28462306a36Sopenharmony_cithe SAS layer of anything happening internally or in the SAS
28562306a36Sopenharmony_cidomain.
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciPhy events::
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	PHYE_LOSS_OF_SIGNAL, (C)
29062306a36Sopenharmony_ci	PHYE_OOB_DONE,
29162306a36Sopenharmony_ci	PHYE_OOB_ERROR,      (C)
29262306a36Sopenharmony_ci	PHYE_SPINUP_HOLD.
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciPort events, passed on a _phy_::
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	PORTE_BYTES_DMAED,      (M)
29762306a36Sopenharmony_ci	PORTE_BROADCAST_RCVD,   (E)
29862306a36Sopenharmony_ci	PORTE_LINK_RESET_ERR,   (C)
29962306a36Sopenharmony_ci	PORTE_TIMER_EVENT,      (C)
30062306a36Sopenharmony_ci	PORTE_HARD_RESET.
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ciHost Adapter event:
30362306a36Sopenharmony_ci	HAE_RESET
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ciA SAS LLDD should be able to generate
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	- at least one event from group C (choice),
30862306a36Sopenharmony_ci	- events marked M (mandatory) are mandatory (only one),
30962306a36Sopenharmony_ci	- events marked E (expander) if it wants the SAS layer
31062306a36Sopenharmony_ci	  to handle domain revalidation (only one such).
31162306a36Sopenharmony_ci	- Unmarked events are optional.
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciMeaning:
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciHAE_RESET
31662306a36Sopenharmony_ci    - when your HA got internal error and was reset.
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ciPORTE_BYTES_DMAED
31962306a36Sopenharmony_ci    - on receiving an IDENTIFY/FIS frame
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciPORTE_BROADCAST_RCVD
32262306a36Sopenharmony_ci    - on receiving a primitive
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ciPORTE_LINK_RESET_ERR
32562306a36Sopenharmony_ci    - timer expired, loss of signal, loss of DWS, etc. [1]_
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciPORTE_TIMER_EVENT
32862306a36Sopenharmony_ci    - DWS reset timeout timer expired [1]_
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciPORTE_HARD_RESET
33162306a36Sopenharmony_ci    - Hard Reset primitive received.
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciPHYE_LOSS_OF_SIGNAL
33462306a36Sopenharmony_ci    - the device is gone [1]_
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciPHYE_OOB_DONE
33762306a36Sopenharmony_ci    - OOB went fine and oob_mode is valid
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciPHYE_OOB_ERROR
34062306a36Sopenharmony_ci    - Error while doing OOB, the device probably
34162306a36Sopenharmony_ci      got disconnected. [1]_
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciPHYE_SPINUP_HOLD
34462306a36Sopenharmony_ci    - SATA is present, COMWAKE not sent.
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci.. [1] should set/clear the appropriate fields in the phy,
34762306a36Sopenharmony_ci       or alternatively call the inlined sas_phy_disconnected()
34862306a36Sopenharmony_ci       which is just a helper, from their tasklet.
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciThe Execute Command SCSI RPC::
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ciUsed to queue a task to the SAS LLDD.  @task is the task to be executed.
35562306a36Sopenharmony_ci@gfp_mask is the gfp_mask defining the context of the caller.
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciThis function should implement the Execute Command SCSI RPC,
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciThat is, when lldd_execute_task() is called, the command
36062306a36Sopenharmony_cigo out on the transport *immediately*.  There is *no*
36162306a36Sopenharmony_ciqueuing of any sort and at any level in a SAS LLDD.
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ciReturns:
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci   * -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
36662306a36Sopenharmony_ci   * 0, the task(s) were queued.
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci::
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci    struct sas_task {
37162306a36Sopenharmony_ci	    dev -- the device this task is destined to
37262306a36Sopenharmony_ci	    task_proto -- _one_ of enum sas_proto
37362306a36Sopenharmony_ci	    scatter -- pointer to scatter gather list array
37462306a36Sopenharmony_ci	    num_scatter -- number of elements in scatter
37562306a36Sopenharmony_ci	    total_xfer_len -- total number of bytes expected to be transferred
37662306a36Sopenharmony_ci	    data_dir -- PCI_DMA_...
37762306a36Sopenharmony_ci	    task_done -- callback when the task has finished execution
37862306a36Sopenharmony_ci    };
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciDiscovery
38162306a36Sopenharmony_ci=========
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciThe sysfs tree has the following purposes:
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci    a) It shows you the physical layout of the SAS domain at
38662306a36Sopenharmony_ci       the current time, i.e. how the domain looks in the
38762306a36Sopenharmony_ci       physical world right now.
38862306a36Sopenharmony_ci    b) Shows some device parameters _at_discovery_time_.
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciThis is a link to the tree(1) program, very useful in
39162306a36Sopenharmony_civiewing the SAS domain:
39262306a36Sopenharmony_ciftp://mama.indstate.edu/linux/tree/
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciI expect user space applications to actually create a
39562306a36Sopenharmony_cigraphical interface of this.
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciThat is, the sysfs domain tree doesn't show or keep state if
39862306a36Sopenharmony_ciyou e.g., change the meaning of the READY LED MEANING
39962306a36Sopenharmony_cisetting, but it does show you the current connection status
40062306a36Sopenharmony_ciof the domain device.
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ciKeeping internal device state changes is responsibility of
40362306a36Sopenharmony_ciupper layers (Command set drivers) and user space.
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ciWhen a device or devices are unplugged from the domain, this
40662306a36Sopenharmony_ciis reflected in the sysfs tree immediately, and the device(s)
40762306a36Sopenharmony_ciremoved from the system.
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ciThe structure domain_device describes any device in the SAS
41062306a36Sopenharmony_cidomain.  It is completely managed by the SAS layer.  A task
41162306a36Sopenharmony_cipoints to a domain device, this is how the SAS LLDD knows
41262306a36Sopenharmony_ciwhere to send the task(s) to.  A SAS LLDD only reads the
41362306a36Sopenharmony_cicontents of the domain_device structure, but it never creates
41462306a36Sopenharmony_cior destroys one.
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciExpander management from User Space
41762306a36Sopenharmony_ci===================================
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciIn each expander directory in sysfs, there is a file called
42062306a36Sopenharmony_ci"smp_portal".  It is a binary sysfs attribute file, which
42162306a36Sopenharmony_ciimplements an SMP portal (Note: this is *NOT* an SMP port),
42262306a36Sopenharmony_cito which user space applications can send SMP requests and
42362306a36Sopenharmony_cireceive SMP responses.
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciFunctionality is deceptively simple:
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci1. Build the SMP frame you want to send. The format and layout
42862306a36Sopenharmony_ci   is described in the SAS spec.  Leave the CRC field equal 0.
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ciopen(2)
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci2. Open the expander's SMP portal sysfs file in RW mode.
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ciwrite(2)
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci3. Write the frame you built in 1.
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciread(2)
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci4. Read the amount of data you expect to receive for the frame you built.
44162306a36Sopenharmony_ci   If you receive different amount of data you expected to receive,
44262306a36Sopenharmony_ci   then there was some kind of error.
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ciclose(2)
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciAll this process is shown in detail in the function do_smp_func()
44762306a36Sopenharmony_ciand its callers, in the file "expander_conf.c".
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ciThe kernel functionality is implemented in the file
45062306a36Sopenharmony_ci"sas_expander.c".
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciThe program "expander_conf.c" implements this. It takes one
45362306a36Sopenharmony_ciargument, the sysfs file name of the SMP portal to the
45462306a36Sopenharmony_ciexpander, and gives expander information, including routing
45562306a36Sopenharmony_citables.
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciThe SMP portal gives you complete control of the expander,
45862306a36Sopenharmony_ciso please be careful.
459