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