]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/dev/mps/mps_sas_lsi.c
MFC 230592:
[FreeBSD/stable/8.git] / sys / dev / mps / mps_sas_lsi.c
1 /*-
2  * Copyright (c) 2011 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
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     Mpi2EventIrConfigElement_t *element);
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         switch (fw_event->event) {
195         case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 
196         {
197                 MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
198                 MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
199                 int i;
200
201                 data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
202                     fw_event->event_data;
203
204                 mps_mapping_topology_change_event(sc, fw_event->event_data);
205
206                 for (i = 0; i < data->NumEntries; i++) {
207                         phy = &data->PHY[i];
208                         switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
209                         case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
210                                 if (mpssas_add_device(sc,
211                                     phy->AttachedDevHandle, phy->LinkRate)){
212                                         printf("%s: failed to add device with "
213                                             "handle 0x%x\n", __func__,
214                                             phy->AttachedDevHandle);
215                                         mpssas_prepare_remove(sassc, phy->
216                                             AttachedDevHandle);
217                                 }
218                                 break;
219                         case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
220                                 mpssas_prepare_remove(sassc, phy->
221                                     AttachedDevHandle);
222                                 break;
223                         case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
224                         case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
225                         case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
226                         default:
227                                 break;
228                         }
229                 }
230                 /*
231                  * refcount was incremented for this event in
232                  * mpssas_evt_handler.  Decrement it here because the event has
233                  * been processed.
234                  */
235                 mpssas_startup_decrement(sassc);
236                 break;
237         }
238         case MPI2_EVENT_SAS_DISCOVERY:
239         {
240                 MPI2_EVENT_DATA_SAS_DISCOVERY *data;
241
242                 data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data;
243
244                 if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
245                         mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n");
246                 if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
247                         mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n");
248                         sassc->flags &= ~MPSSAS_IN_DISCOVERY;
249                         mpssas_discovery_end(sassc);
250                 }
251                 break;
252         }
253         case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
254         {
255                 Mpi2EventDataSasEnclDevStatusChange_t *data;
256                 data = (Mpi2EventDataSasEnclDevStatusChange_t *)
257                     fw_event->event_data;
258                 mps_mapping_enclosure_dev_status_change_event(sc,
259                     fw_event->event_data);
260                 break;
261         }
262         case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
263         {
264                 Mpi2EventIrConfigElement_t *element;
265                 int i;
266                 u8 foreign_config;
267                 Mpi2EventDataIrConfigChangeList_t *event_data;
268                 struct mpssas_target *targ;
269                 unsigned int id;
270
271                 event_data = fw_event->event_data;
272                 foreign_config = (le32toh(event_data->Flags) &
273                     MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
274
275                 element =
276                     (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
277                 id = mps_mapping_get_raid_id_from_handle
278                     (sc, element->VolDevHandle);
279
280                 mps_mapping_ir_config_change_event(sc, event_data);
281
282                 for (i = 0; i < event_data->NumElements; i++, element++) {
283                         switch (element->ReasonCode) {
284                         case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
285                         case MPI2_EVENT_IR_CHANGE_RC_ADDED:
286                                 if (!foreign_config) {
287                                         if (mpssas_volume_add(sc, element)) {
288                                                 printf("%s: failed to add RAID "
289                                                     "volume with handle 0x%x\n",
290                                                     __func__, le16toh(element->
291                                                     VolDevHandle));
292                                         }
293                                 }
294                                 break;
295                         case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
296                         case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
297                                 /*
298                                  * Rescan after volume is deleted or removed.
299                                  */
300                                 if (!foreign_config) {
301                                         if (id == MPS_MAP_BAD_ID) {
302                                                 printf("%s: could not get ID "
303                                                     "for volume with handle "
304                                                     "0x%04x\n", __func__,
305                                                     element->VolDevHandle);
306                                                 break;
307                                         }
308                                         
309                                         targ = &sassc->targets[id];
310                                         targ->handle = 0x0;
311                                         targ->encl_slot = 0x0;
312                                         targ->encl_handle = 0x0;
313                                         targ->exp_dev_handle = 0x0;
314                                         targ->phy_num = 0x0;
315                                         targ->linkrate = 0x0;
316                                         mpssas_rescan_target(sc, targ);
317                                         printf("RAID target id 0x%x removed\n",
318                                             targ->tid);
319                                 }
320                                 break;
321                         case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
322                                 /*
323                                  * Phys Disk of a volume has been created.  Hide
324                                  * it from the OS.
325                                  */
326                                 mpssas_prepare_remove(sassc, element->
327                                     PhysDiskDevHandle);
328                                 break;
329                         case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
330                                 /*
331                                  * Phys Disk of a volume has been deleted.
332                                  * Expose it to the OS.
333                                  */
334                                 if (mpssas_add_device(sc,
335                                     element->PhysDiskDevHandle, 0)){
336                                         printf("%s: failed to add device with "
337                                             "handle 0x%x\n", __func__,
338                                             element->PhysDiskDevHandle);
339                                         mpssas_prepare_remove(sassc, element->
340                                             PhysDiskDevHandle);
341                                 }
342                                 break;
343                         }
344                 }
345                 /*
346                  * refcount was incremented for this event in
347                  * mpssas_evt_handler.  Decrement it here because the event has
348                  * been processed.
349                  */
350                 mpssas_startup_decrement(sassc);
351                 break;
352         }
353         case MPI2_EVENT_IR_VOLUME:
354         {
355                 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
356
357                 /*
358                  * Informational only.
359                  */
360                 mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n");
361                 switch (event_data->ReasonCode) {
362                 case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
363                         mps_dprint(sc, MPS_INFO, "   Volume Settings "
364                             "changed from 0x%x to 0x%x for Volome with "
365                             "handle 0x%x", event_data->PreviousValue,
366                             event_data->NewValue,
367                             event_data->VolDevHandle);
368                         break;
369                 case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
370                         mps_dprint(sc, MPS_INFO, "   Volume Status "
371                             "changed from 0x%x to 0x%x for Volome with "
372                             "handle 0x%x", event_data->PreviousValue,
373                             event_data->NewValue,
374                             event_data->VolDevHandle);
375                         break;
376                 case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
377                         mps_dprint(sc, MPS_INFO, "   Volume State "
378                             "changed from 0x%x to 0x%x for Volome with "
379                             "handle 0x%x", event_data->PreviousValue,
380                             event_data->NewValue,
381                             event_data->VolDevHandle);
382                         break;
383                 default:
384                         break;
385                 }
386                 break;
387         }
388         case MPI2_EVENT_IR_PHYSICAL_DISK:
389         {
390                 Mpi2EventDataIrPhysicalDisk_t *event_data =
391                     fw_event->event_data;
392
393                 /*
394                  * Informational only.
395                  */
396                 mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n");
397                 switch (event_data->ReasonCode) {
398                 case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
399                         mps_dprint(sc, MPS_INFO, "   Phys Disk Settings "
400                             "changed from 0x%x to 0x%x for Phys Disk Number "
401                             "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
402                             "%d", event_data->PreviousValue,
403                             event_data->NewValue, event_data->PhysDiskNum,
404                             event_data->PhysDiskDevHandle,
405                             event_data->EnclosureHandle, event_data->Slot);
406                         break;
407                 case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
408                         mps_dprint(sc, MPS_INFO, "   Phys Disk Status changed "
409                             "from 0x%x to 0x%x for Phys Disk Number %d and "
410                             "handle 0x%x at Enclosure handle 0x%x, Slot %d",
411                             event_data->PreviousValue, event_data->NewValue,
412                             event_data->PhysDiskNum,
413                             event_data->PhysDiskDevHandle,
414                             event_data->EnclosureHandle, event_data->Slot);
415                         break;
416                 case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
417                         mps_dprint(sc, MPS_INFO, "   Phys Disk State changed "
418                             "from 0x%x to 0x%x for Phys Disk Number %d and "
419                             "handle 0x%x at Enclosure handle 0x%x, Slot %d",
420                             event_data->PreviousValue, event_data->NewValue,
421                             event_data->PhysDiskNum,
422                             event_data->PhysDiskDevHandle,
423                             event_data->EnclosureHandle, event_data->Slot);
424                         break;
425                 default:
426                         break;
427                 }
428                 break;
429         }
430         case MPI2_EVENT_IR_OPERATION_STATUS:
431         {
432                 Mpi2EventDataIrOperationStatus_t *event_data =
433                     fw_event->event_data;
434
435                 /*
436                  * Informational only.
437                  */
438                 mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n");
439                 mps_dprint(sc, MPS_INFO, "   RAID Operation of %d is %d "
440                     "percent complete for Volume with handle 0x%x",
441                     event_data->RAIDOperation, event_data->PercentComplete,
442                     event_data->VolDevHandle);
443                 break;
444         }
445         case MPI2_EVENT_LOG_ENTRY_ADDED:
446         {
447                 pMpi2EventDataLogEntryAdded_t   logEntry;
448                 uint16_t                        logQualifier;
449                 uint8_t                         logCode;
450
451                 logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data;
452                 logQualifier = logEntry->LogEntryQualifier;
453
454                 if (logQualifier == MPI2_WD_LOG_ENTRY) {
455                         logCode = logEntry->LogData[0];
456
457                         switch (logCode) {
458                         case MPI2_WD_SSD_THROTTLING:
459                                 printf("WarpDrive Warning: IO Throttling has "
460                                     "occurred in the WarpDrive subsystem. "
461                                     "Check WarpDrive documentation for "
462                                     "additional details\n");
463                                 break;
464                         case MPI2_WD_DRIVE_LIFE_WARN:
465                                 printf("WarpDrive Warning: Program/Erase "
466                                     "Cycles for the WarpDrive subsystem in "
467                                     "degraded range. Check WarpDrive "
468                                     "documentation for additional details\n");
469                                 break;
470                         case MPI2_WD_DRIVE_LIFE_DEAD:
471                                 printf("WarpDrive Fatal Error: There are no "
472                                     "Program/Erase Cycles for the WarpDrive "
473                                     "subsystem. The storage device will be in "
474                                     "read-only mode. Check WarpDrive "
475                                     "documentation for additional details\n");
476                                 break;
477                         case MPI2_WD_RAIL_MON_FAIL:
478                                 printf("WarpDrive Fatal Error: The Backup Rail "
479                                     "Monitor has failed on the WarpDrive "
480                                     "subsystem. Check WarpDrive documentation "
481                                     "for additional details\n");
482                                 break;
483                         default:
484                                 break;
485                         }
486                 }
487                 break;
488         }
489         case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
490         case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
491         default:
492                 mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n",
493                     fw_event->event);
494                 break;
495
496         }
497         mpssas_fw_event_free(sc, fw_event);
498 }
499
500 void
501 mpssas_firmware_event_work(void *arg, int pending)
502 {
503         struct mps_fw_event_work *fw_event;
504         struct mps_softc *sc;
505
506         sc = (struct mps_softc *)arg;
507         mps_lock(sc);
508         while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) {
509                 TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link);
510                 mpssas_fw_work(sc, fw_event);
511         }
512         mps_unlock(sc);
513 }
514
515 static int
516 mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
517         char devstring[80];
518         struct mpssas_softc *sassc;
519         struct mpssas_target *targ;
520         Mpi2ConfigReply_t mpi_reply;
521         Mpi2SasDevicePage0_t config_page;
522         uint64_t sas_address, sata_sas_address;
523         uint64_t parent_sas_address = 0;
524         u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
525         u32 device_info, parent_devinfo = 0;
526         unsigned int id;
527         int ret;
528         int error = 0;
529
530         sassc = sc->sassc;
531         mpssas_startup_increment(sassc);
532         if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page,
533              MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
534                 printf("%s: error reading SAS device page0\n", __func__);
535                 error = ENXIO;
536                 goto out;
537         }
538
539         device_info = le32toh(config_page.DeviceInfo);
540
541         if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0)
542          && (config_page.ParentDevHandle != 0)) {
543                 Mpi2ConfigReply_t tmp_mpi_reply;
544                 Mpi2SasDevicePage0_t parent_config_page;
545
546                 if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply,
547                      &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
548                      le16toh(config_page.ParentDevHandle)))) {
549                         printf("%s: error reading SAS device %#x page0\n",
550                                __func__, le16toh(config_page.ParentDevHandle));
551                 } else {
552                         parent_sas_address = parent_config_page.SASAddress.High;
553                         parent_sas_address = (parent_sas_address << 32) |
554                                 parent_config_page.SASAddress.Low;
555                         parent_devinfo = le32toh(parent_config_page.DeviceInfo);
556                 }
557         }
558         /* TODO Check proper endianess */
559         sas_address = config_page.SASAddress.High;
560         sas_address = (sas_address << 32) | 
561             config_page.SASAddress.Low;
562
563         if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE)
564                     == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
565                 if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
566                         ret = mpssas_get_sas_address_for_sata_disk(sc,
567                             &sata_sas_address, handle, device_info);
568                         if (!ret)
569                                 id = mps_mapping_get_sas_id(sc,
570                                     sata_sas_address, handle);
571                         else
572                                 id = mps_mapping_get_sas_id(sc,
573                                     sas_address, handle);
574                 } else
575                         id = mps_mapping_get_sas_id(sc, sas_address,
576                             handle);
577         } else
578                 id = mps_mapping_get_sas_id(sc, sas_address, handle);
579
580         if (id == MPS_MAP_BAD_ID) {
581                 printf("failure at %s:%d/%s()! Could not get ID for device "
582                     "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
583                     handle);
584                 error = ENXIO;
585                 goto out;
586         }
587         mps_vprintf(sc, "SAS Address from SAS device page0 = %jx\n",
588             sas_address);
589         targ = &sassc->targets[id];
590         targ->devinfo = device_info;
591         targ->devname = le32toh(config_page.DeviceName.High);
592         targ->devname = (targ->devname << 32) | 
593             le32toh(config_page.DeviceName.Low);
594         targ->encl_handle = le16toh(config_page.EnclosureHandle);
595         targ->encl_slot = le16toh(config_page.Slot);
596         targ->handle = handle;
597         targ->parent_handle = le16toh(config_page.ParentDevHandle);
598         targ->sasaddr = mps_to_u64(&config_page.SASAddress);
599         targ->parent_sasaddr = le64toh(parent_sas_address);
600         targ->parent_devinfo = parent_devinfo;
601         targ->tid = id;
602         targ->linkrate = (linkrate>>4);
603         targ->flags = 0;
604         TAILQ_INIT(&targ->commands);
605         TAILQ_INIT(&targ->timedout_commands);
606         SLIST_INIT(&targ->luns);
607         mps_describe_devinfo(targ->devinfo, devstring, 80);
608         mps_vprintf(sc, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring,
609             mps_describe_table(mps_linkrate_names, targ->linkrate),
610             targ->handle, targ->encl_handle, targ->encl_slot);
611         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
612                 mpssas_rescan_target(sc, targ);
613         mps_vprintf(sc, "Target id 0x%x added\n", targ->tid);
614 out:
615         mpssas_startup_decrement(sassc);
616         return (error);
617         
618 }
619         
620 int
621 mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
622     u64 *sas_address, u16 handle, u32 device_info)
623 {
624         Mpi2SataPassthroughReply_t mpi_reply;
625         int i, rc, try_count;
626         u32 *bufferptr;
627         union _sata_sas_address hash_address;
628         struct _ata_identify_device_data ata_identify;
629         u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
630         u32 ioc_status;
631         u8 sas_status;
632
633         memset(&ata_identify, 0, sizeof(ata_identify));
634         try_count = 0;
635         do {
636                 rc = mpssas_get_sata_identify(sc, handle, &mpi_reply,
637                     (char *)&ata_identify, sizeof(ata_identify), device_info);
638                 try_count++;
639                 ioc_status = le16toh(mpi_reply.IOCStatus)
640                     & MPI2_IOCSTATUS_MASK;
641                 sas_status = mpi_reply.SASStatus;
642         } while ((rc == -EAGAIN || ioc_status || sas_status) &&
643             (try_count < 5));
644
645         if (rc == 0 && !ioc_status && !sas_status) {
646                 mps_dprint(sc, MPS_INFO, "%s: got SATA identify successfully "
647                            "for handle = 0x%x with try_count = %d\n",
648                            __func__, handle, try_count);
649         } else {
650                 mps_dprint(sc, MPS_INFO, "%s: handle = 0x%x failed\n",
651                            __func__, handle);
652                 return -1;
653         }
654         /* Copy & byteswap the 40 byte model number to a buffer */
655         for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
656                 buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
657                 buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
658         }
659         /* Copy & byteswap the 20 byte serial number to a buffer */
660         for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
661                 buffer[MPT2SAS_MN_LEN + i] =
662                         ((u8 *)ata_identify.serial_number)[i + 1];
663                 buffer[MPT2SAS_MN_LEN + i + 1] =
664                         ((u8 *)ata_identify.serial_number)[i];
665         }
666         bufferptr = (u32 *)buffer;
667         /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
668          * so loop through the first 56 bytes (7*8),
669          * and then add in the last dword.
670          */
671         hash_address.word.low  = 0;
672         hash_address.word.high = 0;
673         for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
674                 hash_address.word.low += *bufferptr;
675                 bufferptr++;
676                 hash_address.word.high += *bufferptr;
677                 bufferptr++;
678         }
679         /* Add the last dword */
680         hash_address.word.low += *bufferptr;
681         /* Make sure the hash doesn't start with 5, because it could clash
682          * with a SAS address. Change 5 to a D.
683          */
684         if ((hash_address.word.high & 0x000000F0) == (0x00000050))
685                 hash_address.word.high |= 0x00000080;
686         *sas_address = (u64)hash_address.wwid[0] << 56 |
687             (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
688             (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
689             (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] <<  8 |
690             (u64)hash_address.wwid[7];
691         return 0;
692 }
693
694 static int
695 mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
696     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
697 {
698         Mpi2SataPassthroughRequest_t *mpi_request;
699         Mpi2SataPassthroughReply_t *reply;
700         struct mps_command *cm;
701         char *buffer;
702         int error = 0;
703
704         buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO);
705         if (!buffer)
706                 return ENOMEM;
707
708         if ((cm = mps_alloc_command(sc)) == NULL)
709                 return (EBUSY);
710         mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
711         bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
712         mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
713         mpi_request->VF_ID = 0;
714         mpi_request->DevHandle = htole16(handle);
715         mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
716             MPI2_SATA_PT_REQ_PT_FLAGS_READ);
717         mpi_request->DataLength = htole32(sz);
718         mpi_request->CommandFIS[0] = 0x27;
719         mpi_request->CommandFIS[1] = 0x80;
720         mpi_request->CommandFIS[2] =  (devinfo &
721             MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
722         cm->cm_sge = &mpi_request->SGL;
723         cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
724         cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
725         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
726         cm->cm_data = buffer;
727         cm->cm_length = htole32(sz);
728         error = mps_request_polled(sc, cm);
729         reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
730         if (error || (reply == NULL)) {
731                 /* FIXME */
732                 /* If the poll returns error then we need to do diag reset */ 
733                 printf("%s: poll for page completed with error %d",
734                     __func__, error);
735                 error = ENXIO;
736                 goto out;
737         }
738         bcopy(buffer, id_buffer, sz);
739         bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
740         if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
741             MPI2_IOCSTATUS_SUCCESS) {
742                 printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n",
743                     __func__, reply->IOCStatus);
744                 error = ENXIO;
745                 goto out;
746         }
747 out:
748         mps_free_command(sc, cm);
749         free(buffer, M_MPT2);   
750         return (error);
751 }
752
753 static int
754 mpssas_volume_add(struct mps_softc *sc, Mpi2EventIrConfigElement_t *element)
755 {
756         struct mpssas_softc *sassc;
757         struct mpssas_target *targ;
758         u64 wwid;
759         u16 handle = le16toh(element->VolDevHandle);
760         unsigned int id;
761         int error = 0;
762
763         sassc = sc->sassc;
764         mpssas_startup_increment(sassc);
765         mps_config_get_volume_wwid(sc, handle, &wwid);
766         if (!wwid) {
767                 printf("%s: invalid WWID; cannot add volume to mapping table\n",
768                     __func__);
769                 error = ENXIO;
770                 goto out;
771         }
772
773         id = mps_mapping_get_raid_id(sc, wwid, handle);
774         if (id == MPS_MAP_BAD_ID) {
775                 printf("%s: could not get ID for volume with handle 0x%04x and "
776                     "WWID 0x%016llx\n", __func__, handle,
777                     (unsigned long long)wwid);
778                 error = ENXIO;
779                 goto out;
780         }
781
782         targ = &sassc->targets[id];
783         targ->tid = id;
784         targ->handle = handle;
785         targ->devname = wwid;
786         TAILQ_INIT(&targ->commands);
787         TAILQ_INIT(&targ->timedout_commands);
788         SLIST_INIT(&targ->luns);
789         if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
790                 mpssas_rescan_target(sc, targ);
791         mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n",
792             targ->tid, wwid);
793 out:
794         mpssas_startup_decrement(sassc);
795         return (error);
796 }
797
798 /**
799  * mpssas_ir_shutdown - IR shutdown notification
800  * @sc: per adapter object
801  *
802  * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
803  * the host system is shutting down.
804  *
805  * Return nothing.
806  */
807 void
808 mpssas_ir_shutdown(struct mps_softc *sc)
809 {
810         u16 volume_mapping_flags;
811         u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
812         struct dev_mapping_table *mt_entry;
813         u32 start_idx, end_idx;
814         unsigned int id, found_volume = 0;
815         struct mps_command *cm;
816         Mpi2RaidActionRequest_t *action;
817
818         mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
819
820         /* is IR firmware build loaded? */
821         if (!sc->ir_firmware)
822                 return;
823
824         /* are there any volumes?  Look at IR target IDs. */
825         // TODO-later, this should be looked up in the RAID config structure
826         // when it is implemented.
827         volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
828             MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
829         if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
830                 start_idx = 0;
831                 if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
832                         start_idx = 1;
833         } else
834                 start_idx = sc->max_devices - sc->max_volumes;
835         end_idx = start_idx + sc->max_volumes - 1;
836
837         for (id = start_idx; id < end_idx; id++) {
838                 mt_entry = &sc->mapping_table[id];
839                 if ((mt_entry->physical_id != 0) &&
840                     (mt_entry->missing_count == 0)) {
841                         found_volume = 1;
842                         break;
843                 }
844         }
845
846         if (!found_volume)
847                 return;
848
849         if ((cm = mps_alloc_command(sc)) == NULL) {
850                 printf("%s: command alloc failed\n", __func__);
851                 return;
852         }
853
854         action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
855         action->Function = MPI2_FUNCTION_RAID_ACTION;
856         action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
857         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
858         mps_request_polled(sc, cm);
859
860         /*
861          * Don't check for reply, just leave.
862          */
863         if (cm)
864                 mps_free_command(sc, cm);
865 }