]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/mps/mps_sas_lsi.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / mps / mps_sas_lsi.c
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$");
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_EVENT, "(%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_EVENT, "Received IR Volume event:\n");
378                 switch (event_data->ReasonCode) {
379                 case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
380                         mps_dprint(sc, MPS_EVENT, "   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_EVENT, "   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_EVENT, "   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_EVENT, "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_EVENT, "   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_EVENT, "   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_EVENT, "   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_EVENT, "Received IR Op Status event:\n");
522                 mps_dprint(sc, MPS_EVENT, "   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_EVENT, "(%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
673         if (mpssas_check_id(sassc, id) != 0) {
674                 device_printf(sc->mps_dev, "Excluding target id %d\n", id);
675                 error = ENXIO;
676                 goto out;
677         }
678
679         mps_dprint(sc, MPS_MAPPING, "SAS Address from SAS device page0 = %jx\n",
680             sas_address);
681         targ = &sassc->targets[id];
682         targ->devinfo = device_info;
683         targ->devname = le32toh(config_page.DeviceName.High);
684         targ->devname = (targ->devname << 32) | 
685             le32toh(config_page.DeviceName.Low);
686         targ->encl_handle = le16toh(config_page.EnclosureHandle);
687         targ->encl_slot = le16toh(config_page.Slot);
688         targ->handle = handle;
689         targ->parent_handle = le16toh(config_page.ParentDevHandle);
690         targ->sasaddr = mps_to_u64(&config_page.SASAddress);
691         targ->parent_sasaddr = le64toh(parent_sas_address);
692         targ->parent_devinfo = parent_devinfo;
693         targ->tid = id;
694         targ->linkrate = (linkrate>>4);
695         targ->flags = 0;
696         TAILQ_INIT(&targ->commands);
697         TAILQ_INIT(&targ->timedout_commands);
698         while(!SLIST_EMPTY(&targ->luns)) {
699                 lun = SLIST_FIRST(&targ->luns);
700                 SLIST_REMOVE_HEAD(&targ->luns, lun_link);
701                 free(lun, M_MPT2);
702         }
703         SLIST_INIT(&targ->luns);
704
705         mps_describe_devinfo(targ->devinfo, devstring, 80);
706         mps_dprint(sc, MPS_MAPPING, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring,
707             mps_describe_table(mps_linkrate_names, targ->linkrate),
708             targ->handle, targ->encl_handle, targ->encl_slot);
709
710 #if __FreeBSD_version < 1000039
711         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
712 #endif
713                 mpssas_rescan_target(sc, targ);
714         mps_dprint(sc, MPS_MAPPING, "Target id 0x%x added\n", targ->tid);
715 out:
716         mpssas_startup_decrement(sassc);
717         return (error);
718         
719 }
720         
721 int
722 mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
723     u64 *sas_address, u16 handle, u32 device_info)
724 {
725         Mpi2SataPassthroughReply_t mpi_reply;
726         int i, rc, try_count;
727         u32 *bufferptr;
728         union _sata_sas_address hash_address;
729         struct _ata_identify_device_data ata_identify;
730         u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
731         u32 ioc_status;
732         u8 sas_status;
733
734         memset(&ata_identify, 0, sizeof(ata_identify));
735         try_count = 0;
736         do {
737                 rc = mpssas_get_sata_identify(sc, handle, &mpi_reply,
738                     (char *)&ata_identify, sizeof(ata_identify), device_info);
739                 try_count++;
740                 ioc_status = le16toh(mpi_reply.IOCStatus)
741                     & MPI2_IOCSTATUS_MASK;
742                 sas_status = mpi_reply.SASStatus;
743         } while ((rc == -EAGAIN || ioc_status || sas_status) &&
744             (try_count < 5));
745
746         if (rc == 0 && !ioc_status && !sas_status) {
747                 mps_dprint(sc, MPS_MAPPING, "%s: got SATA identify successfully "
748                            "for handle = 0x%x with try_count = %d\n",
749                            __func__, handle, try_count);
750         } else {
751                 mps_dprint(sc, MPS_MAPPING, "%s: handle = 0x%x failed\n",
752                            __func__, handle);
753                 return -1;
754         }
755         /* Copy & byteswap the 40 byte model number to a buffer */
756         for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
757                 buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
758                 buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
759         }
760         /* Copy & byteswap the 20 byte serial number to a buffer */
761         for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
762                 buffer[MPT2SAS_MN_LEN + i] =
763                         ((u8 *)ata_identify.serial_number)[i + 1];
764                 buffer[MPT2SAS_MN_LEN + i + 1] =
765                         ((u8 *)ata_identify.serial_number)[i];
766         }
767         bufferptr = (u32 *)buffer;
768         /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
769          * so loop through the first 56 bytes (7*8),
770          * and then add in the last dword.
771          */
772         hash_address.word.low  = 0;
773         hash_address.word.high = 0;
774         for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
775                 hash_address.word.low += *bufferptr;
776                 bufferptr++;
777                 hash_address.word.high += *bufferptr;
778                 bufferptr++;
779         }
780         /* Add the last dword */
781         hash_address.word.low += *bufferptr;
782         /* Make sure the hash doesn't start with 5, because it could clash
783          * with a SAS address. Change 5 to a D.
784          */
785         if ((hash_address.word.high & 0x000000F0) == (0x00000050))
786                 hash_address.word.high |= 0x00000080;
787         *sas_address = (u64)hash_address.wwid[0] << 56 |
788             (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
789             (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
790             (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] <<  8 |
791             (u64)hash_address.wwid[7];
792         return 0;
793 }
794
795 static int
796 mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
797     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
798 {
799         Mpi2SataPassthroughRequest_t *mpi_request;
800         Mpi2SataPassthroughReply_t *reply;
801         struct mps_command *cm;
802         char *buffer;
803         int error = 0;
804
805         buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO);
806         if (!buffer)
807                 return ENOMEM;
808
809         if ((cm = mps_alloc_command(sc)) == NULL) {
810                 free(buffer, M_MPT2);
811                 return (EBUSY);
812         }
813         mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
814         bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
815         mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
816         mpi_request->VF_ID = 0;
817         mpi_request->DevHandle = htole16(handle);
818         mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
819             MPI2_SATA_PT_REQ_PT_FLAGS_READ);
820         mpi_request->DataLength = htole32(sz);
821         mpi_request->CommandFIS[0] = 0x27;
822         mpi_request->CommandFIS[1] = 0x80;
823         mpi_request->CommandFIS[2] =  (devinfo &
824             MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
825         cm->cm_sge = &mpi_request->SGL;
826         cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
827         cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
828         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
829         cm->cm_data = buffer;
830         cm->cm_length = htole32(sz);
831         error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
832         reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
833         if (error || (reply == NULL)) {
834                 /* FIXME */
835                 /*
836                  * If the request returns an error then we need to do a diag
837                  * reset
838                  */ 
839                 printf("%s: request for page completed with error %d",
840                     __func__, error);
841                 error = ENXIO;
842                 goto out;
843         }
844         bcopy(buffer, id_buffer, sz);
845         bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
846         if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
847             MPI2_IOCSTATUS_SUCCESS) {
848                 printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n",
849                     __func__, reply->IOCStatus);
850                 error = ENXIO;
851                 goto out;
852         }
853 out:
854         mps_free_command(sc, cm);
855         free(buffer, M_MPT2);   
856         return (error);
857 }
858
859 static int
860 mpssas_volume_add(struct mps_softc *sc, u16 handle)
861 {
862         struct mpssas_softc *sassc;
863         struct mpssas_target *targ;
864         u64 wwid;
865         unsigned int id;
866         int error = 0;
867         struct mpssas_lun *lun;
868
869         sassc = sc->sassc;
870         mpssas_startup_increment(sassc);
871         /* wwid is endian safe */
872         mps_config_get_volume_wwid(sc, handle, &wwid);
873         if (!wwid) {
874                 printf("%s: invalid WWID; cannot add volume to mapping table\n",
875                     __func__);
876                 error = ENXIO;
877                 goto out;
878         }
879
880         id = mps_mapping_get_raid_id(sc, wwid, handle);
881         if (id == MPS_MAP_BAD_ID) {
882                 printf("%s: could not get ID for volume with handle 0x%04x and "
883                     "WWID 0x%016llx\n", __func__, handle,
884                     (unsigned long long)wwid);
885                 error = ENXIO;
886                 goto out;
887         }
888
889         targ = &sassc->targets[id];
890         targ->tid = id;
891         targ->handle = handle;
892         targ->devname = wwid;
893         TAILQ_INIT(&targ->commands);
894         TAILQ_INIT(&targ->timedout_commands);
895         while(!SLIST_EMPTY(&targ->luns)) {
896                 lun = SLIST_FIRST(&targ->luns);
897                 SLIST_REMOVE_HEAD(&targ->luns, lun_link);
898                 free(lun, M_MPT2);
899         }
900         SLIST_INIT(&targ->luns);
901 #if __FreeBSD_version < 1000039
902         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
903 #endif
904                 mpssas_rescan_target(sc, targ);
905         mps_dprint(sc, MPS_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n",
906             targ->tid, wwid);
907 out:
908         mpssas_startup_decrement(sassc);
909         return (error);
910 }
911
912 /**
913  * mpssas_ir_shutdown - IR shutdown notification
914  * @sc: per adapter object
915  *
916  * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
917  * the host system is shutting down.
918  *
919  * Return nothing.
920  */
921 void
922 mpssas_ir_shutdown(struct mps_softc *sc)
923 {
924         u16 volume_mapping_flags;
925         u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
926         struct dev_mapping_table *mt_entry;
927         u32 start_idx, end_idx;
928         unsigned int id, found_volume = 0;
929         struct mps_command *cm;
930         Mpi2RaidActionRequest_t *action;
931
932         mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
933
934         /* is IR firmware build loaded? */
935         if (!sc->ir_firmware)
936                 return;
937
938         /* are there any volumes?  Look at IR target IDs. */
939         // TODO-later, this should be looked up in the RAID config structure
940         // when it is implemented.
941         volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
942             MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
943         if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
944                 start_idx = 0;
945                 if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
946                         start_idx = 1;
947         } else
948                 start_idx = sc->max_devices - sc->max_volumes;
949         end_idx = start_idx + sc->max_volumes - 1;
950
951         for (id = start_idx; id < end_idx; id++) {
952                 mt_entry = &sc->mapping_table[id];
953                 if ((mt_entry->physical_id != 0) &&
954                     (mt_entry->missing_count == 0)) {
955                         found_volume = 1;
956                         break;
957                 }
958         }
959
960         if (!found_volume)
961                 return;
962
963         if ((cm = mps_alloc_command(sc)) == NULL) {
964                 printf("%s: command alloc failed\n", __func__);
965                 return;
966         }
967
968         action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
969         action->Function = MPI2_FUNCTION_RAID_ACTION;
970         action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
971         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
972         mps_lock(sc);
973         mps_wait_command(sc, cm, 5, CAN_SLEEP);
974         mps_unlock(sc);
975
976         /*
977          * Don't check for reply, just leave.
978          */
979         if (cm)
980                 mps_free_command(sc, cm);
981 }