xref: /freebsd/sys/dev/mps/mps_sas_lsi.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1d043c564SKenneth D. Merry /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4ef065d89SStephen McConnell  * Copyright (c) 2011-2015 LSI Corp.
5ef065d89SStephen McConnell  * Copyright (c) 2013-2015 Avago Technologies
6d043c564SKenneth D. Merry  * All rights reserved.
7d043c564SKenneth D. Merry  *
8d043c564SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
9d043c564SKenneth D. Merry  * modification, are permitted provided that the following conditions
10d043c564SKenneth D. Merry  * are met:
11d043c564SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
12d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
13d043c564SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
14d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
15d043c564SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
16d043c564SKenneth D. Merry  *
17d043c564SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d043c564SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d043c564SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d043c564SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d043c564SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d043c564SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d043c564SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d043c564SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d043c564SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d043c564SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d043c564SKenneth D. Merry  * SUCH DAMAGE.
28d043c564SKenneth D. Merry  *
29ef065d89SStephen McConnell  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
30d043c564SKenneth D. Merry  */
31d043c564SKenneth D. Merry 
32d043c564SKenneth D. Merry #include <sys/cdefs.h>
33ef065d89SStephen McConnell /* Communications core for Avago Technologies (LSI) MPT2 */
34d043c564SKenneth D. Merry 
35d043c564SKenneth D. Merry /* TODO Move headers to mpsvar */
36d043c564SKenneth D. Merry #include <sys/types.h>
37d043c564SKenneth D. Merry #include <sys/param.h>
38d043c564SKenneth D. Merry #include <sys/systm.h>
39d043c564SKenneth D. Merry #include <sys/kernel.h>
40d043c564SKenneth D. Merry #include <sys/selinfo.h>
41d043c564SKenneth D. Merry #include <sys/module.h>
42d043c564SKenneth D. Merry #include <sys/bus.h>
43d043c564SKenneth D. Merry #include <sys/conf.h>
44d043c564SKenneth D. Merry #include <sys/bio.h>
45d043c564SKenneth D. Merry #include <sys/malloc.h>
46d043c564SKenneth D. Merry #include <sys/uio.h>
47d043c564SKenneth D. Merry #include <sys/sysctl.h>
48d043c564SKenneth D. Merry #include <sys/endian.h>
49d4b95382SWarner Losh #include <sys/proc.h>
50d043c564SKenneth D. Merry #include <sys/queue.h>
51d043c564SKenneth D. Merry #include <sys/kthread.h>
52d043c564SKenneth D. Merry #include <sys/taskqueue.h>
53d043c564SKenneth D. Merry #include <sys/sbuf.h>
547d147b81SSteven Hartland #include <sys/reboot.h>
55d043c564SKenneth D. Merry 
56d043c564SKenneth D. Merry #include <machine/bus.h>
57d043c564SKenneth D. Merry #include <machine/resource.h>
58d043c564SKenneth D. Merry #include <sys/rman.h>
59d043c564SKenneth D. Merry 
60d043c564SKenneth D. Merry #include <machine/stdarg.h>
61d043c564SKenneth D. Merry 
62d043c564SKenneth D. Merry #include <cam/cam.h>
63d043c564SKenneth D. Merry #include <cam/cam_ccb.h>
64d043c564SKenneth D. Merry #include <cam/cam_debug.h>
65d043c564SKenneth D. Merry #include <cam/cam_sim.h>
66d043c564SKenneth D. Merry #include <cam/cam_xpt_sim.h>
67d043c564SKenneth D. Merry #include <cam/cam_xpt_periph.h>
68d043c564SKenneth D. Merry #include <cam/cam_periph.h>
69d043c564SKenneth D. Merry #include <cam/scsi/scsi_all.h>
70d043c564SKenneth D. Merry #include <cam/scsi/scsi_message.h>
71d043c564SKenneth D. Merry 
72d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h>
73d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2.h>
74d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h>
75d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_sas.h>
76d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h>
77d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_init.h>
78d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_raid.h>
79d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_tool.h>
80d043c564SKenneth D. Merry #include <dev/mps/mps_ioctl.h>
81d043c564SKenneth D. Merry #include <dev/mps/mpsvar.h>
82d043c564SKenneth D. Merry #include <dev/mps/mps_table.h>
83d043c564SKenneth D. Merry #include <dev/mps/mps_sas.h>
84d043c564SKenneth D. Merry 
85d043c564SKenneth D. Merry /* For Hashed SAS Address creation for SATA Drives */
86d043c564SKenneth D. Merry #define MPT2SAS_SN_LEN 20
87d043c564SKenneth D. Merry #define MPT2SAS_MN_LEN 40
88d043c564SKenneth D. Merry 
89d043c564SKenneth D. Merry struct mps_fw_event_work {
90d043c564SKenneth D. Merry 	u16			event;
91d043c564SKenneth D. Merry 	void			*event_data;
92d043c564SKenneth D. Merry 	TAILQ_ENTRY(mps_fw_event_work)	ev_link;
93d043c564SKenneth D. Merry };
94d043c564SKenneth D. Merry 
95d043c564SKenneth D. Merry union _sata_sas_address {
96d043c564SKenneth D. Merry 	u8 wwid[8];
97d043c564SKenneth D. Merry 	struct {
98d043c564SKenneth D. Merry 		u32 high;
99d043c564SKenneth D. Merry 		u32 low;
100d043c564SKenneth D. Merry 	} word;
101d043c564SKenneth D. Merry };
102d043c564SKenneth D. Merry 
103d043c564SKenneth D. Merry /*
104d043c564SKenneth D. Merry  * define the IDENTIFY DEVICE structure
105d043c564SKenneth D. Merry  */
106d043c564SKenneth D. Merry struct _ata_identify_device_data {
107d043c564SKenneth D. Merry 	u16 reserved1[10];	/* 0-9 */
108d043c564SKenneth D. Merry 	u16 serial_number[10];	/* 10-19 */
109d043c564SKenneth D. Merry 	u16 reserved2[7];	/* 20-26 */
110d043c564SKenneth D. Merry 	u16 model_number[20];	/* 27-46*/
111ef065d89SStephen McConnell 	u16 reserved3[170];	/* 47-216 */
112ef065d89SStephen McConnell 	u16 rotational_speed;	/* 217 */
113ef065d89SStephen McConnell 	u16 reserved4[38];	/* 218-255 */
114d043c564SKenneth D. Merry };
115653c521fSKenneth D. Merry static u32 event_count;
116d043c564SKenneth D. Merry static void mpssas_fw_work(struct mps_softc *sc,
117d043c564SKenneth D. Merry     struct mps_fw_event_work *fw_event);
118d043c564SKenneth D. Merry static void mpssas_fw_event_free(struct mps_softc *,
119d043c564SKenneth D. Merry     struct mps_fw_event_work *);
120d043c564SKenneth D. Merry static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate);
121d043c564SKenneth D. Merry static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
122d043c564SKenneth D. Merry     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
123d043c564SKenneth D. Merry     u32 devinfo);
124175ad3d0SKenneth D. Merry static void mpssas_ata_id_complete(struct mps_softc *, struct mps_command *);
12586312e46SConrad Meyer static void mpssas_ata_id_timeout(struct mps_softc *, struct mps_command *);
126d043c564SKenneth D. Merry int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
127ef065d89SStephen McConnell     u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD);
128d043c564SKenneth D. Merry static int mpssas_volume_add(struct mps_softc *sc,
129653c521fSKenneth D. Merry     u16 handle);
1307d147b81SSteven Hartland static void mpssas_SSU_to_SATA_devices(struct mps_softc *sc, int howto);
1317571e7f6SSteven Hartland static void mpssas_stop_unit_done(struct cam_periph *periph,
1327571e7f6SSteven Hartland     union ccb *done_ccb);
133d043c564SKenneth D. Merry 
134d043c564SKenneth D. Merry void
mpssas_evt_handler(struct mps_softc * sc,uintptr_t data,MPI2_EVENT_NOTIFICATION_REPLY * event)135d043c564SKenneth D. Merry mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
136d043c564SKenneth D. Merry     MPI2_EVENT_NOTIFICATION_REPLY *event)
137d043c564SKenneth D. Merry {
138d043c564SKenneth D. Merry 	struct mps_fw_event_work *fw_event;
139d043c564SKenneth D. Merry 	u16 sz;
140d043c564SKenneth D. Merry 
141d043c564SKenneth D. Merry 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
142055e2653SScott Long 	MPS_DPRINT_EVENT(sc, sas, event);
143d043c564SKenneth D. Merry 	mpssas_record_event(sc, event);
144d043c564SKenneth D. Merry 
145d043c564SKenneth D. Merry 	fw_event = malloc(sizeof(struct mps_fw_event_work), M_MPT2,
146d043c564SKenneth D. Merry 	     M_ZERO|M_NOWAIT);
147d043c564SKenneth D. Merry 	if (!fw_event) {
148d043c564SKenneth D. Merry 		printf("%s: allocate failed for fw_event\n", __func__);
149d043c564SKenneth D. Merry 		return;
150d043c564SKenneth D. Merry 	}
151d043c564SKenneth D. Merry 	sz = le16toh(event->EventDataLength) * 4;
152d043c564SKenneth D. Merry 	fw_event->event_data = malloc(sz, M_MPT2, M_ZERO|M_NOWAIT);
153d043c564SKenneth D. Merry 	if (!fw_event->event_data) {
154d043c564SKenneth D. Merry 		printf("%s: allocate failed for event_data\n", __func__);
155d043c564SKenneth D. Merry 		free(fw_event, M_MPT2);
156d043c564SKenneth D. Merry 		return;
157d043c564SKenneth D. Merry 	}
158d043c564SKenneth D. Merry 
159d043c564SKenneth D. Merry 	bcopy(event->EventData, fw_event->event_data, sz);
160d043c564SKenneth D. Merry 	fw_event->event = event->Event;
161d043c564SKenneth D. Merry 	if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
162d043c564SKenneth D. Merry 	    event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
163d043c564SKenneth D. Merry 	    event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
164d043c564SKenneth D. Merry 	    sc->track_mapping_events)
165d043c564SKenneth D. Merry 		sc->pending_map_events++;
166d043c564SKenneth D. Merry 
167d043c564SKenneth D. Merry 	/*
168d043c564SKenneth D. Merry 	 * When wait_for_port_enable flag is set, make sure that all the events
169d043c564SKenneth D. Merry 	 * are processed. Increment the startup_refcount and decrement it after
170d043c564SKenneth D. Merry 	 * events are processed.
171d043c564SKenneth D. Merry 	 */
172d043c564SKenneth D. Merry 	if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
173d043c564SKenneth D. Merry 	    event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
174d043c564SKenneth D. Merry 	    sc->wait_for_port_enable)
175d043c564SKenneth D. Merry 		mpssas_startup_increment(sc->sassc);
176d043c564SKenneth D. Merry 
177d043c564SKenneth D. Merry 	TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
178d043c564SKenneth D. Merry 	taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
179d043c564SKenneth D. Merry 
180d043c564SKenneth D. Merry }
181d043c564SKenneth D. Merry 
182d043c564SKenneth D. Merry static void
mpssas_fw_event_free(struct mps_softc * sc,struct mps_fw_event_work * fw_event)183d043c564SKenneth D. Merry mpssas_fw_event_free(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
184d043c564SKenneth D. Merry {
185d043c564SKenneth D. Merry 
186d043c564SKenneth D. Merry 	free(fw_event->event_data, M_MPT2);
187d043c564SKenneth D. Merry 	free(fw_event, M_MPT2);
188d043c564SKenneth D. Merry }
189d043c564SKenneth D. Merry 
190d043c564SKenneth D. Merry /**
191d043c564SKenneth D. Merry  * _mps_fw_work - delayed task for processing firmware events
192d043c564SKenneth D. Merry  * @sc: per adapter object
193d043c564SKenneth D. Merry  * @fw_event: The fw_event_work object
194d043c564SKenneth D. Merry  * Context: user.
195d043c564SKenneth D. Merry  *
196d043c564SKenneth D. Merry  * Return nothing.
197d043c564SKenneth D. Merry  */
198d043c564SKenneth D. Merry static void
mpssas_fw_work(struct mps_softc * sc,struct mps_fw_event_work * fw_event)199d043c564SKenneth D. Merry mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
200d043c564SKenneth D. Merry {
201d043c564SKenneth D. Merry 	struct mpssas_softc *sassc;
202d043c564SKenneth D. Merry 	sassc = sc->sassc;
203d043c564SKenneth D. Merry 
2041610f95cSScott Long 	mps_dprint(sc, MPS_EVENT, "(%d)->(%s) Working on  Event: [%x]\n",
205653c521fSKenneth D. Merry 			event_count++,__func__,fw_event->event);
206d043c564SKenneth D. Merry 	switch (fw_event->event) {
207d043c564SKenneth D. Merry 	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
208d043c564SKenneth D. Merry 	{
209d043c564SKenneth D. Merry 		MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
210d043c564SKenneth D. Merry 		MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
211d043c564SKenneth D. Merry 		int i;
212d043c564SKenneth D. Merry 
213d043c564SKenneth D. Merry 		data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
214d043c564SKenneth D. Merry 		    fw_event->event_data;
215d043c564SKenneth D. Merry 
216d043c564SKenneth D. Merry 		mps_mapping_topology_change_event(sc, fw_event->event_data);
217d043c564SKenneth D. Merry 
218d043c564SKenneth D. Merry 		for (i = 0; i < data->NumEntries; i++) {
219d043c564SKenneth D. Merry 			phy = &data->PHY[i];
220d043c564SKenneth D. Merry 			switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
221d043c564SKenneth D. Merry 			case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
222d043c564SKenneth D. Merry 				if (mpssas_add_device(sc,
223635e58c7SStephen McConnell 				    le16toh(phy->AttachedDevHandle),
224635e58c7SStephen McConnell 				    phy->LinkRate)){
225635e58c7SStephen McConnell 					mps_dprint(sc, MPS_ERROR, "%s: "
226635e58c7SStephen McConnell 					    "failed to add device with handle "
227635e58c7SStephen McConnell 					    "0x%x\n", __func__,
228be4aa869SKenneth D. Merry 					    le16toh(phy->AttachedDevHandle));
229be4aa869SKenneth D. Merry 					mpssas_prepare_remove(sassc, le16toh(
230be4aa869SKenneth D. Merry 						phy->AttachedDevHandle));
231d043c564SKenneth D. Merry 				}
232d043c564SKenneth D. Merry 				break;
233d043c564SKenneth D. Merry 			case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
234be4aa869SKenneth D. Merry 				mpssas_prepare_remove(sassc,le16toh(
235be4aa869SKenneth D. Merry 					phy->AttachedDevHandle));
236d043c564SKenneth D. Merry 				break;
237d043c564SKenneth D. Merry 			case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
238d043c564SKenneth D. Merry 			case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
239d043c564SKenneth D. Merry 			case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
240d043c564SKenneth D. Merry 			default:
241d043c564SKenneth D. Merry 				break;
242d043c564SKenneth D. Merry 			}
243d043c564SKenneth D. Merry 		}
244d043c564SKenneth D. Merry 		/*
245d043c564SKenneth D. Merry 		 * refcount was incremented for this event in
246d043c564SKenneth D. Merry 		 * mpssas_evt_handler.  Decrement it here because the event has
247d043c564SKenneth D. Merry 		 * been processed.
248d043c564SKenneth D. Merry 		 */
249d043c564SKenneth D. Merry 		mpssas_startup_decrement(sassc);
250d043c564SKenneth D. Merry 		break;
251d043c564SKenneth D. Merry 	}
252d043c564SKenneth D. Merry 	case MPI2_EVENT_SAS_DISCOVERY:
253d043c564SKenneth D. Merry 	{
254d043c564SKenneth D. Merry 		MPI2_EVENT_DATA_SAS_DISCOVERY *data;
255d043c564SKenneth D. Merry 
256d043c564SKenneth D. Merry 		data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data;
257d043c564SKenneth D. Merry 
258d043c564SKenneth D. Merry 		if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
259d043c564SKenneth D. Merry 			mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n");
260d043c564SKenneth D. Merry 		if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
261d043c564SKenneth D. Merry 			mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n");
262d043c564SKenneth D. Merry 			sassc->flags &= ~MPSSAS_IN_DISCOVERY;
263d043c564SKenneth D. Merry 			mpssas_discovery_end(sassc);
264d043c564SKenneth D. Merry 		}
265d043c564SKenneth D. Merry 		break;
266d043c564SKenneth D. Merry 	}
267d043c564SKenneth D. Merry 	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
268d043c564SKenneth D. Merry 	{
269d043c564SKenneth D. Merry 		mps_mapping_enclosure_dev_status_change_event(sc,
270d043c564SKenneth D. Merry 		    fw_event->event_data);
271d043c564SKenneth D. Merry 		break;
272d043c564SKenneth D. Merry 	}
273d043c564SKenneth D. Merry 	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
274d043c564SKenneth D. Merry 	{
275d043c564SKenneth D. Merry 		Mpi2EventIrConfigElement_t *element;
276d043c564SKenneth D. Merry 		int i;
277d043c564SKenneth D. Merry 		u8 foreign_config;
278d043c564SKenneth D. Merry 		Mpi2EventDataIrConfigChangeList_t *event_data;
279d043c564SKenneth D. Merry 		struct mpssas_target *targ;
280d043c564SKenneth D. Merry 		unsigned int id;
281d043c564SKenneth D. Merry 
282d043c564SKenneth D. Merry 		event_data = fw_event->event_data;
283d043c564SKenneth D. Merry 		foreign_config = (le32toh(event_data->Flags) &
284d043c564SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
285d043c564SKenneth D. Merry 
286d043c564SKenneth D. Merry 		element =
287d043c564SKenneth D. Merry 		    (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
288635e58c7SStephen McConnell 		id = mps_mapping_get_raid_tid_from_handle(sc,
289635e58c7SStephen McConnell 		    element->VolDevHandle);
290d043c564SKenneth D. Merry 
291d043c564SKenneth D. Merry 		mps_mapping_ir_config_change_event(sc, event_data);
292d043c564SKenneth D. Merry 
293d043c564SKenneth D. Merry 		for (i = 0; i < event_data->NumElements; i++, element++) {
294d043c564SKenneth D. Merry 			switch (element->ReasonCode) {
295d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
296d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_ADDED:
297d043c564SKenneth D. Merry 				if (!foreign_config) {
298635e58c7SStephen McConnell 					if (mpssas_volume_add(sc,
299635e58c7SStephen McConnell 					    le16toh(element->VolDevHandle))){
300d043c564SKenneth D. Merry 						printf("%s: failed to add RAID "
301d043c564SKenneth D. Merry 						    "volume with handle 0x%x\n",
302d043c564SKenneth D. Merry 						    __func__, le16toh(element->
303d043c564SKenneth D. Merry 						    VolDevHandle));
304d043c564SKenneth D. Merry 					}
305d043c564SKenneth D. Merry 				}
306d043c564SKenneth D. Merry 				break;
307d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
308d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
309d043c564SKenneth D. Merry 				/*
310d043c564SKenneth D. Merry 				 * Rescan after volume is deleted or removed.
311d043c564SKenneth D. Merry 				 */
312d043c564SKenneth D. Merry 				if (!foreign_config) {
313d043c564SKenneth D. Merry 					if (id == MPS_MAP_BAD_ID) {
314d043c564SKenneth D. Merry 						printf("%s: could not get ID "
315d043c564SKenneth D. Merry 						    "for volume with handle "
316d043c564SKenneth D. Merry 						    "0x%04x\n", __func__,
317be4aa869SKenneth D. Merry 						    le16toh(element->VolDevHandle));
318d043c564SKenneth D. Merry 						break;
319d043c564SKenneth D. Merry 					}
320d043c564SKenneth D. Merry 
321d043c564SKenneth D. Merry 					targ = &sassc->targets[id];
322d043c564SKenneth D. Merry 					targ->handle = 0x0;
323d043c564SKenneth D. Merry 					targ->encl_slot = 0x0;
324d043c564SKenneth D. Merry 					targ->encl_handle = 0x0;
325d043c564SKenneth D. Merry 					targ->exp_dev_handle = 0x0;
326d043c564SKenneth D. Merry 					targ->phy_num = 0x0;
327d043c564SKenneth D. Merry 					targ->linkrate = 0x0;
328d043c564SKenneth D. Merry 					mpssas_rescan_target(sc, targ);
329d043c564SKenneth D. Merry 					printf("RAID target id 0x%x removed\n",
330d043c564SKenneth D. Merry 					    targ->tid);
331d043c564SKenneth D. Merry 				}
332d043c564SKenneth D. Merry 				break;
333d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
334653c521fSKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_HIDE:
335d043c564SKenneth D. Merry 				/*
336d043c564SKenneth D. Merry 				 * Phys Disk of a volume has been created.  Hide
337d043c564SKenneth D. Merry 				 * it from the OS.
338d043c564SKenneth D. Merry 				 */
339635e58c7SStephen McConnell 				targ = mpssas_find_target_by_handle(sassc, 0,
340635e58c7SStephen McConnell 				    element->PhysDiskDevHandle);
341653c521fSKenneth D. Merry 				if (targ == NULL)
342653c521fSKenneth D. Merry 					break;
343653c521fSKenneth D. Merry 
344635e58c7SStephen McConnell 				/*
345635e58c7SStephen McConnell 				 * Set raid component flags only if it is not
346635e58c7SStephen McConnell 				 * WD. OR WrapDrive with
347635e58c7SStephen McConnell 				 * WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in
348635e58c7SStephen McConnell 				 * NVRAM
349be4aa869SKenneth D. Merry 				 */
350be4aa869SKenneth D. Merry 				if((!sc->WD_available) ||
351be4aa869SKenneth D. Merry 				((sc->WD_available &&
352be4aa869SKenneth D. Merry 				(sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) ||
353be4aa869SKenneth D. Merry 				(sc->WD_valid_config && (sc->WD_hide_expose ==
354be4aa869SKenneth D. Merry 				MPS_WD_HIDE_IF_VOLUME)))) {
355653c521fSKenneth D. Merry 					targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
356be4aa869SKenneth D. Merry 				}
357653c521fSKenneth D. Merry 				mpssas_rescan_target(sc, targ);
358653c521fSKenneth D. Merry 
359d043c564SKenneth D. Merry 				break;
360d043c564SKenneth D. Merry 			case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
361d043c564SKenneth D. Merry 				/*
362d043c564SKenneth D. Merry 				 * Phys Disk of a volume has been deleted.
363d043c564SKenneth D. Merry 				 * Expose it to the OS.
364d043c564SKenneth D. Merry 				 */
365d043c564SKenneth D. Merry 				if (mpssas_add_device(sc,
366be4aa869SKenneth D. Merry 				    le16toh(element->PhysDiskDevHandle), 0)){
367d043c564SKenneth D. Merry 					printf("%s: failed to add device with "
368d043c564SKenneth D. Merry 					    "handle 0x%x\n", __func__,
369be4aa869SKenneth D. Merry 					    le16toh(element->PhysDiskDevHandle));
370be4aa869SKenneth D. Merry 					mpssas_prepare_remove(sassc, le16toh(element->
371be4aa869SKenneth D. Merry 					    PhysDiskDevHandle));
372d043c564SKenneth D. Merry 				}
373d043c564SKenneth D. Merry 				break;
374d043c564SKenneth D. Merry 			}
375d043c564SKenneth D. Merry 		}
376d043c564SKenneth D. Merry 		/*
377d043c564SKenneth D. Merry 		 * refcount was incremented for this event in
378d043c564SKenneth D. Merry 		 * mpssas_evt_handler.  Decrement it here because the event has
379d043c564SKenneth D. Merry 		 * been processed.
380d043c564SKenneth D. Merry 		 */
381d043c564SKenneth D. Merry 		mpssas_startup_decrement(sassc);
382d043c564SKenneth D. Merry 		break;
383d043c564SKenneth D. Merry 	}
384d043c564SKenneth D. Merry 	case MPI2_EVENT_IR_VOLUME:
385d043c564SKenneth D. Merry 	{
386d043c564SKenneth D. Merry 		Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
387d043c564SKenneth D. Merry 
388d043c564SKenneth D. Merry 		/*
389d043c564SKenneth D. Merry 		 * Informational only.
390d043c564SKenneth D. Merry 		 */
3911610f95cSScott Long 		mps_dprint(sc, MPS_EVENT, "Received IR Volume event:\n");
392d043c564SKenneth D. Merry 		switch (event_data->ReasonCode) {
393d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
3941610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Volume Settings "
395d043c564SKenneth D. Merry   			    "changed from 0x%x to 0x%x for Volome with "
396be4aa869SKenneth D. Merry  			    "handle 0x%x", le32toh(event_data->PreviousValue),
397be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue),
398be4aa869SKenneth D. Merry  			    le16toh(event_data->VolDevHandle));
399d043c564SKenneth D. Merry 			break;
400d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
4011610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Volume Status "
402d043c564SKenneth D. Merry   			    "changed from 0x%x to 0x%x for Volome with "
403be4aa869SKenneth D. Merry  			    "handle 0x%x", le32toh(event_data->PreviousValue),
404be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue),
405be4aa869SKenneth D. Merry  			    le16toh(event_data->VolDevHandle));
406d043c564SKenneth D. Merry 			break;
407d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
4081610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Volume State "
409d043c564SKenneth D. Merry   			    "changed from 0x%x to 0x%x for Volome with "
410be4aa869SKenneth D. Merry  			    "handle 0x%x", le32toh(event_data->PreviousValue),
411be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue),
412be4aa869SKenneth D. Merry  			    le16toh(event_data->VolDevHandle));
413653c521fSKenneth D. Merry 				u32 state;
414653c521fSKenneth D. Merry 				struct mpssas_target *targ;
415653c521fSKenneth D. Merry 				state = le32toh(event_data->NewValue);
416653c521fSKenneth D. Merry 				switch (state) {
417653c521fSKenneth D. Merry 				case MPI2_RAID_VOL_STATE_MISSING:
418653c521fSKenneth D. Merry 				case MPI2_RAID_VOL_STATE_FAILED:
419653c521fSKenneth D. Merry 					mpssas_prepare_volume_remove(sassc, event_data->
420653c521fSKenneth D. Merry 							VolDevHandle);
421653c521fSKenneth D. Merry 					break;
422653c521fSKenneth D. Merry 
423653c521fSKenneth D. Merry 				case MPI2_RAID_VOL_STATE_ONLINE:
424653c521fSKenneth D. Merry 				case MPI2_RAID_VOL_STATE_DEGRADED:
425653c521fSKenneth D. Merry 				case MPI2_RAID_VOL_STATE_OPTIMAL:
426653c521fSKenneth D. Merry 					targ = mpssas_find_target_by_handle(sassc, 0, event_data->VolDevHandle);
427653c521fSKenneth D. Merry 					if (targ) {
428653c521fSKenneth D. Merry 						printf("%s %d: Volume handle 0x%x is already added \n",
429653c521fSKenneth D. Merry 							       	__func__, __LINE__ , event_data->VolDevHandle);
430653c521fSKenneth D. Merry 						break;
431653c521fSKenneth D. Merry 					}
432653c521fSKenneth D. Merry 					if (mpssas_volume_add(sc, le16toh(event_data->VolDevHandle))) {
433653c521fSKenneth D. Merry 						printf("%s: failed to add RAID "
434653c521fSKenneth D. Merry 							"volume with handle 0x%x\n",
435653c521fSKenneth D. Merry 							__func__, le16toh(event_data->
436653c521fSKenneth D. Merry 							VolDevHandle));
437653c521fSKenneth D. Merry 					}
438653c521fSKenneth D. Merry 					break;
439653c521fSKenneth D. Merry 				default:
440653c521fSKenneth D. Merry 					break;
441653c521fSKenneth D. Merry 				}
442d043c564SKenneth D. Merry 			break;
443d043c564SKenneth D. Merry 		default:
444d043c564SKenneth D. Merry 			break;
445d043c564SKenneth D. Merry 		}
446d043c564SKenneth D. Merry 		break;
447d043c564SKenneth D. Merry 	}
448d043c564SKenneth D. Merry 	case MPI2_EVENT_IR_PHYSICAL_DISK:
449d043c564SKenneth D. Merry 	{
450d043c564SKenneth D. Merry 		Mpi2EventDataIrPhysicalDisk_t *event_data =
451d043c564SKenneth D. Merry 		    fw_event->event_data;
452653c521fSKenneth D. Merry 		struct mpssas_target *targ;
453d043c564SKenneth D. Merry 
454d043c564SKenneth D. Merry 		/*
455d043c564SKenneth D. Merry 		 * Informational only.
456d043c564SKenneth D. Merry 		 */
4571610f95cSScott Long 		mps_dprint(sc, MPS_EVENT, "Received IR Phys Disk event:\n");
458d043c564SKenneth D. Merry 		switch (event_data->ReasonCode) {
459d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
4601610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Phys Disk Settings "
461d043c564SKenneth D. Merry   			    "changed from 0x%x to 0x%x for Phys Disk Number "
462d043c564SKenneth D. Merry   			    "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
463be4aa869SKenneth D. Merry  			    "%d", le32toh(event_data->PreviousValue),
464be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue),
465be4aa869SKenneth D. Merry  				event_data->PhysDiskNum,
466be4aa869SKenneth D. Merry  			    le16toh(event_data->PhysDiskDevHandle),
467be4aa869SKenneth D. Merry  			    le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
468d043c564SKenneth D. Merry 			break;
469d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
4701610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Phys Disk Status changed "
471d043c564SKenneth D. Merry   			    "from 0x%x to 0x%x for Phys Disk Number %d and "
472be4aa869SKenneth D. Merry   			    "handle 0x%x at Enclosure handle 0x%x, Slot %d",
473be4aa869SKenneth D. Merry  				le32toh(event_data->PreviousValue),
474be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue), event_data->PhysDiskNum,
475be4aa869SKenneth D. Merry  			    le16toh(event_data->PhysDiskDevHandle),
476be4aa869SKenneth D. Merry  			    le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
477d043c564SKenneth D. Merry 			break;
478d043c564SKenneth D. Merry 		case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
4791610f95cSScott Long   			mps_dprint(sc, MPS_EVENT, "   Phys Disk State changed "
480d043c564SKenneth D. Merry   			    "from 0x%x to 0x%x for Phys Disk Number %d and "
481be4aa869SKenneth D. Merry   			    "handle 0x%x at Enclosure handle 0x%x, Slot %d",
482be4aa869SKenneth D. Merry  				le32toh(event_data->PreviousValue),
483be4aa869SKenneth D. Merry  			    le32toh(event_data->NewValue), event_data->PhysDiskNum,
484be4aa869SKenneth D. Merry  			    le16toh(event_data->PhysDiskDevHandle),
485be4aa869SKenneth D. Merry  			    le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
486653c521fSKenneth D. Merry 			switch (event_data->NewValue) {
487653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_ONLINE:
488653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_DEGRADED:
489653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_REBUILDING:
490653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_OPTIMAL:
491653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_HOT_SPARE:
492653c521fSKenneth D. Merry 					targ = mpssas_find_target_by_handle(sassc, 0,
493653c521fSKenneth D. Merry 							event_data->PhysDiskDevHandle);
494653c521fSKenneth D. Merry 					if (targ) {
495be4aa869SKenneth D. Merry 						if(!sc->WD_available) {
496653c521fSKenneth D. Merry 							targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
497653c521fSKenneth D. Merry 							printf("%s %d: Found Target for handle 0x%x.  \n",
498653c521fSKenneth D. Merry 							__func__, __LINE__ , event_data->PhysDiskDevHandle);
499be4aa869SKenneth D. Merry 						} else if ((sc->WD_available &&
500be4aa869SKenneth D. Merry 							(sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) ||
501be4aa869SKenneth D. Merry         						(sc->WD_valid_config && (sc->WD_hide_expose ==
502be4aa869SKenneth D. Merry         						MPS_WD_HIDE_IF_VOLUME))) {
503be4aa869SKenneth D. Merry 							targ->flags |= MPS_TARGET_FLAGS_RAID_COMPONENT;
504be4aa869SKenneth D. Merry 							printf("%s %d: WD: Found Target for handle 0x%x.  \n",
505be4aa869SKenneth D. Merry 							__func__, __LINE__ , event_data->PhysDiskDevHandle);
506be4aa869SKenneth D. Merry 						}
507653c521fSKenneth D. Merry  					}
508d043c564SKenneth D. Merry 				break;
509653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_OFFLINE:
510653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
511653c521fSKenneth D. Merry 				case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
512653c521fSKenneth D. Merry 				default:
513653c521fSKenneth D. Merry 					targ = mpssas_find_target_by_handle(sassc, 0,
514653c521fSKenneth D. Merry 							event_data->PhysDiskDevHandle);
515653c521fSKenneth D. Merry 					if (targ) {
516653c521fSKenneth D. Merry 						targ->flags |= ~MPS_TARGET_FLAGS_RAID_COMPONENT;
517653c521fSKenneth D. Merry 						printf("%s %d: Found Target for handle 0x%x.  \n",
518653c521fSKenneth D. Merry 						__func__, __LINE__ , event_data->PhysDiskDevHandle);
519653c521fSKenneth D. Merry 					}
520653c521fSKenneth D. Merry 				break;
521653c521fSKenneth D. Merry 			}
522d043c564SKenneth D. Merry 		default:
523d043c564SKenneth D. Merry 			break;
524d043c564SKenneth D. Merry 		}
525d043c564SKenneth D. Merry 		break;
526d043c564SKenneth D. Merry 	}
527d043c564SKenneth D. Merry 	case MPI2_EVENT_IR_OPERATION_STATUS:
528d043c564SKenneth D. Merry 	{
529d043c564SKenneth D. Merry 		Mpi2EventDataIrOperationStatus_t *event_data =
530d043c564SKenneth D. Merry 		    fw_event->event_data;
531d043c564SKenneth D. Merry 
532d043c564SKenneth D. Merry 		/*
533d043c564SKenneth D. Merry 		 * Informational only.
534d043c564SKenneth D. Merry 		 */
5351610f95cSScott Long 		mps_dprint(sc, MPS_EVENT, "Received IR Op Status event:\n");
5361610f95cSScott Long 		mps_dprint(sc, MPS_EVENT, "   RAID Operation of %d is %d "
537d043c564SKenneth D. Merry 		    "percent complete for Volume with handle 0x%x",
538d043c564SKenneth D. Merry 		    event_data->RAIDOperation, event_data->PercentComplete,
539be4aa869SKenneth D. Merry 		    le16toh(event_data->VolDevHandle));
540d043c564SKenneth D. Merry 		break;
541d043c564SKenneth D. Merry 	}
542d043c564SKenneth D. Merry 	case MPI2_EVENT_LOG_ENTRY_ADDED:
543d043c564SKenneth D. Merry 	{
544d043c564SKenneth D. Merry 		pMpi2EventDataLogEntryAdded_t	logEntry;
545d043c564SKenneth D. Merry 		uint16_t			logQualifier;
546d043c564SKenneth D. Merry 		uint8_t				logCode;
547d043c564SKenneth D. Merry 
548d043c564SKenneth D. Merry 		logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data;
549d043c564SKenneth D. Merry 		logQualifier = logEntry->LogEntryQualifier;
550d043c564SKenneth D. Merry 
551d043c564SKenneth D. Merry 		if (logQualifier == MPI2_WD_LOG_ENTRY) {
552d043c564SKenneth D. Merry 			logCode = logEntry->LogData[0];
553d043c564SKenneth D. Merry 
554d043c564SKenneth D. Merry 			switch (logCode) {
555d043c564SKenneth D. Merry 			case MPI2_WD_SSD_THROTTLING:
556d043c564SKenneth D. Merry 				printf("WarpDrive Warning: IO Throttling has "
557d043c564SKenneth D. Merry 				    "occurred in the WarpDrive subsystem. "
558d043c564SKenneth D. Merry 				    "Check WarpDrive documentation for "
559d043c564SKenneth D. Merry 				    "additional details\n");
560d043c564SKenneth D. Merry 				break;
561d043c564SKenneth D. Merry 			case MPI2_WD_DRIVE_LIFE_WARN:
562d043c564SKenneth D. Merry 				printf("WarpDrive Warning: Program/Erase "
563d043c564SKenneth D. Merry 				    "Cycles for the WarpDrive subsystem in "
564d043c564SKenneth D. Merry 				    "degraded range. Check WarpDrive "
565d043c564SKenneth D. Merry 				    "documentation for additional details\n");
566d043c564SKenneth D. Merry 				break;
567d043c564SKenneth D. Merry 			case MPI2_WD_DRIVE_LIFE_DEAD:
568d043c564SKenneth D. Merry 				printf("WarpDrive Fatal Error: There are no "
569d043c564SKenneth D. Merry 				    "Program/Erase Cycles for the WarpDrive "
570d043c564SKenneth D. Merry 				    "subsystem. The storage device will be in "
571d043c564SKenneth D. Merry 				    "read-only mode. Check WarpDrive "
572d043c564SKenneth D. Merry 				    "documentation for additional details\n");
573d043c564SKenneth D. Merry 				break;
574d043c564SKenneth D. Merry 			case MPI2_WD_RAIL_MON_FAIL:
575d043c564SKenneth D. Merry 				printf("WarpDrive Fatal Error: The Backup Rail "
576d043c564SKenneth D. Merry 				    "Monitor has failed on the WarpDrive "
577d043c564SKenneth D. Merry 				    "subsystem. Check WarpDrive documentation "
578d043c564SKenneth D. Merry 				    "for additional details\n");
579d043c564SKenneth D. Merry 				break;
580d043c564SKenneth D. Merry 			default:
581d043c564SKenneth D. Merry 				break;
582d043c564SKenneth D. Merry 			}
583d043c564SKenneth D. Merry 		}
584d043c564SKenneth D. Merry 		break;
585d043c564SKenneth D. Merry 	}
586d043c564SKenneth D. Merry 	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
587d043c564SKenneth D. Merry 	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
588d043c564SKenneth D. Merry 	default:
589d043c564SKenneth D. Merry 		mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n",
590d043c564SKenneth D. Merry 		    fw_event->event);
591d043c564SKenneth D. Merry 		break;
592d043c564SKenneth D. Merry 	}
5931610f95cSScott Long 	mps_dprint(sc, MPS_EVENT, "(%d)->(%s) Event Free: [%x]\n",event_count,__func__, fw_event->event);
594d043c564SKenneth D. Merry 	mpssas_fw_event_free(sc, fw_event);
595d043c564SKenneth D. Merry }
596d043c564SKenneth D. Merry 
597d043c564SKenneth D. Merry void
mpssas_firmware_event_work(void * arg,int pending)598d043c564SKenneth D. Merry mpssas_firmware_event_work(void *arg, int pending)
599d043c564SKenneth D. Merry {
600d043c564SKenneth D. Merry 	struct mps_fw_event_work *fw_event;
601d043c564SKenneth D. Merry 	struct mps_softc *sc;
602d043c564SKenneth D. Merry 
603d043c564SKenneth D. Merry 	sc = (struct mps_softc *)arg;
604d043c564SKenneth D. Merry 	mps_lock(sc);
605d043c564SKenneth D. Merry 	while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) {
606d043c564SKenneth D. Merry 		TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link);
607d043c564SKenneth D. Merry 		mpssas_fw_work(sc, fw_event);
608d043c564SKenneth D. Merry 	}
609d043c564SKenneth D. Merry 	mps_unlock(sc);
610d043c564SKenneth D. Merry }
611d043c564SKenneth D. Merry 
612d043c564SKenneth D. Merry static int
mpssas_add_device(struct mps_softc * sc,u16 handle,u8 linkrate)613d043c564SKenneth D. Merry mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
614d043c564SKenneth D. Merry 	char devstring[80];
615d043c564SKenneth D. Merry 	struct mpssas_softc *sassc;
616d043c564SKenneth D. Merry 	struct mpssas_target *targ;
617d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
618d043c564SKenneth D. Merry 	Mpi2SasDevicePage0_t config_page;
619ef065d89SStephen McConnell 	uint64_t sas_address;
620d043c564SKenneth D. Merry 	uint64_t parent_sas_address = 0;
621d043c564SKenneth D. Merry 	u32 device_info, parent_devinfo = 0;
622d043c564SKenneth D. Merry 	unsigned int id;
623ef065d89SStephen McConnell 	int ret = 1, error = 0, i;
624be4aa869SKenneth D. Merry 	struct mpssas_lun *lun;
625ef065d89SStephen McConnell 	u8 is_SATA_SSD = 0;
626ef065d89SStephen McConnell 	struct mps_command *cm;
627d043c564SKenneth D. Merry 
628d043c564SKenneth D. Merry 	sassc = sc->sassc;
629d043c564SKenneth D. Merry 	mpssas_startup_increment(sassc);
630aeb9ac0dSScott Long 	if (mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page,
631aeb9ac0dSScott Long 	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle) != 0) {
632aeb9ac0dSScott Long 		mps_dprint(sc, MPS_INFO|MPS_MAPPING|MPS_FAULT,
633aeb9ac0dSScott Long 		    "Error reading SAS device %#x page0, iocstatus= 0x%x\n",
634aeb9ac0dSScott Long 		    handle, mpi_reply.IOCStatus);
635d043c564SKenneth D. Merry 		error = ENXIO;
636d043c564SKenneth D. Merry 		goto out;
637d043c564SKenneth D. Merry 	}
638d043c564SKenneth D. Merry 
639d043c564SKenneth D. Merry 	device_info = le32toh(config_page.DeviceInfo);
640d043c564SKenneth D. Merry 
641d043c564SKenneth D. Merry 	if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0)
642be4aa869SKenneth D. Merry 	 && (le16toh(config_page.ParentDevHandle) != 0)) {
643d043c564SKenneth D. Merry 		Mpi2ConfigReply_t tmp_mpi_reply;
644d043c564SKenneth D. Merry 		Mpi2SasDevicePage0_t parent_config_page;
645d043c564SKenneth D. Merry 
646aeb9ac0dSScott Long 		if (mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply,
647d043c564SKenneth D. Merry 		    &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
648aeb9ac0dSScott Long 		    le16toh(config_page.ParentDevHandle)) != 0) {
649757ff642SScott Long 			mps_dprint(sc, MPS_MAPPING|MPS_FAULT,
650aeb9ac0dSScott Long 			    "Error reading parent SAS device %#x page0, "
651aeb9ac0dSScott Long 			    "iocstatus= 0x%x\n",
652aeb9ac0dSScott Long 			    le16toh(config_page.ParentDevHandle),
653aeb9ac0dSScott Long 			    tmp_mpi_reply.IOCStatus);
654d043c564SKenneth D. Merry 		} else {
655d043c564SKenneth D. Merry 			parent_sas_address = parent_config_page.SASAddress.High;
656d043c564SKenneth D. Merry 			parent_sas_address = (parent_sas_address << 32) |
657d043c564SKenneth D. Merry 				parent_config_page.SASAddress.Low;
658d043c564SKenneth D. Merry 			parent_devinfo = le32toh(parent_config_page.DeviceInfo);
659d043c564SKenneth D. Merry 		}
660d043c564SKenneth D. Merry 	}
661453130d9SPedro F. Giffuni 	/* TODO Check proper endianness */
662d043c564SKenneth D. Merry 	sas_address = config_page.SASAddress.High;
663ef065d89SStephen McConnell 	sas_address = (sas_address << 32) | config_page.SASAddress.Low;
664757ff642SScott Long         mps_dprint(sc, MPS_MAPPING, "Handle 0x%04x SAS Address from SAS device "
665757ff642SScott Long             "page0 = %jx\n", handle, sas_address);
666d043c564SKenneth D. Merry 
667ef065d89SStephen McConnell 	/*
668ef065d89SStephen McConnell 	 * Always get SATA Identify information because this is used to
669ef065d89SStephen McConnell 	 * determine if Start/Stop Unit should be sent to the drive when the
670ef065d89SStephen McConnell 	 * system is shutdown.
671ef065d89SStephen McConnell 	 */
672d043c564SKenneth D. Merry 	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
673ef065d89SStephen McConnell 		ret = mpssas_get_sas_address_for_sata_disk(sc, &sas_address,
674ef065d89SStephen McConnell 		    handle, device_info, &is_SATA_SSD);
675ef065d89SStephen McConnell 		if (ret) {
676757ff642SScott Long 			mps_dprint(sc, MPS_MAPPING|MPS_ERROR,
677757ff642SScott Long 			    "%s: failed to get disk type (SSD or HDD) for SATA "
678757ff642SScott Long 			    "device with handle 0x%04x\n",
679ef065d89SStephen McConnell 			    __func__, handle);
680ef065d89SStephen McConnell 		} else {
681757ff642SScott Long 			mps_dprint(sc, MPS_MAPPING, "Handle 0x%04x SAS Address "
682757ff642SScott Long 			    "from SATA device = %jx\n", handle, sas_address);
683ef065d89SStephen McConnell 		}
684ef065d89SStephen McConnell 	}
685d043c564SKenneth D. Merry 
6864ab1cdc5SScott Long 	/*
6874ab1cdc5SScott Long 	 * use_phynum:
6884ab1cdc5SScott Long 	 *  1 - use the PhyNum field as a fallback to the mapping logic
6894ab1cdc5SScott Long 	 *  0 - never use the PhyNum field
6904ab1cdc5SScott Long 	 * -1 - only use the PhyNum field
691635e58c7SStephen McConnell 	 *
692635e58c7SStephen McConnell 	 * Note that using the Phy number to map a device can cause device adds
693635e58c7SStephen McConnell 	 * to fail if multiple enclosures/expanders are in the topology. For
694635e58c7SStephen McConnell 	 * example, if two devices are in the same slot number in two different
695635e58c7SStephen McConnell 	 * enclosures within the topology, only one of those devices will be
696635e58c7SStephen McConnell 	 * added. PhyNum mapping should not be used if multiple enclosures are
697635e58c7SStephen McConnell 	 * in the topology.
6984ab1cdc5SScott Long 	 */
6994ab1cdc5SScott Long 	id = MPS_MAP_BAD_ID;
7004ab1cdc5SScott Long 	if (sc->use_phynum != -1)
701635e58c7SStephen McConnell 		id = mps_mapping_get_tid(sc, sas_address, handle);
702d043c564SKenneth D. Merry 	if (id == MPS_MAP_BAD_ID) {
7034ab1cdc5SScott Long 		if ((sc->use_phynum == 0)
7044ab1cdc5SScott Long 		 || ((id = config_page.PhyNum) > sassc->maxtargets)) {
7054ab1cdc5SScott Long 			mps_dprint(sc, MPS_INFO, "failure at %s:%d/%s()! "
7064ab1cdc5SScott Long 			    "Could not get ID for device with handle 0x%04x\n",
7074ab1cdc5SScott Long 			    __FILE__, __LINE__, __func__, handle);
708d043c564SKenneth D. Merry 			error = ENXIO;
709d043c564SKenneth D. Merry 			goto out;
710d043c564SKenneth D. Merry 		}
7114ab1cdc5SScott Long 	}
712635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Target ID for added device is %d.\n",
713635e58c7SStephen McConnell 	    __func__, id);
714d9802debSScott Long 
715635e58c7SStephen McConnell 	/*
716635e58c7SStephen McConnell 	 * Only do the ID check and reuse check if the target is not from a
717635e58c7SStephen McConnell 	 * RAID Component. For Physical Disks of a Volume, the ID will be reused
718635e58c7SStephen McConnell 	 * when a volume is deleted because the mapping entry for the PD will
719635e58c7SStephen McConnell 	 * still be in the mapping table. The ID check should not be done here
720635e58c7SStephen McConnell 	 * either since this PD is already being used.
721635e58c7SStephen McConnell 	 */
722635e58c7SStephen McConnell 	targ = &sassc->targets[id];
723635e58c7SStephen McConnell 	if (!(targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT)) {
724d9802debSScott Long 		if (mpssas_check_id(sassc, id) != 0) {
725757ff642SScott Long 			mps_dprint(sc, MPS_MAPPING|MPS_INFO,
726757ff642SScott Long 			    "Excluding target id %d\n", id);
727d9802debSScott Long 			error = ENXIO;
728d9802debSScott Long 			goto out;
729d9802debSScott Long 		}
730d9802debSScott Long 
7314ab1cdc5SScott Long 		if (targ->handle != 0x0) {
732635e58c7SStephen McConnell 			mps_dprint(sc, MPS_MAPPING, "Attempting to reuse "
733635e58c7SStephen McConnell 			    "target id %d handle 0x%04x\n", id, targ->handle);
7344ab1cdc5SScott Long 			error = ENXIO;
7354ab1cdc5SScott Long 			goto out;
7364ab1cdc5SScott Long 		}
737635e58c7SStephen McConnell 	}
7384ab1cdc5SScott Long 
739d043c564SKenneth D. Merry 	targ->devinfo = device_info;
740d043c564SKenneth D. Merry 	targ->devname = le32toh(config_page.DeviceName.High);
741d043c564SKenneth D. Merry 	targ->devname = (targ->devname << 32) |
742d043c564SKenneth D. Merry 	    le32toh(config_page.DeviceName.Low);
743d043c564SKenneth D. Merry 	targ->encl_handle = le16toh(config_page.EnclosureHandle);
744d043c564SKenneth D. Merry 	targ->encl_slot = le16toh(config_page.Slot);
745d043c564SKenneth D. Merry 	targ->handle = handle;
746d043c564SKenneth D. Merry 	targ->parent_handle = le16toh(config_page.ParentDevHandle);
747d043c564SKenneth D. Merry 	targ->sasaddr = mps_to_u64(&config_page.SASAddress);
748d043c564SKenneth D. Merry 	targ->parent_sasaddr = le64toh(parent_sas_address);
749d043c564SKenneth D. Merry 	targ->parent_devinfo = parent_devinfo;
750d043c564SKenneth D. Merry 	targ->tid = id;
751d043c564SKenneth D. Merry 	targ->linkrate = (linkrate>>4);
752d043c564SKenneth D. Merry 	targ->flags = 0;
753ef065d89SStephen McConnell 	if (is_SATA_SSD) {
754ef065d89SStephen McConnell 		targ->flags = MPS_TARGET_IS_SATA_SSD;
755ef065d89SStephen McConnell 	}
756d043c564SKenneth D. Merry 	TAILQ_INIT(&targ->commands);
757d043c564SKenneth D. Merry 	TAILQ_INIT(&targ->timedout_commands);
758be4aa869SKenneth D. Merry 	while(!SLIST_EMPTY(&targ->luns)) {
759be4aa869SKenneth D. Merry 		lun = SLIST_FIRST(&targ->luns);
760be4aa869SKenneth D. Merry 		SLIST_REMOVE_HEAD(&targ->luns, lun_link);
761be4aa869SKenneth D. Merry 		free(lun, M_MPT2);
762be4aa869SKenneth D. Merry 	}
763d043c564SKenneth D. Merry 	SLIST_INIT(&targ->luns);
764be4aa869SKenneth D. Merry 
765d043c564SKenneth D. Merry 	mps_describe_devinfo(targ->devinfo, devstring, 80);
766ef065d89SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "Found device <%s> <%s> <0x%04x> <%d/%d>\n",
767ef065d89SStephen McConnell 	    devstring, mps_describe_table(mps_linkrate_names, targ->linkrate),
768d043c564SKenneth D. Merry 	    targ->handle, targ->encl_handle, targ->encl_slot);
769b01773b0SKenneth D. Merry 
770d043c564SKenneth D. Merry 	mpssas_rescan_target(sc, targ);
7711610f95cSScott Long 	mps_dprint(sc, MPS_MAPPING, "Target id 0x%x added\n", targ->tid);
772ef065d89SStephen McConnell 
773ef065d89SStephen McConnell 	/*
774ef065d89SStephen McConnell 	 * Check all commands to see if the SATA_ID_TIMEOUT flag has been set.
775ef065d89SStephen McConnell 	 * If so, send a Target Reset TM to the target that was just created.
776ef065d89SStephen McConnell 	 * An Abort Task TM should be used instead of a Target Reset, but that
777ef065d89SStephen McConnell 	 * would be much more difficult because targets have not been fully
778ef065d89SStephen McConnell 	 * discovered yet, and LUN's haven't been setup.  So, just reset the
779175ad3d0SKenneth D. Merry 	 * target instead of the LUN.  The commands should complete once the
780175ad3d0SKenneth D. Merry 	 * target has been reset.
781ef065d89SStephen McConnell 	 */
782ef065d89SStephen McConnell 	for (i = 1; i < sc->num_reqs; i++) {
783ef065d89SStephen McConnell 		cm = &sc->commands[i];
784ef065d89SStephen McConnell 		if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
785ef065d89SStephen McConnell 			targ->timeouts++;
7868fe7bf06SWarner Losh 			cm->cm_flags |= MPS_CM_FLAGS_TIMEDOUT;
787ef065d89SStephen McConnell 
788ef065d89SStephen McConnell 			if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
789ef065d89SStephen McConnell 				mps_dprint(sc, MPS_INFO, "%s: sending Target "
790ef065d89SStephen McConnell 				    "Reset for stuck SATA identify command "
791ef065d89SStephen McConnell 				    "(cm = %p)\n", __func__, cm);
792ef065d89SStephen McConnell 				targ->tm->cm_targ = targ;
793ef065d89SStephen McConnell 				mpssas_send_reset(sc, targ->tm,
794ef065d89SStephen McConnell 				    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
795ef065d89SStephen McConnell 			} else {
796ef065d89SStephen McConnell 				mps_dprint(sc, MPS_ERROR, "Failed to allocate "
797ef065d89SStephen McConnell 				    "tm for Target Reset after SATA ID command "
798ef065d89SStephen McConnell 				    "timed out (cm %p)\n", cm);
799ef065d89SStephen McConnell 			}
800ef065d89SStephen McConnell 			/*
801ef065d89SStephen McConnell 			 * No need to check for more since the target is
802ef065d89SStephen McConnell 			 * already being reset.
803ef065d89SStephen McConnell 			 */
804ef065d89SStephen McConnell 			break;
805ef065d89SStephen McConnell 		}
806ef065d89SStephen McConnell 	}
807d043c564SKenneth D. Merry out:
808d043c564SKenneth D. Merry 	mpssas_startup_decrement(sassc);
809d043c564SKenneth D. Merry 	return (error);
810d043c564SKenneth D. Merry }
811d043c564SKenneth D. Merry 
812d043c564SKenneth D. Merry int
mpssas_get_sas_address_for_sata_disk(struct mps_softc * sc,u64 * sas_address,u16 handle,u32 device_info,u8 * is_SATA_SSD)813d043c564SKenneth D. Merry mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
814ef065d89SStephen McConnell     u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD)
815d043c564SKenneth D. Merry {
816d043c564SKenneth D. Merry 	Mpi2SataPassthroughReply_t mpi_reply;
817d043c564SKenneth D. Merry 	int i, rc, try_count;
818d043c564SKenneth D. Merry 	u32 *bufferptr;
819d043c564SKenneth D. Merry 	union _sata_sas_address hash_address;
820d043c564SKenneth D. Merry 	struct _ata_identify_device_data ata_identify;
821d043c564SKenneth D. Merry 	u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
822d043c564SKenneth D. Merry 	u32 ioc_status;
823d043c564SKenneth D. Merry 	u8 sas_status;
824d043c564SKenneth D. Merry 
825d043c564SKenneth D. Merry 	memset(&ata_identify, 0, sizeof(ata_identify));
826d043c564SKenneth D. Merry 	try_count = 0;
827d043c564SKenneth D. Merry 	do {
828d043c564SKenneth D. Merry 		rc = mpssas_get_sata_identify(sc, handle, &mpi_reply,
829d043c564SKenneth D. Merry 		    (char *)&ata_identify, sizeof(ata_identify), device_info);
830d043c564SKenneth D. Merry 		try_count++;
831d043c564SKenneth D. Merry 		ioc_status = le16toh(mpi_reply.IOCStatus)
832d043c564SKenneth D. Merry 		    & MPI2_IOCSTATUS_MASK;
833d043c564SKenneth D. Merry 		sas_status = mpi_reply.SASStatus;
834a92fe027SAlan Somers 		switch (ioc_status) {
835a92fe027SAlan Somers 		case MPI2_IOCSTATUS_SUCCESS:
836a92fe027SAlan Somers 			break;
837a92fe027SAlan Somers 		case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
838a92fe027SAlan Somers 			/* No sense sleeping.  this error won't get better */
839a92fe027SAlan Somers 			break;
840a92fe027SAlan Somers 		default:
841ef065d89SStephen McConnell 			if (sc->spinup_wait_time > 0) {
842ef065d89SStephen McConnell 				mps_dprint(sc, MPS_INFO, "Sleeping %d seconds "
843ef065d89SStephen McConnell 				    "after SATA ID error to wait for spinup\n",
844ef065d89SStephen McConnell 				    sc->spinup_wait_time);
845ef065d89SStephen McConnell 				msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0,
846ef065d89SStephen McConnell 				    "mpsid", sc->spinup_wait_time * hz);
847ef065d89SStephen McConnell 			}
848ef065d89SStephen McConnell 		}
849a92fe027SAlan Somers 	} while (((rc && (rc != EWOULDBLOCK)) ||
850a92fe027SAlan Somers 	    	 (ioc_status &&
851a92fe027SAlan Somers 		  (ioc_status != MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR))
852a92fe027SAlan Somers 	       || sas_status) && (try_count < 5));
853d043c564SKenneth D. Merry 
854d043c564SKenneth D. Merry 	if (rc == 0 && !ioc_status && !sas_status) {
855ef065d89SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: got SATA identify "
856ef065d89SStephen McConnell 		    "successfully for handle = 0x%x with try_count = %d\n",
857d043c564SKenneth D. Merry 		    __func__, handle, try_count);
858d043c564SKenneth D. Merry 	} else {
8591610f95cSScott Long 		mps_dprint(sc, MPS_MAPPING, "%s: handle = 0x%x failed\n",
860d043c564SKenneth D. Merry 		    __func__, handle);
861d043c564SKenneth D. Merry 		return -1;
862d043c564SKenneth D. Merry 	}
863d043c564SKenneth D. Merry 	/* Copy & byteswap the 40 byte model number to a buffer */
864d043c564SKenneth D. Merry 	for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
865d043c564SKenneth D. Merry 		buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
866d043c564SKenneth D. Merry 		buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
867d043c564SKenneth D. Merry 	}
868d043c564SKenneth D. Merry 	/* Copy & byteswap the 20 byte serial number to a buffer */
869d043c564SKenneth D. Merry 	for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
870d043c564SKenneth D. Merry 		buffer[MPT2SAS_MN_LEN + i] =
871d043c564SKenneth D. Merry 		    ((u8 *)ata_identify.serial_number)[i + 1];
872d043c564SKenneth D. Merry 		buffer[MPT2SAS_MN_LEN + i + 1] =
873d043c564SKenneth D. Merry 		    ((u8 *)ata_identify.serial_number)[i];
874d043c564SKenneth D. Merry 	}
875d043c564SKenneth D. Merry 	bufferptr = (u32 *)buffer;
876d043c564SKenneth D. Merry 	/* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
877d043c564SKenneth D. Merry 	 * so loop through the first 56 bytes (7*8),
878d043c564SKenneth D. Merry 	 * and then add in the last dword.
879d043c564SKenneth D. Merry 	 */
880d043c564SKenneth D. Merry 	hash_address.word.low  = 0;
881d043c564SKenneth D. Merry 	hash_address.word.high = 0;
882d043c564SKenneth D. Merry 	for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
883d043c564SKenneth D. Merry 		hash_address.word.low += *bufferptr;
884d043c564SKenneth D. Merry 		bufferptr++;
885d043c564SKenneth D. Merry 		hash_address.word.high += *bufferptr;
886d043c564SKenneth D. Merry 		bufferptr++;
887d043c564SKenneth D. Merry 	}
888d043c564SKenneth D. Merry 	/* Add the last dword */
889d043c564SKenneth D. Merry 	hash_address.word.low += *bufferptr;
890d043c564SKenneth D. Merry 	/* Make sure the hash doesn't start with 5, because it could clash
891d043c564SKenneth D. Merry 	 * with a SAS address. Change 5 to a D.
892d043c564SKenneth D. Merry 	 */
893d043c564SKenneth D. Merry 	if ((hash_address.word.high & 0x000000F0) == (0x00000050))
894d043c564SKenneth D. Merry 		hash_address.word.high |= 0x00000080;
895d043c564SKenneth D. Merry 	*sas_address = (u64)hash_address.wwid[0] << 56 |
896d043c564SKenneth D. Merry 	    (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
897d043c564SKenneth D. Merry 	    (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
898d043c564SKenneth D. Merry 	    (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] <<  8 |
899d043c564SKenneth D. Merry 	    (u64)hash_address.wwid[7];
900ef065d89SStephen McConnell 	if (ata_identify.rotational_speed == 1) {
901ef065d89SStephen McConnell 		*is_SATA_SSD = 1;
902ef065d89SStephen McConnell 	}
903ef065d89SStephen McConnell 
904d043c564SKenneth D. Merry 	return 0;
905d043c564SKenneth D. Merry }
906d043c564SKenneth D. Merry 
907d043c564SKenneth D. Merry static int
mpssas_get_sata_identify(struct mps_softc * sc,u16 handle,Mpi2SataPassthroughReply_t * mpi_reply,char * id_buffer,int sz,u32 devinfo)908d043c564SKenneth D. Merry mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
909d043c564SKenneth D. Merry     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
910d043c564SKenneth D. Merry {
911d043c564SKenneth D. Merry 	Mpi2SataPassthroughRequest_t *mpi_request;
9126d4ffcb4SKenneth D. Merry 	Mpi2SataPassthroughReply_t *reply = NULL;
913d043c564SKenneth D. Merry 	struct mps_command *cm;
914d043c564SKenneth D. Merry 	char *buffer;
915d043c564SKenneth D. Merry 	int error = 0;
916d043c564SKenneth D. Merry 
917d043c564SKenneth D. Merry 	buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO);
918d043c564SKenneth D. Merry 	if (!buffer)
919d043c564SKenneth D. Merry 		return ENOMEM;
920d043c564SKenneth D. Merry 
9211d50dd1fSChristian Brueffer 	if ((cm = mps_alloc_command(sc)) == NULL) {
9221d50dd1fSChristian Brueffer 		free(buffer, M_MPT2);
923d043c564SKenneth D. Merry 		return (EBUSY);
9241d50dd1fSChristian Brueffer 	}
925d043c564SKenneth D. Merry 	mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
926d043c564SKenneth D. Merry 	bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
927d043c564SKenneth D. Merry 	mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
928d043c564SKenneth D. Merry 	mpi_request->VF_ID = 0;
929d043c564SKenneth D. Merry 	mpi_request->DevHandle = htole16(handle);
930d043c564SKenneth D. Merry 	mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
931d043c564SKenneth D. Merry 	    MPI2_SATA_PT_REQ_PT_FLAGS_READ);
932d043c564SKenneth D. Merry 	mpi_request->DataLength = htole32(sz);
933d043c564SKenneth D. Merry 	mpi_request->CommandFIS[0] = 0x27;
934d043c564SKenneth D. Merry 	mpi_request->CommandFIS[1] = 0x80;
935d043c564SKenneth D. Merry 	mpi_request->CommandFIS[2] =  (devinfo &
936d043c564SKenneth D. Merry 	    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
937d043c564SKenneth D. Merry 	cm->cm_sge = &mpi_request->SGL;
938d043c564SKenneth D. Merry 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
939d043c564SKenneth D. Merry 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
940d043c564SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
941d043c564SKenneth D. Merry 	cm->cm_data = buffer;
942d043c564SKenneth D. Merry 	cm->cm_length = htole32(sz);
943ef065d89SStephen McConnell 
944ef065d89SStephen McConnell 	/*
94586312e46SConrad Meyer 	 * Use a custom handler to avoid reinit'ing the controller on timeout.
94686312e46SConrad Meyer 	 * This fixes a problem where the FW does not send a reply sometimes
947ef065d89SStephen McConnell 	 * when a bad disk is in the topology. So, this is used to timeout the
948ef065d89SStephen McConnell 	 * command so that processing can continue normally.
949ef065d89SStephen McConnell 	 */
95086312e46SConrad Meyer 	cm->cm_timeout_handler = mpssas_ata_id_timeout;
951ef065d89SStephen McConnell 
95286312e46SConrad Meyer 	error = mps_wait_command(sc, &cm, MPS_ATA_ID_TIMEOUT, CAN_SLEEP);
95386312e46SConrad Meyer 
95486312e46SConrad Meyer 	/* mpssas_ata_id_timeout does not reset controller */
95586312e46SConrad Meyer 	KASSERT(cm != NULL, ("%s: surprise command freed", __func__));
95686312e46SConrad Meyer 
957d043c564SKenneth D. Merry 	reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
958d043c564SKenneth D. Merry 	if (error || (reply == NULL)) {
959d043c564SKenneth D. Merry 		/* FIXME */
9609b91b192SKenneth D. Merry  		/*
9619b91b192SKenneth D. Merry  		 * If the request returns an error then we need to do a diag
9629b91b192SKenneth D. Merry  		 * reset
9639b91b192SKenneth D. Merry  		 */
964aeb9ac0dSScott Long  		mps_dprint(sc, MPS_INFO|MPS_FAULT|MPS_MAPPING,
965e7ef108cSWarner Losh 		    "Request for SATA PASSTHROUGH page completed with error %d\n",
966aeb9ac0dSScott Long 		    error);
967d043c564SKenneth D. Merry 		error = ENXIO;
968d043c564SKenneth D. Merry 		goto out;
969d043c564SKenneth D. Merry 	}
970d043c564SKenneth D. Merry 	bcopy(buffer, id_buffer, sz);
971d043c564SKenneth D. Merry 	bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
972be4aa869SKenneth D. Merry 	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
973d043c564SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS) {
974aeb9ac0dSScott Long 		mps_dprint(sc, MPS_INFO|MPS_MAPPING|MPS_FAULT,
975aeb9ac0dSScott Long 		    "Error reading device %#x SATA PASSTHRU; iocstatus= 0x%x\n",
976aeb9ac0dSScott Long 		    handle, reply->IOCStatus);
977d043c564SKenneth D. Merry 		error = ENXIO;
978d043c564SKenneth D. Merry 		goto out;
979d043c564SKenneth D. Merry 	}
980d043c564SKenneth D. Merry out:
981ef065d89SStephen McConnell 	/*
982ef065d89SStephen McConnell 	 * If the SATA_ID_TIMEOUT flag has been set for this command, don't free
983175ad3d0SKenneth D. Merry 	 * it.  The command and buffer will be freed after we send a Target
984175ad3d0SKenneth D. Merry 	 * Reset TM and the command comes back from the controller.
985ef065d89SStephen McConnell 	 */
98686312e46SConrad Meyer 	if ((cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) == 0) {
987d043c564SKenneth D. Merry 		mps_free_command(sc, cm);
988d043c564SKenneth D. Merry 		free(buffer, M_MPT2);
98986312e46SConrad Meyer 	}
990d043c564SKenneth D. Merry 	return (error);
991d043c564SKenneth D. Merry }
992d043c564SKenneth D. Merry 
993175ad3d0SKenneth D. Merry /*
994175ad3d0SKenneth D. Merry  * This is completion handler to make sure that commands and allocated
995175ad3d0SKenneth D. Merry  * buffers get freed when timed out SATA ID commands finally complete after
996175ad3d0SKenneth D. Merry  * we've reset the target.  In the normal case, we wait for the command to
997175ad3d0SKenneth D. Merry  * complete.
998175ad3d0SKenneth D. Merry  */
999175ad3d0SKenneth D. Merry static void
mpssas_ata_id_complete(struct mps_softc * sc,struct mps_command * cm)1000175ad3d0SKenneth D. Merry mpssas_ata_id_complete(struct mps_softc *sc, struct mps_command *cm)
1001175ad3d0SKenneth D. Merry {
1002175ad3d0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "%s ATA ID completed late cm %p sc %p\n",
1003175ad3d0SKenneth D. Merry 	    __func__, cm, sc);
1004175ad3d0SKenneth D. Merry 
1005175ad3d0SKenneth D. Merry 	free(cm->cm_data, M_MPT2);
1006175ad3d0SKenneth D. Merry 	mps_free_command(sc, cm);
1007175ad3d0SKenneth D. Merry }
1008175ad3d0SKenneth D. Merry 
1009175ad3d0SKenneth D. Merry 
1010ef065d89SStephen McConnell static void
mpssas_ata_id_timeout(struct mps_softc * sc,struct mps_command * cm)101186312e46SConrad Meyer mpssas_ata_id_timeout(struct mps_softc *sc, struct mps_command *cm)
1012ef065d89SStephen McConnell {
101386312e46SConrad Meyer 	mps_dprint(sc, MPS_INFO, "%s ATA ID command timeout cm %p sc %p\n",
1014ef065d89SStephen McConnell 	    __func__, cm, sc);
1015ef065d89SStephen McConnell 
1016ef065d89SStephen McConnell 	/*
101786312e46SConrad Meyer 	 * The Abort Task cannot be sent from here because the driver has not
101886312e46SConrad Meyer 	 * completed setting up targets.  Instead, the command is flagged so
1019175ad3d0SKenneth D. Merry 	 * that special handling will be used to send a target reset.
1020ef065d89SStephen McConnell 	 */
1021ef065d89SStephen McConnell 	cm->cm_flags |= MPS_CM_FLAGS_SATA_ID_TIMEOUT;
1022175ad3d0SKenneth D. Merry 
1023175ad3d0SKenneth D. Merry 	/*
1024175ad3d0SKenneth D. Merry 	 * Since we will no longer be waiting for the command to complete,
1025175ad3d0SKenneth D. Merry 	 * set a completion handler to make sure we free all resources.
1026175ad3d0SKenneth D. Merry 	 */
1027175ad3d0SKenneth D. Merry 	cm->cm_complete = mpssas_ata_id_complete;
1028ef065d89SStephen McConnell }
1029ef065d89SStephen McConnell 
1030d043c564SKenneth D. Merry static int
mpssas_volume_add(struct mps_softc * sc,u16 handle)1031653c521fSKenneth D. Merry mpssas_volume_add(struct mps_softc *sc, u16 handle)
1032d043c564SKenneth D. Merry {
1033d043c564SKenneth D. Merry 	struct mpssas_softc *sassc;
1034d043c564SKenneth D. Merry 	struct mpssas_target *targ;
1035d043c564SKenneth D. Merry 	u64 wwid;
1036d043c564SKenneth D. Merry 	unsigned int id;
1037d043c564SKenneth D. Merry 	int error = 0;
1038be4aa869SKenneth D. Merry 	struct mpssas_lun *lun;
1039d043c564SKenneth D. Merry 
1040d043c564SKenneth D. Merry 	sassc = sc->sassc;
1041d043c564SKenneth D. Merry 	mpssas_startup_increment(sassc);
1042be4aa869SKenneth D. Merry 	/* wwid is endian safe */
1043d043c564SKenneth D. Merry 	mps_config_get_volume_wwid(sc, handle, &wwid);
1044d043c564SKenneth D. Merry 	if (!wwid) {
1045d043c564SKenneth D. Merry 		printf("%s: invalid WWID; cannot add volume to mapping table\n",
1046d043c564SKenneth D. Merry 		    __func__);
1047d043c564SKenneth D. Merry 		error = ENXIO;
1048d043c564SKenneth D. Merry 		goto out;
1049d043c564SKenneth D. Merry 	}
1050d043c564SKenneth D. Merry 
1051635e58c7SStephen McConnell 	id = mps_mapping_get_raid_tid(sc, wwid, handle);
1052d043c564SKenneth D. Merry 	if (id == MPS_MAP_BAD_ID) {
1053d043c564SKenneth D. Merry 		printf("%s: could not get ID for volume with handle 0x%04x and "
1054d043c564SKenneth D. Merry 		    "WWID 0x%016llx\n", __func__, handle,
1055d043c564SKenneth D. Merry 		    (unsigned long long)wwid);
1056d043c564SKenneth D. Merry 		error = ENXIO;
1057d043c564SKenneth D. Merry 		goto out;
1058d043c564SKenneth D. Merry 	}
1059d043c564SKenneth D. Merry 
1060d043c564SKenneth D. Merry 	targ = &sassc->targets[id];
1061d043c564SKenneth D. Merry 	targ->tid = id;
1062d043c564SKenneth D. Merry 	targ->handle = handle;
1063d043c564SKenneth D. Merry 	targ->devname = wwid;
1064d043c564SKenneth D. Merry 	TAILQ_INIT(&targ->commands);
1065d043c564SKenneth D. Merry 	TAILQ_INIT(&targ->timedout_commands);
1066be4aa869SKenneth D. Merry 	while(!SLIST_EMPTY(&targ->luns)) {
1067be4aa869SKenneth D. Merry 		lun = SLIST_FIRST(&targ->luns);
1068be4aa869SKenneth D. Merry 		SLIST_REMOVE_HEAD(&targ->luns, lun_link);
1069be4aa869SKenneth D. Merry 		free(lun, M_MPT2);
1070be4aa869SKenneth D. Merry 	}
1071d043c564SKenneth D. Merry 	SLIST_INIT(&targ->luns);
1072d043c564SKenneth D. Merry 	mpssas_rescan_target(sc, targ);
10731610f95cSScott Long 	mps_dprint(sc, MPS_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n",
1074d043c564SKenneth D. Merry 	    targ->tid, wwid);
1075d043c564SKenneth D. Merry out:
1076d043c564SKenneth D. Merry 	mpssas_startup_decrement(sassc);
1077d043c564SKenneth D. Merry 	return (error);
1078d043c564SKenneth D. Merry }
1079d043c564SKenneth D. Merry 
1080d043c564SKenneth D. Merry /**
10817571e7f6SSteven Hartland  * mpssas_SSU_to_SATA_devices
10827571e7f6SSteven Hartland  * @sc: per adapter object
1083acc173a6SWarner Losh  * @howto: mast of RB_* bits for how we're rebooting
10847571e7f6SSteven Hartland  *
10857571e7f6SSteven Hartland  * Looks through the target list and issues a StartStopUnit SCSI command to each
10867571e7f6SSteven Hartland  * SATA direct-access device.  This helps to ensure that data corruption is
10877571e7f6SSteven Hartland  * avoided when the system is being shut down.  This must be called after the IR
10887571e7f6SSteven Hartland  * System Shutdown RAID Action is sent if in IR mode.
10897571e7f6SSteven Hartland  *
10907571e7f6SSteven Hartland  * Return nothing.
10917571e7f6SSteven Hartland  */
10927571e7f6SSteven Hartland static void
mpssas_SSU_to_SATA_devices(struct mps_softc * sc,int howto)10937d147b81SSteven Hartland mpssas_SSU_to_SATA_devices(struct mps_softc *sc, int howto)
10947571e7f6SSteven Hartland {
10957571e7f6SSteven Hartland 	struct mpssas_softc *sassc = sc->sassc;
10967571e7f6SSteven Hartland 	union ccb *ccb;
10977571e7f6SSteven Hartland 	path_id_t pathid = cam_sim_path(sassc->sim);
10987571e7f6SSteven Hartland 	target_id_t targetid;
10997571e7f6SSteven Hartland 	struct mpssas_target *target;
11007571e7f6SSteven Hartland 	char path_str[64];
11017d147b81SSteven Hartland 	int timeout;
11027571e7f6SSteven Hartland 
11037571e7f6SSteven Hartland 	/*
1104ef065d89SStephen McConnell 	 * For each target, issue a StartStopUnit command to stop the device.
11057571e7f6SSteven Hartland 	 */
11067571e7f6SSteven Hartland 	sc->SSU_started = TRUE;
11077571e7f6SSteven Hartland 	sc->SSU_refcount = 0;
1108635e58c7SStephen McConnell 	for (targetid = 0; targetid < sc->max_devices; targetid++) {
11097571e7f6SSteven Hartland 		target = &sassc->targets[targetid];
11107571e7f6SSteven Hartland 		if (target->handle == 0x0) {
11117571e7f6SSteven Hartland 			continue;
11127571e7f6SSteven Hartland 		}
11137571e7f6SSteven Hartland 
11147571e7f6SSteven Hartland 		ccb = xpt_alloc_ccb_nowait();
11157571e7f6SSteven Hartland 		if (ccb == NULL) {
1116ef065d89SStephen McConnell 			mps_dprint(sc, MPS_FAULT, "Unable to alloc CCB to stop "
1117ef065d89SStephen McConnell 			    "unit.\n");
11187571e7f6SSteven Hartland 			return;
11197571e7f6SSteven Hartland 		}
11207571e7f6SSteven Hartland 
11217571e7f6SSteven Hartland 		/*
1122ef065d89SStephen McConnell 		 * The stop_at_shutdown flag will be set if this device is
11237571e7f6SSteven Hartland 		 * a SATA direct-access end device.
11247571e7f6SSteven Hartland 		 */
1125ef065d89SStephen McConnell 		if (target->stop_at_shutdown) {
11267571e7f6SSteven Hartland 			if (xpt_create_path(&ccb->ccb_h.path,
11277571e7f6SSteven Hartland 			    xpt_periph, pathid, targetid,
1128ef065d89SStephen McConnell 			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1129ef065d89SStephen McConnell 				mps_dprint(sc, MPS_FAULT, "Unable to create "
1130ef065d89SStephen McConnell 				    "LUN path to stop unit.\n");
11317571e7f6SSteven Hartland 				xpt_free_ccb(ccb);
11327571e7f6SSteven Hartland 				return;
11337571e7f6SSteven Hartland 			}
11347571e7f6SSteven Hartland 			xpt_path_string(ccb->ccb_h.path, path_str,
11357571e7f6SSteven Hartland 			    sizeof(path_str));
11367571e7f6SSteven Hartland 
1137ef065d89SStephen McConnell 			mps_dprint(sc, MPS_INFO, "Sending StopUnit: path %s "
1138ef065d89SStephen McConnell 			    "handle %d\n", path_str, target->handle);
11397571e7f6SSteven Hartland 
11407571e7f6SSteven Hartland 			/*
1141ef065d89SStephen McConnell 			 * Issue a START STOP UNIT command for the target.
1142ef065d89SStephen McConnell 			 * Increment the SSU counter to be used to count the
1143ef065d89SStephen McConnell 			 * number of required replies.
11447571e7f6SSteven Hartland 			 */
1145ef065d89SStephen McConnell 			mps_dprint(sc, MPS_INFO, "Incrementing SSU count\n");
11467571e7f6SSteven Hartland 			sc->SSU_refcount++;
11477571e7f6SSteven Hartland 			ccb->ccb_h.target_id =
11487571e7f6SSteven Hartland 			    xpt_path_target_id(ccb->ccb_h.path);
11497571e7f6SSteven Hartland 			ccb->ccb_h.ppriv_ptr1 = sassc;
11507571e7f6SSteven Hartland 			scsi_start_stop(&ccb->csio,
11517571e7f6SSteven Hartland 			    /*retries*/0,
11527571e7f6SSteven Hartland 			    mpssas_stop_unit_done,
11537571e7f6SSteven Hartland 			    MSG_SIMPLE_Q_TAG,
11547571e7f6SSteven Hartland 			    /*start*/FALSE,
11557571e7f6SSteven Hartland 			    /*load/eject*/0,
11567571e7f6SSteven Hartland 			    /*immediate*/FALSE,
11577571e7f6SSteven Hartland 			    MPS_SENSE_LEN,
11587571e7f6SSteven Hartland 			    /*timeout*/10000);
11597571e7f6SSteven Hartland 			xpt_action(ccb);
11607571e7f6SSteven Hartland 		}
11617571e7f6SSteven Hartland 	}
11627571e7f6SSteven Hartland 
11637571e7f6SSteven Hartland 	/*
11647d147b81SSteven Hartland 	 * Timeout after 60 seconds by default or 10 seconds if howto has
11657d147b81SSteven Hartland 	 * RB_NOSYNC set which indicates we're likely handling a panic.
11667571e7f6SSteven Hartland 	 */
11677d147b81SSteven Hartland 	timeout = 600;
11687d147b81SSteven Hartland 	if (howto & RB_NOSYNC)
11697d147b81SSteven Hartland 		timeout = 100;
11707d147b81SSteven Hartland 
11717d147b81SSteven Hartland 	/*
11727d147b81SSteven Hartland 	 * Wait until all of the SSU commands have completed or timeout has
11737d147b81SSteven Hartland 	 * expired.  Pause for 100ms each time through.  If any command
11747d147b81SSteven Hartland 	 * times out, the target will be reset in the SCSI command timeout
11757d147b81SSteven Hartland 	 * routine.
11767d147b81SSteven Hartland 	 */
11777d147b81SSteven Hartland 	while (sc->SSU_refcount > 0) {
11787571e7f6SSteven Hartland 		pause("mpswait", hz/10);
1179d4b95382SWarner Losh 		if (SCHEDULER_STOPPED())
1180d4b95382SWarner Losh 			xpt_sim_poll(sassc->sim);
11817571e7f6SSteven Hartland 
11827d147b81SSteven Hartland 		if (--timeout == 0) {
11837571e7f6SSteven Hartland 			mps_dprint(sc, MPS_FAULT, "Time has expired waiting "
11847571e7f6SSteven Hartland 			    "for SSU commands to complete.\n");
11857571e7f6SSteven Hartland 			break;
11867571e7f6SSteven Hartland 		}
11877571e7f6SSteven Hartland 	}
11887571e7f6SSteven Hartland }
11897571e7f6SSteven Hartland 
11907571e7f6SSteven Hartland static void
mpssas_stop_unit_done(struct cam_periph * periph,union ccb * done_ccb)11917571e7f6SSteven Hartland mpssas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb)
11927571e7f6SSteven Hartland {
11937571e7f6SSteven Hartland 	struct mpssas_softc *sassc;
11947571e7f6SSteven Hartland 	char path_str[64];
11957571e7f6SSteven Hartland 
1196f4e69c98SStephen McConnell 	if (done_ccb == NULL)
1197f4e69c98SStephen McConnell 		return;
1198f4e69c98SStephen McConnell 
11997571e7f6SSteven Hartland 	sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1;
12007571e7f6SSteven Hartland 
12017571e7f6SSteven Hartland 	xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str));
12027571e7f6SSteven Hartland 	mps_dprint(sassc->sc, MPS_INFO, "Completing stop unit for %s\n",
12037571e7f6SSteven Hartland 	    path_str);
12047571e7f6SSteven Hartland 
12057571e7f6SSteven Hartland 	/*
12067571e7f6SSteven Hartland 	 * Nothing more to do except free the CCB and path.  If the command
12077571e7f6SSteven Hartland 	 * timed out, an abort reset, then target reset will be issued during
12087571e7f6SSteven Hartland 	 * the SCSI Command process.
12097571e7f6SSteven Hartland 	 */
12107571e7f6SSteven Hartland 	xpt_free_path(done_ccb->ccb_h.path);
12117571e7f6SSteven Hartland 	xpt_free_ccb(done_ccb);
12127571e7f6SSteven Hartland }
12137571e7f6SSteven Hartland 
12147571e7f6SSteven Hartland /**
1215d043c564SKenneth D. Merry  * mpssas_ir_shutdown - IR shutdown notification
1216d043c564SKenneth D. Merry  * @sc: per adapter object
1217acc173a6SWarner Losh  * @howto: mast of RB_* bits for how we're rebooting
1218d043c564SKenneth D. Merry  *
1219d043c564SKenneth D. Merry  * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
1220d043c564SKenneth D. Merry  * the host system is shutting down.
1221d043c564SKenneth D. Merry  *
1222d043c564SKenneth D. Merry  * Return nothing.
1223d043c564SKenneth D. Merry  */
1224d043c564SKenneth D. Merry void
mpssas_ir_shutdown(struct mps_softc * sc,int howto)12257d147b81SSteven Hartland mpssas_ir_shutdown(struct mps_softc *sc, int howto)
1226d043c564SKenneth D. Merry {
1227d043c564SKenneth D. Merry 	u16 volume_mapping_flags;
1228d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1229d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1230d043c564SKenneth D. Merry 	u32 start_idx, end_idx;
1231d043c564SKenneth D. Merry 	unsigned int id, found_volume = 0;
1232d043c564SKenneth D. Merry 	struct mps_command *cm;
1233d043c564SKenneth D. Merry 	Mpi2RaidActionRequest_t	*action;
1234ef065d89SStephen McConnell 	target_id_t targetid;
1235ef065d89SStephen McConnell 	struct mpssas_target *target;
1236d043c564SKenneth D. Merry 
1237d043c564SKenneth D. Merry 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1238d043c564SKenneth D. Merry 
1239d043c564SKenneth D. Merry 	/* is IR firmware build loaded? */
1240d043c564SKenneth D. Merry 	if (!sc->ir_firmware)
12417571e7f6SSteven Hartland 		goto out;
1242d043c564SKenneth D. Merry 
1243d043c564SKenneth D. Merry 	/* are there any volumes?  Look at IR target IDs. */
1244d043c564SKenneth D. Merry 	// TODO-later, this should be looked up in the RAID config structure
1245d043c564SKenneth D. Merry 	// when it is implemented.
1246d043c564SKenneth D. Merry 	volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
1247d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
1248d043c564SKenneth D. Merry 	if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
1249d043c564SKenneth D. Merry 		start_idx = 0;
1250d043c564SKenneth D. Merry 		if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
1251d043c564SKenneth D. Merry 			start_idx = 1;
1252d043c564SKenneth D. Merry 	} else
1253d043c564SKenneth D. Merry 		start_idx = sc->max_devices - sc->max_volumes;
1254d043c564SKenneth D. Merry 	end_idx = start_idx + sc->max_volumes - 1;
1255d043c564SKenneth D. Merry 
1256d043c564SKenneth D. Merry 	for (id = start_idx; id < end_idx; id++) {
1257d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[id];
1258d043c564SKenneth D. Merry 		if ((mt_entry->physical_id != 0) &&
1259d043c564SKenneth D. Merry 		    (mt_entry->missing_count == 0)) {
1260d043c564SKenneth D. Merry 			found_volume = 1;
1261d043c564SKenneth D. Merry 			break;
1262d043c564SKenneth D. Merry 		}
1263d043c564SKenneth D. Merry 	}
1264d043c564SKenneth D. Merry 
1265d043c564SKenneth D. Merry 	if (!found_volume)
12667571e7f6SSteven Hartland 		goto out;
1267d043c564SKenneth D. Merry 
1268d043c564SKenneth D. Merry 	if ((cm = mps_alloc_command(sc)) == NULL) {
1269d043c564SKenneth D. Merry 		printf("%s: command alloc failed\n", __func__);
12707571e7f6SSteven Hartland 		goto out;
1271d043c564SKenneth D. Merry 	}
1272d043c564SKenneth D. Merry 
1273d043c564SKenneth D. Merry 	action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
1274d043c564SKenneth D. Merry 	action->Function = MPI2_FUNCTION_RAID_ACTION;
1275d043c564SKenneth D. Merry 	action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
1276d043c564SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1277653c521fSKenneth D. Merry 	mps_lock(sc);
12786d4ffcb4SKenneth D. Merry 	mps_wait_command(sc, &cm, 5, CAN_SLEEP);
1279653c521fSKenneth D. Merry 	mps_unlock(sc);
1280d043c564SKenneth D. Merry 
1281d043c564SKenneth D. Merry 	/*
1282d043c564SKenneth D. Merry 	 * Don't check for reply, just leave.
1283d043c564SKenneth D. Merry 	 */
1284d043c564SKenneth D. Merry 	if (cm)
1285d043c564SKenneth D. Merry 		mps_free_command(sc, cm);
12867571e7f6SSteven Hartland 
12877571e7f6SSteven Hartland out:
1288ef065d89SStephen McConnell 	/*
1289ef065d89SStephen McConnell 	 * All of the targets must have the correct value set for
1290ef065d89SStephen McConnell 	 * 'stop_at_shutdown' for the current 'enable_ssu' sysctl variable.
1291ef065d89SStephen McConnell 	 *
1292ef065d89SStephen McConnell 	 * The possible values for the 'enable_ssu' variable are:
1293ef065d89SStephen McConnell 	 * 0: disable to SSD and HDD
1294ef065d89SStephen McConnell 	 * 1: disable only to HDD (default)
1295ef065d89SStephen McConnell 	 * 2: disable only to SSD
1296ef065d89SStephen McConnell 	 * 3: enable to SSD and HDD
1297ef065d89SStephen McConnell 	 * anything else will default to 1.
1298ef065d89SStephen McConnell 	 */
1299635e58c7SStephen McConnell 	for (targetid = 0; targetid < sc->max_devices; targetid++) {
1300ef065d89SStephen McConnell 		target = &sc->sassc->targets[targetid];
1301ef065d89SStephen McConnell 		if (target->handle == 0x0) {
1302ef065d89SStephen McConnell 			continue;
1303ef065d89SStephen McConnell 		}
1304ef065d89SStephen McConnell 
1305ef065d89SStephen McConnell 		if (target->supports_SSU) {
1306ef065d89SStephen McConnell 			switch (sc->enable_ssu) {
1307ef065d89SStephen McConnell 			case MPS_SSU_DISABLE_SSD_DISABLE_HDD:
1308ef065d89SStephen McConnell 				target->stop_at_shutdown = FALSE;
1309ef065d89SStephen McConnell 				break;
1310ef065d89SStephen McConnell 			case MPS_SSU_DISABLE_SSD_ENABLE_HDD:
1311ef065d89SStephen McConnell 				target->stop_at_shutdown = TRUE;
1312ef065d89SStephen McConnell 				if (target->flags & MPS_TARGET_IS_SATA_SSD) {
1313ef065d89SStephen McConnell 					target->stop_at_shutdown = FALSE;
1314ef065d89SStephen McConnell 				}
1315ef065d89SStephen McConnell 				break;
1316ef065d89SStephen McConnell 			case MPS_SSU_ENABLE_SSD_ENABLE_HDD:
1317ef065d89SStephen McConnell 				target->stop_at_shutdown = TRUE;
1318ef065d89SStephen McConnell 				break;
1319ef065d89SStephen McConnell 			case MPS_SSU_ENABLE_SSD_DISABLE_HDD:
1320ef065d89SStephen McConnell 			default:
1321ef065d89SStephen McConnell 				target->stop_at_shutdown = TRUE;
1322ef065d89SStephen McConnell 				if ((target->flags &
1323ef065d89SStephen McConnell 				    MPS_TARGET_IS_SATA_SSD) == 0) {
1324ef065d89SStephen McConnell 					target->stop_at_shutdown = FALSE;
1325ef065d89SStephen McConnell 				}
1326ef065d89SStephen McConnell 				break;
1327ef065d89SStephen McConnell 			}
1328ef065d89SStephen McConnell 		}
1329ef065d89SStephen McConnell 	}
13307d147b81SSteven Hartland 	mpssas_SSU_to_SATA_devices(sc, howto);
1331d043c564SKenneth D. Merry }
1332