]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
scsi: docs: convert libsas.txt to ReST
authorMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 2 Mar 2020 08:15:52 +0000 (09:15 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 12 Mar 2020 03:08:00 +0000 (23:08 -0400)
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>
Documentation/scsi/index.rst
Documentation/scsi/libsas.rst [new file with mode: 0644]
Documentation/scsi/libsas.txt [deleted file]

index b13df9c1810aa8f6d9c7bda293918ae85b0fbc16..e6850c0a1378e484d9e8e4d599a9fc5c8d5e2dac 100644 (file)
@@ -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 (file)
index 0000000..7216b5d
--- /dev/null
@@ -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 (file)
index 8cac649..0000000
+++ /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.