diff options
author | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2020-03-02 09:15:52 +0100 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2020-03-11 23:08:00 -0400 |
commit | a88dc3ec2ca48d23c7761af02e1ceea731f609e9 (patch) | |
tree | 64db97d10109df75302c7a3f8042fb5b095382f4 /Documentation/scsi/libsas.txt | |
parent | ac69461b6058dc8bc84b940665b84828575b0cc6 (diff) | |
download | linux-a88dc3ec2ca48d23c7761af02e1ceea731f609e9.tar.bz2 |
scsi: docs: convert libsas.txt to ReST
Link: https://lore.kernel.org/r/9022cb5551487f774cab16a828fe06b0b6b3add3.1583136624.git.mchehab+huawei@kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'Documentation/scsi/libsas.txt')
-rw-r--r-- | Documentation/scsi/libsas.txt | 395 |
1 files changed, 0 insertions, 395 deletions
diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt deleted file mode 100644 index 8cac6492aade..000000000000 --- a/Documentation/scsi/libsas.txt +++ /dev/null @@ -1,395 +0,0 @@ -SAS Layer ---------- - -The SAS Layer is a management infrastructure which manages -SAS LLDDs. It sits between SCSI Core and SAS LLDDs. The -layout is as follows: while SCSI Core is concerned with -SAM/SPC issues, and a SAS LLDD+sequencer is concerned with -phy/OOB/link management, the SAS layer is concerned with: - - * SAS Phy/Port/HA event management (LLDD generates, - SAS Layer processes), - * SAS Port management (creation/destruction), - * SAS Domain discovery and revalidation, - * SAS Domain device management, - * SCSI Host registration/unregistration, - * Device registration with SCSI Core (SAS) or libata - (SATA), and - * Expander management and exporting expander control - to user space. - -A SAS LLDD is a PCI device driver. It is concerned with -phy/OOB management, and vendor specific tasks and generates -events to the SAS layer. - -The SAS Layer does most SAS tasks as outlined in the SAS 1.1 -spec. - -The sas_ha_struct describes the SAS LLDD to the SAS layer. -Most of it is used by the SAS Layer but a few fields need to -be initialized by the LLDDs. - -After initializing your hardware, from the probe() function -you call sas_register_ha(). It will register your LLDD with -the SCSI subsystem, creating a SCSI host and it will -register your SAS driver with the sysfs SAS tree it creates. -It will then return. Then you enable your phys to actually -start OOB (at which point your driver will start calling the -notify_* event callbacks). - -Structure descriptions: - -struct sas_phy -------------------- -Normally this is statically embedded to your driver's -phy structure: - struct my_phy { - blah; - struct sas_phy sas_phy; - bleh; - }; -And then all the phys are an array of my_phy in your HA -struct (shown below). - -Then as you go along and initialize your phys you also -initialize the sas_phy struct, along with your own -phy structure. - -In general, the phys are managed by the LLDD and the ports -are managed by the SAS layer. So the phys are initialized -and updated by the LLDD and the ports are initialized and -updated by the SAS layer. - -There is a scheme where the LLDD can RW certain fields, -and the SAS layer can only read such ones, and vice versa. -The idea is to avoid unnecessary locking. - -enabled -- must be set (0/1) -id -- must be set [0,MAX_PHYS) -class, proto, type, role, oob_mode, linkrate -- must be set -oob_mode -- you set this when OOB has finished and then notify -the SAS Layer. - -sas_addr -- this normally points to an array holding the sas -address of the phy, possibly somewhere in your my_phy -struct. - -attached_sas_addr -- set this when you (LLDD) receive an -IDENTIFY frame or a FIS frame, _before_ notifying the SAS -layer. The idea is that sometimes the LLDD may want to fake -or provide a different SAS address on that phy/port and this -allows it to do this. At best you should copy the sas -address from the IDENTIFY frame or maybe generate a SAS -address for SATA directly attached devices. The Discover -process may later change this. - -frame_rcvd -- this is where you copy the IDENTIFY/FIS frame -when you get it; you lock, copy, set frame_rcvd_size and -unlock the lock, and then call the event. It is a pointer -since there's no way to know your hw frame size _exactly_, -so you define the actual array in your phy struct and let -this pointer point to it. You copy the frame from your -DMAable memory to that area holding the lock. - -sas_prim -- this is where primitives go when they're -received. See sas.h. Grab the lock, set the primitive, -release the lock, notify. - -port -- this points to the sas_port if the phy belongs -to a port -- the LLDD only reads this. It points to the -sas_port this phy is part of. Set by the SAS Layer. - -ha -- may be set; the SAS layer sets it anyway. - -lldd_phy -- you should set this to point to your phy so you -can find your way around faster when the SAS layer calls one -of your callbacks and passes you a phy. If the sas_phy is -embedded you can also use container_of -- whatever you -prefer. - - -struct sas_port -------------------- -The LLDD doesn't set any fields of this struct -- it only -reads them. They should be self explanatory. - -phy_mask is 32 bit, this should be enough for now, as I -haven't heard of a HA having more than 8 phys. - -lldd_port -- I haven't found use for that -- maybe other -LLDD who wish to have internal port representation can make -use of this. - - -struct sas_ha_struct -------------------- -It normally is statically declared in your own LLDD -structure describing your adapter: -struct my_sas_ha { - blah; - struct sas_ha_struct sas_ha; - struct my_phy phys[MAX_PHYS]; - struct sas_port sas_ports[MAX_PHYS]; /* (1) */ - bleh; -}; - -(1) If your LLDD doesn't have its own port representation. - -What needs to be initialized (sample function given below). - -pcidev -sas_addr -- since the SAS layer doesn't want to mess with - memory allocation, etc, this points to statically - allocated array somewhere (say in your host adapter - structure) and holds the SAS address of the host - adapter as given by you or the manufacturer, etc. -sas_port -sas_phy -- an array of pointers to structures. (see - note above on sas_addr). - These must be set. See more notes below. -num_phys -- the number of phys present in the sas_phy array, - and the number of ports present in the sas_port - array. There can be a maximum num_phys ports (one per - port) so we drop the num_ports, and only use - num_phys. - -The event interface: - - /* LLDD calls these to notify the class of an event. */ - void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event); - void (*notify_port_event)(struct sas_phy *, enum port_event); - void (*notify_phy_event)(struct sas_phy *, enum phy_event); - -When sas_register_ha() returns, those are set and can be -called by the LLDD to notify the SAS layer of such events -the SAS layer. - -The port notification: - - /* The class calls these to notify the LLDD of an event. */ - void (*lldd_port_formed)(struct sas_phy *); - void (*lldd_port_deformed)(struct sas_phy *); - -If the LLDD wants notification when a port has been formed -or deformed it sets those to a function satisfying the type. - -A SAS LLDD should also implement at least one of the Task -Management Functions (TMFs) described in SAM: - - /* Task Management Functions. Must be called from process context. */ - int (*lldd_abort_task)(struct sas_task *); - int (*lldd_abort_task_set)(struct domain_device *, u8 *lun); - int (*lldd_clear_aca)(struct domain_device *, u8 *lun); - int (*lldd_clear_task_set)(struct domain_device *, u8 *lun); - int (*lldd_I_T_nexus_reset)(struct domain_device *); - int (*lldd_lu_reset)(struct domain_device *, u8 *lun); - int (*lldd_query_task)(struct sas_task *); - -For more information please read SAM from T10.org. - -Port and Adapter management: - - /* Port and Adapter management */ - int (*lldd_clear_nexus_port)(struct sas_port *); - int (*lldd_clear_nexus_ha)(struct sas_ha_struct *); - -A SAS LLDD should implement at least one of those. - -Phy management: - - /* Phy management */ - int (*lldd_control_phy)(struct sas_phy *, enum phy_func); - -lldd_ha -- set this to point to your HA struct. You can also -use container_of if you embedded it as shown above. - -A sample initialization and registration function -can look like this (called last thing from probe()) -*but* before you enable the phys to do OOB: - -static int register_sas_ha(struct my_sas_ha *my_ha) -{ - int i; - static struct sas_phy *sas_phys[MAX_PHYS]; - static struct sas_port *sas_ports[MAX_PHYS]; - - my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0]; - - for (i = 0; i < MAX_PHYS; i++) { - sas_phys[i] = &my_ha->phys[i].sas_phy; - sas_ports[i] = &my_ha->sas_ports[i]; - } - - my_ha->sas_ha.sas_phy = sas_phys; - my_ha->sas_ha.sas_port = sas_ports; - my_ha->sas_ha.num_phys = MAX_PHYS; - - my_ha->sas_ha.lldd_port_formed = my_port_formed; - - my_ha->sas_ha.lldd_dev_found = my_dev_found; - my_ha->sas_ha.lldd_dev_gone = my_dev_gone; - - my_ha->sas_ha.lldd_execute_task = my_execute_task; - - my_ha->sas_ha.lldd_abort_task = my_abort_task; - my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set; - my_ha->sas_ha.lldd_clear_aca = my_clear_aca; - my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set; - my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2) - my_ha->sas_ha.lldd_lu_reset = my_lu_reset; - my_ha->sas_ha.lldd_query_task = my_query_task; - - my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port; - my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha; - - my_ha->sas_ha.lldd_control_phy = my_control_phy; - - return sas_register_ha(&my_ha->sas_ha); -} - -(2) SAS 1.1 does not define I_T Nexus Reset TMF. - -Events ------- - -Events are _the only way_ a SAS LLDD notifies the SAS layer -of anything. There is no other method or way a LLDD to tell -the SAS layer of anything happening internally or in the SAS -domain. - -Phy events: - PHYE_LOSS_OF_SIGNAL, (C) - PHYE_OOB_DONE, - PHYE_OOB_ERROR, (C) - PHYE_SPINUP_HOLD. - -Port events, passed on a _phy_: - PORTE_BYTES_DMAED, (M) - PORTE_BROADCAST_RCVD, (E) - PORTE_LINK_RESET_ERR, (C) - PORTE_TIMER_EVENT, (C) - PORTE_HARD_RESET. - -Host Adapter event: - HAE_RESET - -A SAS LLDD should be able to generate - - at least one event from group C (choice), - - events marked M (mandatory) are mandatory (only one), - - events marked E (expander) if it wants the SAS layer - to handle domain revalidation (only one such). - - Unmarked events are optional. - -Meaning: - -HAE_RESET -- when your HA got internal error and was reset. - -PORTE_BYTES_DMAED -- on receiving an IDENTIFY/FIS frame -PORTE_BROADCAST_RCVD -- on receiving a primitive -PORTE_LINK_RESET_ERR -- timer expired, loss of signal, loss -of DWS, etc. (*) -PORTE_TIMER_EVENT -- DWS reset timeout timer expired (*) -PORTE_HARD_RESET -- Hard Reset primitive received. - -PHYE_LOSS_OF_SIGNAL -- the device is gone (*) -PHYE_OOB_DONE -- OOB went fine and oob_mode is valid -PHYE_OOB_ERROR -- Error while doing OOB, the device probably -got disconnected. (*) -PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent. - -(*) should set/clear the appropriate fields in the phy, - or alternatively call the inlined sas_phy_disconnected() - which is just a helper, from their tasklet. - -The Execute Command SCSI RPC: - - int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags); - -Used to queue a task to the SAS LLDD. @task is the task to be executed. -@gfp_mask is the gfp_mask defining the context of the caller. - -This function should implement the Execute Command SCSI RPC, - -That is, when lldd_execute_task() is called, the command -go out on the transport *immediately*. There is *no* -queuing of any sort and at any level in a SAS LLDD. - -Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued; - 0, the task(s) were queued. - -struct sas_task { - dev -- the device this task is destined to - task_proto -- _one_ of enum sas_proto - scatter -- pointer to scatter gather list array - num_scatter -- number of elements in scatter - total_xfer_len -- total number of bytes expected to be transferred - data_dir -- PCI_DMA_... - task_done -- callback when the task has finished execution -}; - -DISCOVERY ---------- - -The sysfs tree has the following purposes: - a) It shows you the physical layout of the SAS domain at - the current time, i.e. how the domain looks in the - physical world right now. - b) Shows some device parameters _at_discovery_time_. - -This is a link to the tree(1) program, very useful in -viewing the SAS domain: -ftp://mama.indstate.edu/linux/tree/ -I expect user space applications to actually create a -graphical interface of this. - -That is, the sysfs domain tree doesn't show or keep state if -you e.g., change the meaning of the READY LED MEANING -setting, but it does show you the current connection status -of the domain device. - -Keeping internal device state changes is responsibility of -upper layers (Command set drivers) and user space. - -When a device or devices are unplugged from the domain, this -is reflected in the sysfs tree immediately, and the device(s) -removed from the system. - -The structure domain_device describes any device in the SAS -domain. It is completely managed by the SAS layer. A task -points to a domain device, this is how the SAS LLDD knows -where to send the task(s) to. A SAS LLDD only reads the -contents of the domain_device structure, but it never creates -or destroys one. - -Expander management from User Space ------------------------------------ - -In each expander directory in sysfs, there is a file called -"smp_portal". It is a binary sysfs attribute file, which -implements an SMP portal (Note: this is *NOT* an SMP port), -to which user space applications can send SMP requests and -receive SMP responses. - -Functionality is deceptively simple: - -1. Build the SMP frame you want to send. The format and layout - is described in the SAS spec. Leave the CRC field equal 0. -open(2) -2. Open the expander's SMP portal sysfs file in RW mode. -write(2) -3. Write the frame you built in 1. -read(2) -4. Read the amount of data you expect to receive for the frame you built. - If you receive different amount of data you expected to receive, - then there was some kind of error. -close(2) -All this process is shown in detail in the function do_smp_func() -and its callers, in the file "expander_conf.c". - -The kernel functionality is implemented in the file -"sas_expander.c". - -The program "expander_conf.c" implements this. It takes one -argument, the sysfs file name of the SMP portal to the -expander, and gives expander information, including routing -tables. - -The SMP portal gives you complete control of the expander, -so please be careful. |