From a88dc3ec2ca48d23c7761af02e1ceea731f609e9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 2 Mar 2020 09:15:52 +0100 Subject: 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 Signed-off-by: Martin K. Petersen --- Documentation/scsi/index.rst | 1 + Documentation/scsi/libsas.rst | 465 ++++++++++++++++++++++++++++++++++++++++++ Documentation/scsi/libsas.txt | 395 ----------------------------------- 3 files changed, 466 insertions(+), 395 deletions(-) create mode 100644 Documentation/scsi/libsas.rst delete mode 100644 Documentation/scsi/libsas.txt (limited to 'Documentation/scsi') diff --git a/Documentation/scsi/index.rst b/Documentation/scsi/index.rst index b13df9c1810a..e6850c0a1378 100644 --- a/Documentation/scsi/index.rst +++ b/Documentation/scsi/index.rst @@ -23,5 +23,6 @@ Linux SCSI Subsystem g_NCR5380 hpsa hptiop + libsas scsi_transport_srp/figures diff --git a/Documentation/scsi/libsas.rst b/Documentation/scsi/libsas.rst new file mode 100644 index 000000000000..7216b5d25800 --- /dev/null +++ b/Documentation/scsi/libsas.rst @@ -0,0 +1,465 @@ +.. SPDX-License-Identifier: GPL-2.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. [1]_ + +PORTE_TIMER_EVENT + - DWS reset timeout timer expired [1]_ + +PORTE_HARD_RESET + - Hard Reset primitive received. + +PHYE_LOSS_OF_SIGNAL + - the device is gone [1]_ + +PHYE_OOB_DONE + - OOB went fine and oob_mode is valid + +PHYE_OOB_ERROR + - Error while doing OOB, the device probably + got disconnected. [1]_ + +PHYE_SPINUP_HOLD + - SATA is present, COMWAKE not sent. + +.. [1] 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. 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. -- cgit v1.2.3