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