The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mps/mps_sas_lsi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2011, 2012 LSI Corp.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * LSI MPT-Fusion Host Adapter FreeBSD
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.4/sys/dev/mps/mps_sas_lsi.c 238768 2012-07-25 12:06:52Z brueffer $");
   31 
   32 /* Communications core for LSI MPT2 */
   33 
   34 /* TODO Move headers to mpsvar */
   35 #include <sys/types.h>
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/selinfo.h>
   40 #include <sys/module.h>
   41 #include <sys/bus.h>
   42 #include <sys/conf.h>
   43 #include <sys/bio.h>
   44 #include <sys/malloc.h>
   45 #include <sys/uio.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/endian.h>
   48 #include <sys/queue.h>
   49 #include <sys/kthread.h>
   50 #include <sys/taskqueue.h>
   51 #include <sys/sbuf.h>
   52 
   53 #include <machine/bus.h>
   54 #include <machine/resource.h>
   55 #include <sys/rman.h>
   56 
   57 #include <machine/stdarg.h>
   58 
   59 #include <cam/cam.h>
   60 #include <cam/cam_ccb.h>
   61 #include <cam/cam_debug.h>
   62 #include <cam/cam_sim.h>
   63 #include <cam/cam_xpt_sim.h>
   64 #include <cam/cam_xpt_periph.h>
   65 #include <cam/cam_periph.h>
   66 #include <cam/scsi/scsi_all.h>
   67 #include <cam/scsi/scsi_message.h>
   68 
   69 #include <dev/mps/mpi/mpi2_type.h>
   70 #include <dev/mps/mpi/mpi2.h>
   71 #include <dev/mps/mpi/mpi2_ioc.h>
   72 #include <dev/mps/mpi/mpi2_sas.h>
   73 #include <dev/mps/mpi/mpi2_cnfg.h>
   74 #include <dev/mps/mpi/mpi2_init.h>
   75 #include <dev/mps/mpi/mpi2_raid.h>
   76 #include <dev/mps/mpi/mpi2_tool.h>
   77 #include <dev/mps/mps_ioctl.h>
   78 #include <dev/mps/mpsvar.h>
   79 #include <dev/mps/mps_table.h>
   80 #include <dev/mps/mps_sas.h>
   81 
   82 /* For Hashed SAS Address creation for SATA Drives */
   83 #define MPT2SAS_SN_LEN 20
   84 #define MPT2SAS_MN_LEN 40
   85 
   86 struct mps_fw_event_work {
   87         u16                     event;
   88         void                    *event_data;
   89         TAILQ_ENTRY(mps_fw_event_work)  ev_link;
   90 };
   91 
   92 union _sata_sas_address {
   93         u8 wwid[8];
   94         struct {
   95                 u32 high;
   96                 u32 low;
   97         } word;
   98 };
   99 
  100 /*
  101  * define the IDENTIFY DEVICE structure
  102  */
  103 struct _ata_identify_device_data {
  104         u16 reserved1[10];      /* 0-9 */
  105         u16 serial_number[10];  /* 10-19 */
  106         u16 reserved2[7];       /* 20-26 */
  107         u16 model_number[20];   /* 27-46*/
  108         u16 reserved3[209];     /* 47-255*/
  109 };
  110 static u32 event_count;
  111 static void mpssas_fw_work(struct mps_softc *sc,
  112     struct mps_fw_event_work *fw_event);
  113 static void mpssas_fw_event_free(struct mps_softc *,
  114     struct mps_fw_event_work *);
  115 static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate);
  116 static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
  117     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
  118     u32 devinfo);
  119 int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
  120     u64 *sas_address, u16 handle, u32 device_info);
  121 static int mpssas_volume_add(struct mps_softc *sc,
  122     u16 handle);
  123 
  124 void
  125 mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
  126     MPI2_EVENT_NOTIFICATION_REPLY *event)
  127 {
  128         struct mps_fw_event_work *fw_event;
  129         u16 sz;
  130 
  131         mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
  132         mps_print_evt_sas(sc, event);
  133         mpssas_record_event(sc, event);
  134 
  135         fw_event = malloc(sizeof(struct mps_fw_event_work), M_MPT2,
  136              M_ZERO|M_NOWAIT);
  137         if (!fw_event) {
  138                 printf("%s: allocate failed for fw_event\n", __func__);
  139                 return;
  140         }
  141         sz = le16toh(event->EventDataLength) * 4;
  142         fw_event->event_data = malloc(sz, M_MPT2, M_ZERO|M_NOWAIT);
  143         if (!fw_event->event_data) {
  144                 printf("%s: allocate failed for event_data\n", __func__);
  145                 free(fw_event, M_MPT2);
  146                 return;
  147         }
  148 
  149         bcopy(event->EventData, fw_event->event_data, sz);
  150         fw_event->event = event->Event;
  151         if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
  152             event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
  153             event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
  154             sc->track_mapping_events)
  155                 sc->pending_map_events++;
  156 
  157         /*
  158          * When wait_for_port_enable flag is set, make sure that all the events
  159          * are processed. Increment the startup_refcount and decrement it after
  160          * events are processed.
  161          */
  162         if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
  163             event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
  164             sc->wait_for_port_enable)
  165                 mpssas_startup_increment(sc->sassc);
  166 
  167         TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
  168         taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
  169 
  170 }
  171 
  172 static void
  173 mpssas_fw_event_free(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
  174 {
  175 
  176         free(fw_event->event_data, M_MPT2);
  177         free(fw_event, M_MPT2);
  178 }
  179 
  180 /**
  181  * _mps_fw_work - delayed task for processing firmware events
  182  * @sc: per adapter object
  183  * @fw_event: The fw_event_work object
  184  * Context: user.
  185  *
  186  * Return nothing.
  187  */
  188 static void
  189 mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
  190 {
  191         struct mpssas_softc *sassc;
  192         sassc = sc->sassc;
  193 
  194         mps_dprint(sc, MPS_INFO, "(%d)->(%s) Working on  Event: [%x]\n",
  195                         event_count++,__func__,fw_event->event);
  196         switch (fw_event->event) {
  197         case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 
  198         {
  199                 MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
  200                 MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
  201                 int i;
  202 
  203                 data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
  204                     fw_event->event_data;
  205 
  206                 mps_mapping_topology_change_event(sc, fw_event->event_data);
  207 
  208                 for (i = 0; i < data->NumEntries; i++) {
  209                         phy = &data->PHY[i];
  210                         switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
  211                         case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
  212                                 if (mpssas_add_device(sc,
  213                                     le16toh(phy->AttachedDevHandle), phy->LinkRate)){
  214                                         printf("%s: failed to add device with "
  215                                             "handle 0x%x\n", __func__,
  216                                             le16toh(phy->AttachedDevHandle));
  217                                         mpssas_prepare_remove(sassc, le16toh(
  218                                                 phy->AttachedDevHandle));
  219                                 }
  220                                 break;
  221                         case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
  222                                 mpssas_prepare_remove(sassc,le16toh( 
  223                                         phy->AttachedDevHandle));
  224                                 break;
  225                         case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
  226                         case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
  227                         case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
  228                         default:
  229                                 break;
  230                         }
  231                 }
  232                 /*
  233                  * refcount was incremented for this event in
  234                  * mpssas_evt_handler.  Decrement it here because the event has
  235                  * been processed.
  236                  */
  237                 mpssas_startup_decrement(sassc);
  238                 break;
  239         }
  240         case MPI2_EVENT_SAS_DISCOVERY:
  241         {
  242                 MPI2_EVENT_DATA_SAS_DISCOVERY *data;
  243 
  244                 data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data;
  245 
  246                 if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
  247                         mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n");
  248                 if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
  249                         mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n");
  250                         sassc->flags &= ~MPSSAS_IN_DISCOVERY;
  251                         mpssas_discovery_end(sassc);
  252                 }
  253                 break;
  254         }
  255         case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
  256         {
  257                 Mpi2EventDataSasEnclDevStatusChange_t *data;
  258                 data = (Mpi2EventDataSasEnclDevStatusChange_t *)
  259                     fw_event->event_data;
  260                 mps_mapping_enclosure_dev_status_change_event(sc,
  261                     fw_event->event_data);
  262                 break;
  263         }
  264         case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
  265         {
  266                 Mpi2EventIrConfigElement_t *element;
  267                 int i;
  268                 u8 foreign_config;
  269                 Mpi2EventDataIrConfigChangeList_t *event_data;
  270                 struct mpssas_target *targ;
  271                 unsigned int id;
  272 
  273                 event_data = fw_event->event_data;
  274                 foreign_config = (le32toh(event_data->Flags) &
  275                     MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
  276 
  277                 element =
  278                     (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
  279                 id = mps_mapping_get_raid_id_from_handle
  280                     (sc, element->VolDevHandle);
  281 
  282                 mps_mapping_ir_config_change_event(sc, event_data);
  283 
  284                 for (i = 0; i < event_data->NumElements; i++, element++) {
  285                         switch (element->ReasonCode) {
  286                         case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
  287                         case MPI2_EVENT_IR_CHANGE_RC_ADDED:
  288                                 if (!foreign_config) {
  289                                         if (mpssas_volume_add(sc, le16toh(element->VolDevHandle))){
  290                                                 printf("%s: failed to add RAID "
  291                                                     "volume with handle 0x%x\n",
  292                                                     __func__, le16toh(element->
  293                                                     VolDevHandle));
  294                                         }
  295                                 }
  296                                 break;
  297                         case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
  298                         case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
  299                                 /*
  300                                  * Rescan after volume is deleted or removed.
  301                                  */
  302                                 if (!foreign_config) {
  303                                         if (id == MPS_MAP_BAD_ID) {
  304                                                 printf("%s: could not get ID "
  305                                                     "for volume with handle "
  306                                                     "0x%04x\n", __func__,
  307                                                     le16toh(element->VolDevHandle));
  308                                                 break;
  309                                         }
  310                                         
  311                                         targ = &sassc->targets[id];
  312                                         targ->handle = 0x0;
  313                                         targ->encl_slot = 0x0;
  314                                         targ->encl_handle = 0x0;
  315                                         targ->exp_dev_handle = 0x0;
  316                                         targ->phy_num = 0x0;
  317                                         targ->linkrate = 0x0;
  318                                         mpssas_rescan_target(sc, targ);
  319                                         printf("RAID target id 0x%x removed\n",
  320                                             targ->tid);
  321                                 }
  322                                 break;
  323                         case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
  324                         case MPI2_EVENT_IR_CHANGE_RC_HIDE:
  325                                 /*
  326                                  * Phys Disk of a volume has been created.  Hide
  327                                  * it from the OS.
  328                                  */
  329                                 targ = mpssas_find_target_by_handle(sassc, 0, element->PhysDiskDevHandle);
  330                                 if (targ == NULL) 
  331                                         break;
  332                                 
  333                                 /* Set raid component flags only if it is not WD.
  334                                  * OR WrapDrive with WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in NVRAM
  335                                  */
  336                                 if((!sc->WD_available) ||
  337                                 ((sc->WD_available && 
  338                                 (sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) ||
  339                                 (sc->WD_valid_config && (sc->WD_hide_expose ==
  340                                 MPS_WD_HIDE_IF_VOLUME)))) {
  341                                         targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
  342                                 }
  343                                 mpssas_rescan_target(sc, targ);
  344                                 
  345                                 break;
  346                         case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
  347                                 /*
  348                                  * Phys Disk of a volume has been deleted.
  349                                  * Expose it to the OS.
  350                                  */
  351                                 if (mpssas_add_device(sc,
  352                                     le16toh(element->PhysDiskDevHandle), 0)){
  353                                         printf("%s: failed to add device with "
  354                                             "handle 0x%x\n", __func__,
  355                                             le16toh(element->PhysDiskDevHandle));
  356                                         mpssas_prepare_remove(sassc, le16toh(element->
  357                                             PhysDiskDevHandle));
  358                                 }
  359                                 break;
  360                         }
  361                 }
  362                 /*
  363                  * refcount was incremented for this event in
  364                  * mpssas_evt_handler.  Decrement it here because the event has
  365                  * been processed.
  366                  */
  367                 mpssas_startup_decrement(sassc);
  368                 break;
  369         }
  370         case MPI2_EVENT_IR_VOLUME:
  371         {
  372                 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
  373 
  374                 /*
  375                  * Informational only.
  376                  */
  377                 mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n");
  378                 switch (event_data->ReasonCode) {
  379                 case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
  380                         mps_dprint(sc, MPS_INFO, "   Volume Settings "
  381                             "changed from 0x%x to 0x%x for Volome with "
  382                             "handle 0x%x", le32toh(event_data->PreviousValue),
  383                             le32toh(event_data->NewValue),
  384                             le16toh(event_data->VolDevHandle));
  385                         break;
  386                 case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
  387                         mps_dprint(sc, MPS_INFO, "   Volume Status "
  388                             "changed from 0x%x to 0x%x for Volome with "
  389                             "handle 0x%x", le32toh(event_data->PreviousValue),
  390                             le32toh(event_data->NewValue),
  391                             le16toh(event_data->VolDevHandle));
  392                         break;
  393                 case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
  394                         mps_dprint(sc, MPS_INFO, "   Volume State "
  395                             "changed from 0x%x to 0x%x for Volome with "
  396                             "handle 0x%x", le32toh(event_data->PreviousValue),
  397                             le32toh(event_data->NewValue),
  398                             le16toh(event_data->VolDevHandle));
  399                                 u32 state;
  400                                 struct mpssas_target *targ;
  401                                 state = le32toh(event_data->NewValue);
  402                                 switch (state) {
  403                                 case MPI2_RAID_VOL_STATE_MISSING:
  404                                 case MPI2_RAID_VOL_STATE_FAILED:
  405                                         mpssas_prepare_volume_remove(sassc, event_data->
  406                                                         VolDevHandle);
  407                                         break;
  408                  
  409                                 case MPI2_RAID_VOL_STATE_ONLINE:
  410                                 case MPI2_RAID_VOL_STATE_DEGRADED:
  411                                 case MPI2_RAID_VOL_STATE_OPTIMAL:
  412                                         targ = mpssas_find_target_by_handle(sassc, 0, event_data->VolDevHandle);
  413                                         if (targ) {
  414                                                 printf("%s %d: Volume handle 0x%x is already added \n",
  415                                                                 __func__, __LINE__ , event_data->VolDevHandle);
  416                                                 break;
  417                                         }
  418                                         if (mpssas_volume_add(sc, le16toh(event_data->VolDevHandle))) {
  419                                                 printf("%s: failed to add RAID "
  420                                                         "volume with handle 0x%x\n",
  421                                                         __func__, le16toh(event_data->
  422                                                         VolDevHandle));
  423                                         }
  424                                         break;
  425                                 default:
  426                                         break;
  427                                 }
  428                         break;
  429                 default:
  430                         break;
  431                 }
  432                 break;
  433         }
  434         case MPI2_EVENT_IR_PHYSICAL_DISK:
  435         {
  436                 Mpi2EventDataIrPhysicalDisk_t *event_data =
  437                     fw_event->event_data;
  438                 struct mpssas_target *targ;
  439 
  440                 /*
  441                  * Informational only.
  442                  */
  443                 mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n");
  444                 switch (event_data->ReasonCode) {
  445                 case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
  446                         mps_dprint(sc, MPS_INFO, "   Phys Disk Settings "
  447                             "changed from 0x%x to 0x%x for Phys Disk Number "
  448                             "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
  449                             "%d", le32toh(event_data->PreviousValue),
  450                             le32toh(event_data->NewValue),
  451                                 event_data->PhysDiskNum,
  452                             le16toh(event_data->PhysDiskDevHandle),
  453                             le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
  454                         break;
  455                 case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
  456                         mps_dprint(sc, MPS_INFO, "   Phys Disk Status changed "
  457                             "from 0x%x to 0x%x for Phys Disk Number %d and "
  458                             "handle 0x%x at Enclosure handle 0x%x, Slot %d",
  459                                 le32toh(event_data->PreviousValue),
  460                             le32toh(event_data->NewValue), event_data->PhysDiskNum,
  461                             le16toh(event_data->PhysDiskDevHandle),
  462                             le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
  463                         break;
  464                 case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
  465                         mps_dprint(sc, MPS_INFO, "   Phys Disk State changed "
  466                             "from 0x%x to 0x%x for Phys Disk Number %d and "
  467                             "handle 0x%x at Enclosure handle 0x%x, Slot %d",
  468                                 le32toh(event_data->PreviousValue),
  469                             le32toh(event_data->NewValue), event_data->PhysDiskNum,
  470                             le16toh(event_data->PhysDiskDevHandle),
  471                             le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
  472                         switch (event_data->NewValue) {
  473                                 case MPI2_RAID_PD_STATE_ONLINE:
  474                                 case MPI2_RAID_PD_STATE_DEGRADED:
  475                                 case MPI2_RAID_PD_STATE_REBUILDING:
  476                                 case MPI2_RAID_PD_STATE_OPTIMAL:
  477                                 case MPI2_RAID_PD_STATE_HOT_SPARE:
  478                                         targ = mpssas_find_target_by_handle(sassc, 0, 
  479                                                         event_data->PhysDiskDevHandle);
  480                                         if (targ) {
  481                                                 if(!sc->WD_available) {
  482                                                         targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
  483                                                         printf("%s %d: Found Target for handle 0x%x.  \n",
  484                                                         __func__, __LINE__ , event_data->PhysDiskDevHandle);
  485                                                 } else if ((sc->WD_available && 
  486                                                         (sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) ||
  487                                                         (sc->WD_valid_config && (sc->WD_hide_expose ==
  488                                                         MPS_WD_HIDE_IF_VOLUME))) {
  489                                                         targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
  490                                                         printf("%s %d: WD: Found Target for handle 0x%x.  \n",
  491                                                         __func__, __LINE__ , event_data->PhysDiskDevHandle);
  492                                                 }
  493                                         }               
  494                                 break;
  495                                 case MPI2_RAID_PD_STATE_OFFLINE:
  496                                 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
  497                                 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
  498                                 default:
  499                                         targ = mpssas_find_target_by_handle(sassc, 0, 
  500                                                         event_data->PhysDiskDevHandle);
  501                                         if (targ) {
  502                                                 targ->flags |= ~MPS_TARGET_FLAGS_RAID_COMPONENT;
  503                                                 printf("%s %d: Found Target for handle 0x%x.  \n",
  504                                                 __func__, __LINE__ , event_data->PhysDiskDevHandle);
  505                                         }
  506                                 break;
  507                         }
  508                 default:
  509                         break;
  510                 }
  511                 break;
  512         }
  513         case MPI2_EVENT_IR_OPERATION_STATUS:
  514         {
  515                 Mpi2EventDataIrOperationStatus_t *event_data =
  516                     fw_event->event_data;
  517 
  518                 /*
  519                  * Informational only.
  520                  */
  521                 mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n");
  522                 mps_dprint(sc, MPS_INFO, "   RAID Operation of %d is %d "
  523                     "percent complete for Volume with handle 0x%x",
  524                     event_data->RAIDOperation, event_data->PercentComplete,
  525                     le16toh(event_data->VolDevHandle));
  526                 break;
  527         }
  528         case MPI2_EVENT_LOG_ENTRY_ADDED:
  529         {
  530                 pMpi2EventDataLogEntryAdded_t   logEntry;
  531                 uint16_t                        logQualifier;
  532                 uint8_t                         logCode;
  533 
  534                 logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data;
  535                 logQualifier = logEntry->LogEntryQualifier;
  536 
  537                 if (logQualifier == MPI2_WD_LOG_ENTRY) {
  538                         logCode = logEntry->LogData[0];
  539 
  540                         switch (logCode) {
  541                         case MPI2_WD_SSD_THROTTLING:
  542                                 printf("WarpDrive Warning: IO Throttling has "
  543                                     "occurred in the WarpDrive subsystem. "
  544                                     "Check WarpDrive documentation for "
  545                                     "additional details\n");
  546                                 break;
  547                         case MPI2_WD_DRIVE_LIFE_WARN:
  548                                 printf("WarpDrive Warning: Program/Erase "
  549                                     "Cycles for the WarpDrive subsystem in "
  550                                     "degraded range. Check WarpDrive "
  551                                     "documentation for additional details\n");
  552                                 break;
  553                         case MPI2_WD_DRIVE_LIFE_DEAD:
  554                                 printf("WarpDrive Fatal Error: There are no "
  555                                     "Program/Erase Cycles for the WarpDrive "
  556                                     "subsystem. The storage device will be in "
  557                                     "read-only mode. Check WarpDrive "
  558                                     "documentation for additional details\n");
  559                                 break;
  560                         case MPI2_WD_RAIL_MON_FAIL:
  561                                 printf("WarpDrive Fatal Error: The Backup Rail "
  562                                     "Monitor has failed on the WarpDrive "
  563                                     "subsystem. Check WarpDrive documentation "
  564                                     "for additional details\n");
  565                                 break;
  566                         default:
  567                                 break;
  568                         }
  569                 }
  570                 break;
  571         }
  572         case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
  573         case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
  574         default:
  575                 mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n",
  576                     fw_event->event);
  577                 break;
  578 
  579         }
  580         mps_dprint(sc, MPS_INFO, "(%d)->(%s) Event Free: [%x]\n",event_count,__func__, fw_event->event);
  581         mpssas_fw_event_free(sc, fw_event);
  582 }
  583 
  584 void
  585 mpssas_firmware_event_work(void *arg, int pending)
  586 {
  587         struct mps_fw_event_work *fw_event;
  588         struct mps_softc *sc;
  589 
  590         sc = (struct mps_softc *)arg;
  591         mps_lock(sc);
  592         while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) {
  593                 TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link);
  594                 mpssas_fw_work(sc, fw_event);
  595         }
  596         mps_unlock(sc);
  597 }
  598 
  599 static int
  600 mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
  601         char devstring[80];
  602         struct mpssas_softc *sassc;
  603         struct mpssas_target *targ;
  604         Mpi2ConfigReply_t mpi_reply;
  605         Mpi2SasDevicePage0_t config_page;
  606         uint64_t sas_address, sata_sas_address;
  607         uint64_t parent_sas_address = 0;
  608         u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
  609         u32 device_info, parent_devinfo = 0;
  610         unsigned int id;
  611         int ret;
  612         int error = 0;
  613         struct mpssas_lun *lun;
  614 
  615         sassc = sc->sassc;
  616         mpssas_startup_increment(sassc);
  617         if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page,
  618              MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
  619                 printf("%s: error reading SAS device page0\n", __func__);
  620                 error = ENXIO;
  621                 goto out;
  622         }
  623 
  624         device_info = le32toh(config_page.DeviceInfo);
  625 
  626         if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0)
  627          && (le16toh(config_page.ParentDevHandle) != 0)) {
  628                 Mpi2ConfigReply_t tmp_mpi_reply;
  629                 Mpi2SasDevicePage0_t parent_config_page;
  630 
  631                 if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply,
  632                      &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
  633                      le16toh(config_page.ParentDevHandle)))) {
  634                         printf("%s: error reading SAS device %#x page0\n",
  635                                __func__, le16toh(config_page.ParentDevHandle));
  636                 } else {
  637                         parent_sas_address = parent_config_page.SASAddress.High;
  638                         parent_sas_address = (parent_sas_address << 32) |
  639                                 parent_config_page.SASAddress.Low;
  640                         parent_devinfo = le32toh(parent_config_page.DeviceInfo);
  641                 }
  642         }
  643         /* TODO Check proper endianess */
  644         sas_address = config_page.SASAddress.High;
  645         sas_address = (sas_address << 32) | 
  646             config_page.SASAddress.Low;
  647 
  648         if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE)
  649                     == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
  650                 if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
  651                         ret = mpssas_get_sas_address_for_sata_disk(sc,
  652                             &sata_sas_address, handle, device_info);
  653                         if (!ret)
  654                                 id = mps_mapping_get_sas_id(sc,
  655                                     sata_sas_address, handle);
  656                         else
  657                                 id = mps_mapping_get_sas_id(sc,
  658                                     sas_address, handle);
  659                 } else
  660                         id = mps_mapping_get_sas_id(sc, sas_address,
  661                             handle);
  662         } else
  663                 id = mps_mapping_get_sas_id(sc, sas_address, handle);
  664 
  665         if (id == MPS_MAP_BAD_ID) {
  666                 printf("failure at %s:%d/%s()! Could not get ID for device "
  667                     "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
  668                     handle);
  669                 error = ENXIO;
  670                 goto out;
  671         }
  672         mps_dprint(sc, MPS_INFO, "SAS Address from SAS device page0 = %jx\n",
  673             sas_address);
  674         targ = &sassc->targets[id];
  675         targ->devinfo = device_info;
  676         targ->devname = le32toh(config_page.DeviceName.High);
  677         targ->devname = (targ->devname << 32) | 
  678             le32toh(config_page.DeviceName.Low);
  679         targ->encl_handle = le16toh(config_page.EnclosureHandle);
  680         targ->encl_slot = le16toh(config_page.Slot);
  681         targ->handle = handle;
  682         targ->parent_handle = le16toh(config_page.ParentDevHandle);
  683         targ->sasaddr = mps_to_u64(&config_page.SASAddress);
  684         targ->parent_sasaddr = le64toh(parent_sas_address);
  685         targ->parent_devinfo = parent_devinfo;
  686         targ->tid = id;
  687         targ->linkrate = (linkrate>>4);
  688         targ->flags = 0;
  689         TAILQ_INIT(&targ->commands);
  690         TAILQ_INIT(&targ->timedout_commands);
  691         while(!SLIST_EMPTY(&targ->luns)) {
  692                 lun = SLIST_FIRST(&targ->luns);
  693                 SLIST_REMOVE_HEAD(&targ->luns, lun_link);
  694                 free(lun, M_MPT2);
  695         }
  696         SLIST_INIT(&targ->luns);
  697 
  698         mps_describe_devinfo(targ->devinfo, devstring, 80);
  699         mps_dprint(sc, MPS_INFO, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring,
  700             mps_describe_table(mps_linkrate_names, targ->linkrate),
  701             targ->handle, targ->encl_handle, targ->encl_slot);
  702         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
  703                 mpssas_rescan_target(sc, targ);
  704         mps_dprint(sc, MPS_INFO, "Target id 0x%x added\n", targ->tid);
  705 out:
  706         mpssas_startup_decrement(sassc);
  707         return (error);
  708         
  709 }
  710         
  711 int
  712 mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
  713     u64 *sas_address, u16 handle, u32 device_info)
  714 {
  715         Mpi2SataPassthroughReply_t mpi_reply;
  716         int i, rc, try_count;
  717         u32 *bufferptr;
  718         union _sata_sas_address hash_address;
  719         struct _ata_identify_device_data ata_identify;
  720         u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
  721         u32 ioc_status;
  722         u8 sas_status;
  723 
  724         memset(&ata_identify, 0, sizeof(ata_identify));
  725         try_count = 0;
  726         do {
  727                 rc = mpssas_get_sata_identify(sc, handle, &mpi_reply,
  728                     (char *)&ata_identify, sizeof(ata_identify), device_info);
  729                 try_count++;
  730                 ioc_status = le16toh(mpi_reply.IOCStatus)
  731                     & MPI2_IOCSTATUS_MASK;
  732                 sas_status = mpi_reply.SASStatus;
  733         } while ((rc == -EAGAIN || ioc_status || sas_status) &&
  734             (try_count < 5));
  735 
  736         if (rc == 0 && !ioc_status && !sas_status) {
  737                 mps_dprint(sc, MPS_INFO, "%s: got SATA identify successfully "
  738                            "for handle = 0x%x with try_count = %d\n",
  739                            __func__, handle, try_count);
  740         } else {
  741                 mps_dprint(sc, MPS_INFO, "%s: handle = 0x%x failed\n",
  742                            __func__, handle);
  743                 return -1;
  744         }
  745         /* Copy & byteswap the 40 byte model number to a buffer */
  746         for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
  747                 buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
  748                 buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
  749         }
  750         /* Copy & byteswap the 20 byte serial number to a buffer */
  751         for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
  752                 buffer[MPT2SAS_MN_LEN + i] =
  753                         ((u8 *)ata_identify.serial_number)[i + 1];
  754                 buffer[MPT2SAS_MN_LEN + i + 1] =
  755                         ((u8 *)ata_identify.serial_number)[i];
  756         }
  757         bufferptr = (u32 *)buffer;
  758         /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
  759          * so loop through the first 56 bytes (7*8),
  760          * and then add in the last dword.
  761          */
  762         hash_address.word.low  = 0;
  763         hash_address.word.high = 0;
  764         for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
  765                 hash_address.word.low += *bufferptr;
  766                 bufferptr++;
  767                 hash_address.word.high += *bufferptr;
  768                 bufferptr++;
  769         }
  770         /* Add the last dword */
  771         hash_address.word.low += *bufferptr;
  772         /* Make sure the hash doesn't start with 5, because it could clash
  773          * with a SAS address. Change 5 to a D.
  774          */
  775         if ((hash_address.word.high & 0x000000F0) == (0x00000050))
  776                 hash_address.word.high |= 0x00000080;
  777         *sas_address = (u64)hash_address.wwid[0] << 56 |
  778             (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
  779             (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
  780             (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] <<  8 |
  781             (u64)hash_address.wwid[7];
  782         return 0;
  783 }
  784 
  785 static int
  786 mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
  787     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
  788 {
  789         Mpi2SataPassthroughRequest_t *mpi_request;
  790         Mpi2SataPassthroughReply_t *reply;
  791         struct mps_command *cm;
  792         char *buffer;
  793         int error = 0;
  794 
  795         buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO);
  796         if (!buffer)
  797                 return ENOMEM;
  798 
  799         if ((cm = mps_alloc_command(sc)) == NULL) {
  800                 free(buffer, M_MPT2);
  801                 return (EBUSY);
  802         }
  803         mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
  804         bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
  805         mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
  806         mpi_request->VF_ID = 0;
  807         mpi_request->DevHandle = htole16(handle);
  808         mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
  809             MPI2_SATA_PT_REQ_PT_FLAGS_READ);
  810         mpi_request->DataLength = htole32(sz);
  811         mpi_request->CommandFIS[0] = 0x27;
  812         mpi_request->CommandFIS[1] = 0x80;
  813         mpi_request->CommandFIS[2] =  (devinfo &
  814             MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
  815         cm->cm_sge = &mpi_request->SGL;
  816         cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
  817         cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
  818         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
  819         cm->cm_data = buffer;
  820         cm->cm_length = htole32(sz);
  821         error = mps_request_polled(sc, cm);
  822         reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
  823         if (error || (reply == NULL)) {
  824                 /* FIXME */
  825                 /* If the poll returns error then we need to do diag reset */ 
  826                 printf("%s: poll for page completed with error %d",
  827                     __func__, error);
  828                 error = ENXIO;
  829                 goto out;
  830         }
  831         bcopy(buffer, id_buffer, sz);
  832         bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
  833         if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
  834             MPI2_IOCSTATUS_SUCCESS) {
  835                 printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n",
  836                     __func__, reply->IOCStatus);
  837                 error = ENXIO;
  838                 goto out;
  839         }
  840 out:
  841         mps_free_command(sc, cm);
  842         free(buffer, M_MPT2);   
  843         return (error);
  844 }
  845 
  846 static int
  847 mpssas_volume_add(struct mps_softc *sc, u16 handle)
  848 {
  849         struct mpssas_softc *sassc;
  850         struct mpssas_target *targ;
  851         u64 wwid;
  852         unsigned int id;
  853         int error = 0;
  854         struct mpssas_lun *lun;
  855 
  856         sassc = sc->sassc;
  857         mpssas_startup_increment(sassc);
  858         /* wwid is endian safe */
  859         mps_config_get_volume_wwid(sc, handle, &wwid);
  860         if (!wwid) {
  861                 printf("%s: invalid WWID; cannot add volume to mapping table\n",
  862                     __func__);
  863                 error = ENXIO;
  864                 goto out;
  865         }
  866 
  867         id = mps_mapping_get_raid_id(sc, wwid, handle);
  868         if (id == MPS_MAP_BAD_ID) {
  869                 printf("%s: could not get ID for volume with handle 0x%04x and "
  870                     "WWID 0x%016llx\n", __func__, handle,
  871                     (unsigned long long)wwid);
  872                 error = ENXIO;
  873                 goto out;
  874         }
  875 
  876         targ = &sassc->targets[id];
  877         targ->tid = id;
  878         targ->handle = handle;
  879         targ->devname = wwid;
  880         TAILQ_INIT(&targ->commands);
  881         TAILQ_INIT(&targ->timedout_commands);
  882         while(!SLIST_EMPTY(&targ->luns)) {
  883                 lun = SLIST_FIRST(&targ->luns);
  884                 SLIST_REMOVE_HEAD(&targ->luns, lun_link);
  885                 free(lun, M_MPT2);
  886         }
  887         SLIST_INIT(&targ->luns);
  888         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
  889                 mpssas_rescan_target(sc, targ);
  890         mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n",
  891             targ->tid, wwid);
  892 out:
  893         mpssas_startup_decrement(sassc);
  894         return (error);
  895 }
  896 
  897 /**
  898  * mpssas_ir_shutdown - IR shutdown notification
  899  * @sc: per adapter object
  900  *
  901  * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
  902  * the host system is shutting down.
  903  *
  904  * Return nothing.
  905  */
  906 void
  907 mpssas_ir_shutdown(struct mps_softc *sc)
  908 {
  909         u16 volume_mapping_flags;
  910         u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
  911         struct dev_mapping_table *mt_entry;
  912         u32 start_idx, end_idx;
  913         unsigned int id, found_volume = 0;
  914         struct mps_command *cm;
  915         Mpi2RaidActionRequest_t *action;
  916 
  917         mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
  918 
  919         /* is IR firmware build loaded? */
  920         if (!sc->ir_firmware)
  921                 return;
  922 
  923         /* are there any volumes?  Look at IR target IDs. */
  924         // TODO-later, this should be looked up in the RAID config structure
  925         // when it is implemented.
  926         volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
  927             MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
  928         if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
  929                 start_idx = 0;
  930                 if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
  931                         start_idx = 1;
  932         } else
  933                 start_idx = sc->max_devices - sc->max_volumes;
  934         end_idx = start_idx + sc->max_volumes - 1;
  935 
  936         for (id = start_idx; id < end_idx; id++) {
  937                 mt_entry = &sc->mapping_table[id];
  938                 if ((mt_entry->physical_id != 0) &&
  939                     (mt_entry->missing_count == 0)) {
  940                         found_volume = 1;
  941                         break;
  942                 }
  943         }
  944 
  945         if (!found_volume)
  946                 return;
  947 
  948         if ((cm = mps_alloc_command(sc)) == NULL) {
  949                 printf("%s: command alloc failed\n", __func__);
  950                 return;
  951         }
  952 
  953         action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
  954         action->Function = MPI2_FUNCTION_RAID_ACTION;
  955         action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
  956         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
  957         mps_lock(sc);
  958         mps_request_polled(sc, cm);
  959         mps_unlock(sc);
  960 
  961         /*
  962          * Don't check for reply, just leave.
  963          */
  964         if (cm)
  965                 mps_free_command(sc, cm);
  966 }

Cache object: 41b5b54d25d902473477a1210bcddb8b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.