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