1fd501800SSascha Wildner /*-
2fd501800SSascha Wildner * Copyright (c) 2011-2015 LSI Corp.
3fd501800SSascha Wildner * Copyright (c) 2013-2016 Avago Technologies
4fd501800SSascha Wildner * All rights reserved.
5fd501800SSascha Wildner *
6fd501800SSascha Wildner * Redistribution and use in source and binary forms, with or without
7fd501800SSascha Wildner * modification, are permitted provided that the following conditions
8fd501800SSascha Wildner * are met:
9fd501800SSascha Wildner * 1. Redistributions of source code must retain the above copyright
10fd501800SSascha Wildner * notice, this list of conditions and the following disclaimer.
11fd501800SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
12fd501800SSascha Wildner * notice, this list of conditions and the following disclaimer in the
13fd501800SSascha Wildner * documentation and/or other materials provided with the distribution.
14fd501800SSascha Wildner *
15fd501800SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16fd501800SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17fd501800SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18fd501800SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19fd501800SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20fd501800SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21fd501800SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22fd501800SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23fd501800SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24fd501800SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25fd501800SSascha Wildner * SUCH DAMAGE.
26fd501800SSascha Wildner *
27fd501800SSascha Wildner * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
28fd501800SSascha Wildner *
29fd501800SSascha Wildner * $FreeBSD: head/sys/dev/mpr/mpr_sas_lsi.c 331228 2018-03-19 23:21:45Z mav $
30fd501800SSascha Wildner */
31fd501800SSascha Wildner
32fd501800SSascha Wildner /* Communications core for Avago Technologies (LSI) MPT3 */
33fd501800SSascha Wildner
34fd501800SSascha Wildner /* TODO Move headers to mprvar */
35fd501800SSascha Wildner #include <sys/types.h>
36fd501800SSascha Wildner #include <sys/param.h>
37fd501800SSascha Wildner #include <sys/systm.h>
38fd501800SSascha Wildner #include <sys/kernel.h>
39fd501800SSascha Wildner #include <sys/module.h>
40fd501800SSascha Wildner #include <sys/bus.h>
41fd501800SSascha Wildner #include <sys/conf.h>
42fd501800SSascha Wildner #include <sys/bio.h>
43fd501800SSascha Wildner #include <sys/malloc.h>
44fd501800SSascha Wildner #include <sys/uio.h>
45fd501800SSascha Wildner #include <sys/sysctl.h>
46fd501800SSascha Wildner #include <sys/endian.h>
47fd501800SSascha Wildner #include <sys/queue.h>
48fd501800SSascha Wildner #include <sys/kthread.h>
49fd501800SSascha Wildner #include <sys/taskqueue.h>
50fd501800SSascha Wildner #include <sys/sbuf.h>
51fd501800SSascha Wildner #include <sys/eventhandler.h>
52fd501800SSascha Wildner
53fd501800SSascha Wildner #include <sys/rman.h>
54fd501800SSascha Wildner
55fd501800SSascha Wildner #include <machine/stdarg.h>
56fd501800SSascha Wildner
57fd501800SSascha Wildner #include <bus/cam/cam.h>
58fd501800SSascha Wildner #include <bus/cam/cam_ccb.h>
59fd501800SSascha Wildner #include <bus/cam/cam_debug.h>
60fd501800SSascha Wildner #include <bus/cam/cam_sim.h>
61fd501800SSascha Wildner #include <bus/cam/cam_xpt_sim.h>
62fd501800SSascha Wildner #include <bus/cam/cam_xpt_periph.h>
63fd501800SSascha Wildner #include <bus/cam/cam_periph.h>
64fd501800SSascha Wildner #include <bus/cam/scsi/scsi_all.h>
65fd501800SSascha Wildner #include <bus/cam/scsi/scsi_message.h>
66fd501800SSascha Wildner
67fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_type.h>
68fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2.h>
69fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_ioc.h>
70fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_sas.h>
71fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_pci.h>
72fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_cnfg.h>
73fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_init.h>
74fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_raid.h>
75fd501800SSascha Wildner #include <dev/raid/mpr/mpi/mpi2_tool.h>
76fd501800SSascha Wildner #include <dev/raid/mpr/mpr_ioctl.h>
77fd501800SSascha Wildner #include <dev/raid/mpr/mprvar.h>
78fd501800SSascha Wildner #include <dev/raid/mpr/mpr_table.h>
79fd501800SSascha Wildner #include <dev/raid/mpr/mpr_sas.h>
80fd501800SSascha Wildner
81fd501800SSascha Wildner /* For Hashed SAS Address creation for SATA Drives */
82fd501800SSascha Wildner #define MPT2SAS_SN_LEN 20
83fd501800SSascha Wildner #define MPT2SAS_MN_LEN 40
84fd501800SSascha Wildner
85fd501800SSascha Wildner struct mpr_fw_event_work {
86fd501800SSascha Wildner u16 event;
87fd501800SSascha Wildner void *event_data;
88fd501800SSascha Wildner TAILQ_ENTRY(mpr_fw_event_work) ev_link;
89fd501800SSascha Wildner };
90fd501800SSascha Wildner
91fd501800SSascha Wildner union _sata_sas_address {
92fd501800SSascha Wildner u8 wwid[8];
93fd501800SSascha Wildner struct {
94fd501800SSascha Wildner u32 high;
95fd501800SSascha Wildner u32 low;
96fd501800SSascha Wildner } word;
97fd501800SSascha Wildner };
98fd501800SSascha Wildner
99fd501800SSascha Wildner /*
100fd501800SSascha Wildner * define the IDENTIFY DEVICE structure
101fd501800SSascha Wildner */
102fd501800SSascha Wildner struct _ata_identify_device_data {
103fd501800SSascha Wildner u16 reserved1[10]; /* 0-9 */
104fd501800SSascha Wildner u16 serial_number[10]; /* 10-19 */
105fd501800SSascha Wildner u16 reserved2[7]; /* 20-26 */
106fd501800SSascha Wildner u16 model_number[20]; /* 27-46*/
107fd501800SSascha Wildner u16 reserved3[170]; /* 47-216 */
108fd501800SSascha Wildner u16 rotational_speed; /* 217 */
109fd501800SSascha Wildner u16 reserved4[38]; /* 218-255 */
110fd501800SSascha Wildner };
111fd501800SSascha Wildner static u32 event_count;
112fd501800SSascha Wildner static void mprsas_fw_work(struct mpr_softc *sc,
113fd501800SSascha Wildner struct mpr_fw_event_work *fw_event);
114fd501800SSascha Wildner static void mprsas_fw_event_free(struct mpr_softc *,
115fd501800SSascha Wildner struct mpr_fw_event_work *);
116fd501800SSascha Wildner static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate);
117fd501800SSascha Wildner static int mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle,
118fd501800SSascha Wildner u8 linkrate);
119fd501800SSascha Wildner static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
120fd501800SSascha Wildner Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
121fd501800SSascha Wildner u32 devinfo);
122fd501800SSascha Wildner static void mprsas_ata_id_timeout(void *data);
123fd501800SSascha Wildner int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
124fd501800SSascha Wildner u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD);
125fd501800SSascha Wildner static int mprsas_volume_add(struct mpr_softc *sc,
126fd501800SSascha Wildner u16 handle);
127fd501800SSascha Wildner static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc);
128fd501800SSascha Wildner static void mprsas_stop_unit_done(struct cam_periph *periph,
129fd501800SSascha Wildner union ccb *done_ccb);
130fd501800SSascha Wildner
131fd501800SSascha Wildner void
mprsas_evt_handler(struct mpr_softc * sc,uintptr_t data,MPI2_EVENT_NOTIFICATION_REPLY * event)132fd501800SSascha Wildner mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
133fd501800SSascha Wildner MPI2_EVENT_NOTIFICATION_REPLY *event)
134fd501800SSascha Wildner {
135fd501800SSascha Wildner struct mpr_fw_event_work *fw_event;
136fd501800SSascha Wildner u16 sz;
137fd501800SSascha Wildner
138fd501800SSascha Wildner mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
139fd501800SSascha Wildner MPR_DPRINT_EVENT(sc, sas, event);
140fd501800SSascha Wildner mprsas_record_event(sc, event);
141fd501800SSascha Wildner
142fd501800SSascha Wildner fw_event = kmalloc(sizeof(struct mpr_fw_event_work), M_MPR,
143fd501800SSascha Wildner M_ZERO|M_NOWAIT);
144fd501800SSascha Wildner if (!fw_event) {
145fd501800SSascha Wildner kprintf("%s: allocate failed for fw_event\n", __func__);
146fd501800SSascha Wildner return;
147fd501800SSascha Wildner }
148fd501800SSascha Wildner sz = le16toh(event->EventDataLength) * 4;
149fd501800SSascha Wildner fw_event->event_data = kmalloc(sz, M_MPR, M_ZERO|M_NOWAIT);
150fd501800SSascha Wildner if (!fw_event->event_data) {
151fd501800SSascha Wildner kprintf("%s: allocate failed for event_data\n", __func__);
152fd501800SSascha Wildner kfree(fw_event, M_MPR);
153fd501800SSascha Wildner return;
154fd501800SSascha Wildner }
155fd501800SSascha Wildner
156fd501800SSascha Wildner bcopy(event->EventData, fw_event->event_data, sz);
157fd501800SSascha Wildner fw_event->event = event->Event;
158fd501800SSascha Wildner if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
159fd501800SSascha Wildner event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
160fd501800SSascha Wildner event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
161fd501800SSascha Wildner event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
162fd501800SSascha Wildner sc->track_mapping_events)
163fd501800SSascha Wildner sc->pending_map_events++;
164fd501800SSascha Wildner
165fd501800SSascha Wildner /*
166fd501800SSascha Wildner * When wait_for_port_enable flag is set, make sure that all the events
167fd501800SSascha Wildner * are processed. Increment the startup_refcount and decrement it after
168fd501800SSascha Wildner * events are processed.
169fd501800SSascha Wildner */
170fd501800SSascha Wildner if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
171fd501800SSascha Wildner event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
172fd501800SSascha Wildner event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
173fd501800SSascha Wildner sc->wait_for_port_enable)
174fd501800SSascha Wildner mprsas_startup_increment(sc->sassc);
175fd501800SSascha Wildner
176fd501800SSascha Wildner TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
177fd501800SSascha Wildner taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
178fd501800SSascha Wildner }
179fd501800SSascha Wildner
180fd501800SSascha Wildner static void
mprsas_fw_event_free(struct mpr_softc * sc,struct mpr_fw_event_work * fw_event)181fd501800SSascha Wildner mprsas_fw_event_free(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
182fd501800SSascha Wildner {
183fd501800SSascha Wildner
184fd501800SSascha Wildner kfree(fw_event->event_data, M_MPR);
185fd501800SSascha Wildner kfree(fw_event, M_MPR);
186fd501800SSascha Wildner }
187fd501800SSascha Wildner
188fd501800SSascha Wildner /**
189fd501800SSascha Wildner * _mpr_fw_work - delayed task for processing firmware events
190fd501800SSascha Wildner * @sc: per adapter object
191fd501800SSascha Wildner * @fw_event: The fw_event_work object
192fd501800SSascha Wildner * Context: user.
193fd501800SSascha Wildner *
194fd501800SSascha Wildner * Return nothing.
195fd501800SSascha Wildner */
196fd501800SSascha Wildner static void
mprsas_fw_work(struct mpr_softc * sc,struct mpr_fw_event_work * fw_event)197fd501800SSascha Wildner mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
198fd501800SSascha Wildner {
199fd501800SSascha Wildner struct mprsas_softc *sassc;
200fd501800SSascha Wildner sassc = sc->sassc;
201fd501800SSascha Wildner
202fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Working on Event: [%x]\n",
203fd501800SSascha Wildner event_count++, __func__, fw_event->event);
204fd501800SSascha Wildner switch (fw_event->event) {
205fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
206fd501800SSascha Wildner {
207fd501800SSascha Wildner MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
208fd501800SSascha Wildner MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
209fd501800SSascha Wildner uint8_t i;
210fd501800SSascha Wildner
211fd501800SSascha Wildner data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
212fd501800SSascha Wildner fw_event->event_data;
213fd501800SSascha Wildner
214fd501800SSascha Wildner mpr_mapping_topology_change_event(sc, fw_event->event_data);
215fd501800SSascha Wildner
216fd501800SSascha Wildner for (i = 0; i < data->NumEntries; i++) {
217fd501800SSascha Wildner phy = &data->PHY[i];
218fd501800SSascha Wildner switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
219fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
220fd501800SSascha Wildner if (mprsas_add_device(sc,
221fd501800SSascha Wildner le16toh(phy->AttachedDevHandle),
222fd501800SSascha Wildner phy->LinkRate)) {
223fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "%s: "
224fd501800SSascha Wildner "failed to add device with handle "
225fd501800SSascha Wildner "0x%x\n", __func__,
226fd501800SSascha Wildner le16toh(phy->AttachedDevHandle));
227fd501800SSascha Wildner mprsas_prepare_remove(sassc, le16toh(
228fd501800SSascha Wildner phy->AttachedDevHandle));
229fd501800SSascha Wildner }
230fd501800SSascha Wildner break;
231fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
232fd501800SSascha Wildner mprsas_prepare_remove(sassc, le16toh(
233fd501800SSascha Wildner phy->AttachedDevHandle));
234fd501800SSascha Wildner break;
235fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
236fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
237fd501800SSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
238fd501800SSascha Wildner default:
239fd501800SSascha Wildner break;
240fd501800SSascha Wildner }
241fd501800SSascha Wildner }
242fd501800SSascha Wildner /*
243fd501800SSascha Wildner * refcount was incremented for this event in
244fd501800SSascha Wildner * mprsas_evt_handler. Decrement it here because the event has
245fd501800SSascha Wildner * been processed.
246fd501800SSascha Wildner */
247fd501800SSascha Wildner mprsas_startup_decrement(sassc);
248fd501800SSascha Wildner break;
249fd501800SSascha Wildner }
250fd501800SSascha Wildner case MPI2_EVENT_SAS_DISCOVERY:
251fd501800SSascha Wildner {
252fd501800SSascha Wildner MPI2_EVENT_DATA_SAS_DISCOVERY *data;
253fd501800SSascha Wildner
254fd501800SSascha Wildner data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data;
255fd501800SSascha Wildner
256fd501800SSascha Wildner if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
257fd501800SSascha Wildner mpr_dprint(sc, MPR_TRACE,"SAS discovery start event\n");
258fd501800SSascha Wildner if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
259fd501800SSascha Wildner mpr_dprint(sc, MPR_TRACE,"SAS discovery stop event\n");
260fd501800SSascha Wildner sassc->flags &= ~MPRSAS_IN_DISCOVERY;
261fd501800SSascha Wildner mprsas_discovery_end(sassc);
262fd501800SSascha Wildner }
263fd501800SSascha Wildner break;
264fd501800SSascha Wildner }
265fd501800SSascha Wildner case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
266fd501800SSascha Wildner {
267fd501800SSascha Wildner Mpi2EventDataSasEnclDevStatusChange_t *data;
268fd501800SSascha Wildner data = (Mpi2EventDataSasEnclDevStatusChange_t *)
269fd501800SSascha Wildner fw_event->event_data;
270fd501800SSascha Wildner mpr_mapping_enclosure_dev_status_change_event(sc,
271fd501800SSascha Wildner fw_event->event_data);
272fd501800SSascha Wildner break;
273fd501800SSascha Wildner }
274fd501800SSascha Wildner case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
275fd501800SSascha Wildner {
276fd501800SSascha Wildner Mpi2EventIrConfigElement_t *element;
277fd501800SSascha Wildner int i;
278fd501800SSascha Wildner u8 foreign_config, reason;
279fd501800SSascha Wildner u16 elementType;
280fd501800SSascha Wildner Mpi2EventDataIrConfigChangeList_t *event_data;
281fd501800SSascha Wildner struct mprsas_target *targ;
282fd501800SSascha Wildner unsigned int id;
283fd501800SSascha Wildner
284fd501800SSascha Wildner event_data = fw_event->event_data;
285fd501800SSascha Wildner foreign_config = (le32toh(event_data->Flags) &
286fd501800SSascha Wildner MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
287fd501800SSascha Wildner
288fd501800SSascha Wildner element =
289fd501800SSascha Wildner (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
290fd501800SSascha Wildner id = mpr_mapping_get_raid_tid_from_handle(sc,
291fd501800SSascha Wildner element->VolDevHandle);
292fd501800SSascha Wildner
293fd501800SSascha Wildner mpr_mapping_ir_config_change_event(sc, event_data);
294fd501800SSascha Wildner for (i = 0; i < event_data->NumElements; i++, element++) {
295fd501800SSascha Wildner reason = element->ReasonCode;
296fd501800SSascha Wildner elementType = le16toh(element->ElementFlags) &
297fd501800SSascha Wildner MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
298fd501800SSascha Wildner /*
299fd501800SSascha Wildner * check for element type of Phys Disk or Hot Spare
300fd501800SSascha Wildner */
301fd501800SSascha Wildner if ((elementType !=
302fd501800SSascha Wildner MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT)
303fd501800SSascha Wildner && (elementType !=
304fd501800SSascha Wildner MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT))
305fd501800SSascha Wildner // do next element
306fd501800SSascha Wildner goto skip_fp_send;
307fd501800SSascha Wildner
308fd501800SSascha Wildner /*
309fd501800SSascha Wildner * check for reason of Hide, Unhide, PD Created, or PD
310fd501800SSascha Wildner * Deleted
311fd501800SSascha Wildner */
312fd501800SSascha Wildner if ((reason != MPI2_EVENT_IR_CHANGE_RC_HIDE) &&
313fd501800SSascha Wildner (reason != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) &&
314fd501800SSascha Wildner (reason != MPI2_EVENT_IR_CHANGE_RC_PD_CREATED) &&
315fd501800SSascha Wildner (reason != MPI2_EVENT_IR_CHANGE_RC_PD_DELETED))
316fd501800SSascha Wildner goto skip_fp_send;
317fd501800SSascha Wildner
318fd501800SSascha Wildner // check for a reason of Hide or PD Created
319fd501800SSascha Wildner if ((reason == MPI2_EVENT_IR_CHANGE_RC_HIDE) ||
320fd501800SSascha Wildner (reason == MPI2_EVENT_IR_CHANGE_RC_PD_CREATED))
321fd501800SSascha Wildner {
322fd501800SSascha Wildner // build RAID Action message
323fd501800SSascha Wildner Mpi2RaidActionRequest_t *action;
324fd501800SSascha Wildner Mpi2RaidActionReply_t *reply = NULL;
325fd501800SSascha Wildner struct mpr_command *cm;
326fd501800SSascha Wildner int error = 0;
327fd501800SSascha Wildner if ((cm = mpr_alloc_command(sc)) == NULL) {
328fd501800SSascha Wildner kprintf("%s: command alloc failed\n",
329fd501800SSascha Wildner __func__);
330fd501800SSascha Wildner return;
331fd501800SSascha Wildner }
332fd501800SSascha Wildner
333fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "Sending FP action "
334fd501800SSascha Wildner "from "
335fd501800SSascha Wildner "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST "
336fd501800SSascha Wildner ":\n");
337fd501800SSascha Wildner action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
338fd501800SSascha Wildner action->Function = MPI2_FUNCTION_RAID_ACTION;
339fd501800SSascha Wildner action->Action =
340fd501800SSascha Wildner MPI2_RAID_ACTION_PHYSDISK_HIDDEN;
341fd501800SSascha Wildner action->PhysDiskNum = element->PhysDiskNum;
342fd501800SSascha Wildner cm->cm_desc.Default.RequestFlags =
343fd501800SSascha Wildner MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
344fd501800SSascha Wildner error = mpr_request_polled(sc, &cm);
345fd501800SSascha Wildner if (cm != NULL)
346fd501800SSascha Wildner reply = (Mpi2RaidActionReply_t *)
347fd501800SSascha Wildner cm->cm_reply;
348fd501800SSascha Wildner if (error || (reply == NULL)) {
349fd501800SSascha Wildner /* FIXME */
350fd501800SSascha Wildner /*
351fd501800SSascha Wildner * If the poll returns error then we
352fd501800SSascha Wildner * need to do diag reset
353fd501800SSascha Wildner */
354fd501800SSascha Wildner kprintf("%s: poll for page completed "
355fd501800SSascha Wildner "with error %d", __func__, error);
356fd501800SSascha Wildner }
357fd501800SSascha Wildner if (reply && (le16toh(reply->IOCStatus) &
358fd501800SSascha Wildner MPI2_IOCSTATUS_MASK) !=
359fd501800SSascha Wildner MPI2_IOCSTATUS_SUCCESS) {
360fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "%s: error "
361fd501800SSascha Wildner "sending RaidActionPage; "
362fd501800SSascha Wildner "iocstatus = 0x%x\n", __func__,
363fd501800SSascha Wildner le16toh(reply->IOCStatus));
364fd501800SSascha Wildner }
365fd501800SSascha Wildner
366fd501800SSascha Wildner if (cm)
367fd501800SSascha Wildner mpr_free_command(sc, cm);
368fd501800SSascha Wildner }
369fd501800SSascha Wildner skip_fp_send:
370fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "Received "
371fd501800SSascha Wildner "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST Reason "
372fd501800SSascha Wildner "code %x:\n", element->ReasonCode);
373fd501800SSascha Wildner switch (element->ReasonCode) {
374fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
375fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_ADDED:
376fd501800SSascha Wildner if (!foreign_config) {
377fd501800SSascha Wildner if (mprsas_volume_add(sc,
378fd501800SSascha Wildner le16toh(element->VolDevHandle))) {
379fd501800SSascha Wildner kprintf("%s: failed to add RAID "
380fd501800SSascha Wildner "volume with handle 0x%x\n",
381fd501800SSascha Wildner __func__, le16toh(element->
382fd501800SSascha Wildner VolDevHandle));
383fd501800SSascha Wildner }
384fd501800SSascha Wildner }
385fd501800SSascha Wildner break;
386fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
387fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
388fd501800SSascha Wildner /*
389fd501800SSascha Wildner * Rescan after volume is deleted or removed.
390fd501800SSascha Wildner */
391fd501800SSascha Wildner if (!foreign_config) {
392fd501800SSascha Wildner if (id == MPR_MAP_BAD_ID) {
393fd501800SSascha Wildner kprintf("%s: could not get ID "
394fd501800SSascha Wildner "for volume with handle "
395fd501800SSascha Wildner "0x%04x\n", __func__,
396fd501800SSascha Wildner le16toh(element->
397fd501800SSascha Wildner VolDevHandle));
398fd501800SSascha Wildner break;
399fd501800SSascha Wildner }
400fd501800SSascha Wildner
401fd501800SSascha Wildner targ = &sassc->targets[id];
402fd501800SSascha Wildner targ->handle = 0x0;
403fd501800SSascha Wildner targ->encl_slot = 0x0;
404fd501800SSascha Wildner targ->encl_handle = 0x0;
405fd501800SSascha Wildner targ->encl_level_valid = 0x0;
406fd501800SSascha Wildner targ->encl_level = 0x0;
407fd501800SSascha Wildner targ->connector_name[0] = ' ';
408fd501800SSascha Wildner targ->connector_name[1] = ' ';
409fd501800SSascha Wildner targ->connector_name[2] = ' ';
410fd501800SSascha Wildner targ->connector_name[3] = ' ';
411fd501800SSascha Wildner targ->exp_dev_handle = 0x0;
412fd501800SSascha Wildner targ->phy_num = 0x0;
413fd501800SSascha Wildner targ->linkrate = 0x0;
414fd501800SSascha Wildner mprsas_rescan_target(sc, targ);
415fd501800SSascha Wildner kprintf("RAID target id 0x%x removed\n",
416fd501800SSascha Wildner targ->tid);
417fd501800SSascha Wildner }
418fd501800SSascha Wildner break;
419fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
420fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_HIDE:
421fd501800SSascha Wildner /*
422fd501800SSascha Wildner * Phys Disk of a volume has been created. Hide
423fd501800SSascha Wildner * it from the OS.
424fd501800SSascha Wildner */
425fd501800SSascha Wildner targ = mprsas_find_target_by_handle(sassc, 0,
426fd501800SSascha Wildner element->PhysDiskDevHandle);
427fd501800SSascha Wildner if (targ == NULL)
428fd501800SSascha Wildner break;
429fd501800SSascha Wildner targ->flags |= MPR_TARGET_FLAGS_RAID_COMPONENT;
430fd501800SSascha Wildner mprsas_rescan_target(sc, targ);
431fd501800SSascha Wildner break;
432fd501800SSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
433fd501800SSascha Wildner /*
434fd501800SSascha Wildner * Phys Disk of a volume has been deleted.
435fd501800SSascha Wildner * Expose it to the OS.
436fd501800SSascha Wildner */
437fd501800SSascha Wildner if (mprsas_add_device(sc,
438fd501800SSascha Wildner le16toh(element->PhysDiskDevHandle), 0)) {
439fd501800SSascha Wildner kprintf("%s: failed to add device with "
440fd501800SSascha Wildner "handle 0x%x\n", __func__,
441fd501800SSascha Wildner le16toh(element->
442fd501800SSascha Wildner PhysDiskDevHandle));
443fd501800SSascha Wildner mprsas_prepare_remove(sassc,
444fd501800SSascha Wildner le16toh(element->
445fd501800SSascha Wildner PhysDiskDevHandle));
446fd501800SSascha Wildner }
447fd501800SSascha Wildner break;
448fd501800SSascha Wildner }
449fd501800SSascha Wildner }
450fd501800SSascha Wildner /*
451fd501800SSascha Wildner * refcount was incremented for this event in
452fd501800SSascha Wildner * mprsas_evt_handler. Decrement it here because the event has
453fd501800SSascha Wildner * been processed.
454fd501800SSascha Wildner */
455fd501800SSascha Wildner mprsas_startup_decrement(sassc);
456fd501800SSascha Wildner break;
457fd501800SSascha Wildner }
458fd501800SSascha Wildner case MPI2_EVENT_IR_VOLUME:
459fd501800SSascha Wildner {
460fd501800SSascha Wildner Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
461fd501800SSascha Wildner
462fd501800SSascha Wildner /*
463fd501800SSascha Wildner * Informational only.
464fd501800SSascha Wildner */
465fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "Received IR Volume event:\n");
466fd501800SSascha Wildner switch (event_data->ReasonCode) {
467fd501800SSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
468fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Volume Settings "
469fd501800SSascha Wildner "changed from 0x%x to 0x%x for Volome with "
470fd501800SSascha Wildner "handle 0x%x", le32toh(event_data->PreviousValue),
471fd501800SSascha Wildner le32toh(event_data->NewValue),
472fd501800SSascha Wildner le16toh(event_data->VolDevHandle));
473fd501800SSascha Wildner break;
474fd501800SSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
475fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Volume Status "
476fd501800SSascha Wildner "changed from 0x%x to 0x%x for Volome with "
477fd501800SSascha Wildner "handle 0x%x", le32toh(event_data->PreviousValue),
478fd501800SSascha Wildner le32toh(event_data->NewValue),
479fd501800SSascha Wildner le16toh(event_data->VolDevHandle));
480fd501800SSascha Wildner break;
481fd501800SSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
482fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Volume State "
483fd501800SSascha Wildner "changed from 0x%x to 0x%x for Volome with "
484fd501800SSascha Wildner "handle 0x%x", le32toh(event_data->PreviousValue),
485fd501800SSascha Wildner le32toh(event_data->NewValue),
486fd501800SSascha Wildner le16toh(event_data->VolDevHandle));
487fd501800SSascha Wildner u32 state;
488fd501800SSascha Wildner struct mprsas_target *targ;
489fd501800SSascha Wildner state = le32toh(event_data->NewValue);
490fd501800SSascha Wildner switch (state) {
491fd501800SSascha Wildner case MPI2_RAID_VOL_STATE_MISSING:
492fd501800SSascha Wildner case MPI2_RAID_VOL_STATE_FAILED:
493fd501800SSascha Wildner mprsas_prepare_volume_remove(sassc,
494fd501800SSascha Wildner event_data->VolDevHandle);
495fd501800SSascha Wildner break;
496fd501800SSascha Wildner
497fd501800SSascha Wildner case MPI2_RAID_VOL_STATE_ONLINE:
498fd501800SSascha Wildner case MPI2_RAID_VOL_STATE_DEGRADED:
499fd501800SSascha Wildner case MPI2_RAID_VOL_STATE_OPTIMAL:
500fd501800SSascha Wildner targ =
501fd501800SSascha Wildner mprsas_find_target_by_handle(sassc,
502fd501800SSascha Wildner 0, event_data->VolDevHandle);
503fd501800SSascha Wildner if (targ) {
504fd501800SSascha Wildner kprintf("%s %d: Volume handle "
505fd501800SSascha Wildner "0x%x is already added \n",
506fd501800SSascha Wildner __func__, __LINE__,
507fd501800SSascha Wildner event_data->VolDevHandle);
508fd501800SSascha Wildner break;
509fd501800SSascha Wildner }
510fd501800SSascha Wildner if (mprsas_volume_add(sc,
511fd501800SSascha Wildner le16toh(event_data->
512fd501800SSascha Wildner VolDevHandle))) {
513fd501800SSascha Wildner kprintf("%s: failed to add RAID "
514fd501800SSascha Wildner "volume with handle 0x%x\n",
515fd501800SSascha Wildner __func__, le16toh(
516fd501800SSascha Wildner event_data->VolDevHandle));
517fd501800SSascha Wildner }
518fd501800SSascha Wildner break;
519fd501800SSascha Wildner default:
520fd501800SSascha Wildner break;
521fd501800SSascha Wildner }
522fd501800SSascha Wildner break;
523fd501800SSascha Wildner default:
524fd501800SSascha Wildner break;
525fd501800SSascha Wildner }
526fd501800SSascha Wildner break;
527fd501800SSascha Wildner }
528fd501800SSascha Wildner case MPI2_EVENT_IR_PHYSICAL_DISK:
529fd501800SSascha Wildner {
530fd501800SSascha Wildner Mpi2EventDataIrPhysicalDisk_t *event_data =
531fd501800SSascha Wildner fw_event->event_data;
532fd501800SSascha Wildner struct mprsas_target *targ;
533fd501800SSascha Wildner
534fd501800SSascha Wildner /*
535fd501800SSascha Wildner * Informational only.
536fd501800SSascha Wildner */
537fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "Received IR Phys Disk event:\n");
538fd501800SSascha Wildner switch (event_data->ReasonCode) {
539fd501800SSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
540fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Phys Disk Settings "
541fd501800SSascha Wildner "changed from 0x%x to 0x%x for Phys Disk Number "
542fd501800SSascha Wildner "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
543fd501800SSascha Wildner "%d", le32toh(event_data->PreviousValue),
544fd501800SSascha Wildner le32toh(event_data->NewValue),
545fd501800SSascha Wildner event_data->PhysDiskNum,
546fd501800SSascha Wildner le16toh(event_data->PhysDiskDevHandle),
547fd501800SSascha Wildner le16toh(event_data->EnclosureHandle),
548fd501800SSascha Wildner le16toh(event_data->Slot));
549fd501800SSascha Wildner break;
550fd501800SSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
551fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Phys Disk Status changed "
552fd501800SSascha Wildner "from 0x%x to 0x%x for Phys Disk Number %d and "
553fd501800SSascha Wildner "handle 0x%x at Enclosure handle 0x%x, Slot %d",
554fd501800SSascha Wildner le32toh(event_data->PreviousValue),
555fd501800SSascha Wildner le32toh(event_data->NewValue),
556fd501800SSascha Wildner event_data->PhysDiskNum,
557fd501800SSascha Wildner le16toh(event_data->PhysDiskDevHandle),
558fd501800SSascha Wildner le16toh(event_data->EnclosureHandle),
559fd501800SSascha Wildner le16toh(event_data->Slot));
560fd501800SSascha Wildner break;
561fd501800SSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
562fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " Phys Disk State changed "
563fd501800SSascha Wildner "from 0x%x to 0x%x for Phys Disk Number %d and "
564fd501800SSascha Wildner "handle 0x%x at Enclosure handle 0x%x, Slot %d",
565fd501800SSascha Wildner le32toh(event_data->PreviousValue),
566fd501800SSascha Wildner le32toh(event_data->NewValue),
567fd501800SSascha Wildner event_data->PhysDiskNum,
568fd501800SSascha Wildner le16toh(event_data->PhysDiskDevHandle),
569fd501800SSascha Wildner le16toh(event_data->EnclosureHandle),
570fd501800SSascha Wildner le16toh(event_data->Slot));
571fd501800SSascha Wildner switch (event_data->NewValue) {
572fd501800SSascha Wildner case MPI2_RAID_PD_STATE_ONLINE:
573fd501800SSascha Wildner case MPI2_RAID_PD_STATE_DEGRADED:
574fd501800SSascha Wildner case MPI2_RAID_PD_STATE_REBUILDING:
575fd501800SSascha Wildner case MPI2_RAID_PD_STATE_OPTIMAL:
576fd501800SSascha Wildner case MPI2_RAID_PD_STATE_HOT_SPARE:
577fd501800SSascha Wildner targ = mprsas_find_target_by_handle(
578fd501800SSascha Wildner sassc, 0,
579fd501800SSascha Wildner event_data->PhysDiskDevHandle);
580fd501800SSascha Wildner if (targ) {
581fd501800SSascha Wildner targ->flags |=
582fd501800SSascha Wildner MPR_TARGET_FLAGS_RAID_COMPONENT;
583fd501800SSascha Wildner kprintf("%s %d: Found Target "
584fd501800SSascha Wildner "for handle 0x%x.\n",
585fd501800SSascha Wildner __func__, __LINE__ ,
586fd501800SSascha Wildner event_data->
587fd501800SSascha Wildner PhysDiskDevHandle);
588fd501800SSascha Wildner }
589fd501800SSascha Wildner break;
590fd501800SSascha Wildner case MPI2_RAID_PD_STATE_OFFLINE:
591fd501800SSascha Wildner case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
592fd501800SSascha Wildner case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
593fd501800SSascha Wildner default:
594fd501800SSascha Wildner targ = mprsas_find_target_by_handle(
595fd501800SSascha Wildner sassc, 0,
596fd501800SSascha Wildner event_data->PhysDiskDevHandle);
597fd501800SSascha Wildner if (targ) {
598fd501800SSascha Wildner targ->flags |=
599fd501800SSascha Wildner ~MPR_TARGET_FLAGS_RAID_COMPONENT;
600fd501800SSascha Wildner kprintf("%s %d: Found Target "
601fd501800SSascha Wildner "for handle 0x%x. \n",
602fd501800SSascha Wildner __func__, __LINE__ ,
603fd501800SSascha Wildner event_data->
604fd501800SSascha Wildner PhysDiskDevHandle);
605fd501800SSascha Wildner }
606fd501800SSascha Wildner break;
607fd501800SSascha Wildner }
608fd501800SSascha Wildner default:
609fd501800SSascha Wildner break;
610fd501800SSascha Wildner }
611fd501800SSascha Wildner break;
612fd501800SSascha Wildner }
613fd501800SSascha Wildner case MPI2_EVENT_IR_OPERATION_STATUS:
614fd501800SSascha Wildner {
615fd501800SSascha Wildner Mpi2EventDataIrOperationStatus_t *event_data =
616fd501800SSascha Wildner fw_event->event_data;
617fd501800SSascha Wildner
618fd501800SSascha Wildner /*
619fd501800SSascha Wildner * Informational only.
620fd501800SSascha Wildner */
621fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "Received IR Op Status event:\n");
622fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, " RAID Operation of %d is %d "
623fd501800SSascha Wildner "percent complete for Volume with handle 0x%x",
624fd501800SSascha Wildner event_data->RAIDOperation, event_data->PercentComplete,
625fd501800SSascha Wildner le16toh(event_data->VolDevHandle));
626fd501800SSascha Wildner break;
627fd501800SSascha Wildner }
628fd501800SSascha Wildner case MPI2_EVENT_TEMP_THRESHOLD:
629fd501800SSascha Wildner {
630fd501800SSascha Wildner pMpi2EventDataTemperature_t temp_event;
631fd501800SSascha Wildner
632fd501800SSascha Wildner temp_event = (pMpi2EventDataTemperature_t)fw_event->event_data;
633fd501800SSascha Wildner
634fd501800SSascha Wildner /*
635fd501800SSascha Wildner * The Temp Sensor Count must be greater than the event's Sensor
636fd501800SSascha Wildner * Num to be valid. If valid, print the temp thresholds that
637fd501800SSascha Wildner * have been exceeded.
638fd501800SSascha Wildner */
639fd501800SSascha Wildner if (sc->iounit_pg8.NumSensors > temp_event->SensorNum) {
640fd501800SSascha Wildner mpr_dprint(sc, MPR_FAULT, "Temperature Threshold flags "
641fd501800SSascha Wildner "%s %s %s %s exceeded for Sensor: %d !!!\n",
642fd501800SSascha Wildner ((temp_event->Status & 0x01) == 1) ? "0 " : " ",
643fd501800SSascha Wildner ((temp_event->Status & 0x02) == 2) ? "1 " : " ",
644fd501800SSascha Wildner ((temp_event->Status & 0x04) == 4) ? "2 " : " ",
645fd501800SSascha Wildner ((temp_event->Status & 0x08) == 8) ? "3 " : " ",
646fd501800SSascha Wildner temp_event->SensorNum);
647fd501800SSascha Wildner mpr_dprint(sc, MPR_FAULT, "Current Temp in Celsius: "
648fd501800SSascha Wildner "%d\n", temp_event->CurrentTemperature);
649fd501800SSascha Wildner }
650fd501800SSascha Wildner break;
651fd501800SSascha Wildner }
652fd501800SSascha Wildner case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION:
653fd501800SSascha Wildner {
654fd501800SSascha Wildner pMpi26EventDataActiveCableExcept_t ace_event_data;
655fd501800SSascha Wildner ace_event_data =
656fd501800SSascha Wildner (pMpi26EventDataActiveCableExcept_t)fw_event->event_data;
657fd501800SSascha Wildner
658fd501800SSascha Wildner switch(ace_event_data->ReasonCode) {
659fd501800SSascha Wildner case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER:
660fd501800SSascha Wildner {
661fd501800SSascha Wildner mpr_printf(sc, "Currently a cable with "
662fd501800SSascha Wildner "ReceptacleID %d cannot be powered and device "
663fd501800SSascha Wildner "connected to this active cable will not be seen. "
664fd501800SSascha Wildner "This active cable requires %d mW of power.\n",
665fd501800SSascha Wildner ace_event_data->ReceptacleID,
666fd501800SSascha Wildner ace_event_data->ActiveCablePowerRequirement);
667fd501800SSascha Wildner break;
668fd501800SSascha Wildner }
669fd501800SSascha Wildner case MPI26_EVENT_ACTIVE_CABLE_DEGRADED:
670fd501800SSascha Wildner {
671fd501800SSascha Wildner mpr_printf(sc, "Currently a cable with "
672fd501800SSascha Wildner "ReceptacleID %d is not running at optimal speed "
673fd501800SSascha Wildner "(12 Gb/s rate)\n", ace_event_data->ReceptacleID);
674fd501800SSascha Wildner break;
675fd501800SSascha Wildner }
676fd501800SSascha Wildner default:
677fd501800SSascha Wildner break;
678fd501800SSascha Wildner }
679fd501800SSascha Wildner break;
680fd501800SSascha Wildner }
681fd501800SSascha Wildner case MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
682fd501800SSascha Wildner {
683fd501800SSascha Wildner pMpi25EventDataSasDeviceDiscoveryError_t discovery_error_data;
684fd501800SSascha Wildner uint64_t sas_address;
685fd501800SSascha Wildner
686fd501800SSascha Wildner discovery_error_data =
687fd501800SSascha Wildner (pMpi25EventDataSasDeviceDiscoveryError_t)
688fd501800SSascha Wildner fw_event->event_data;
689fd501800SSascha Wildner
690fd501800SSascha Wildner sas_address = discovery_error_data->SASAddress.High;
691fd501800SSascha Wildner sas_address = (sas_address << 32) |
692fd501800SSascha Wildner discovery_error_data->SASAddress.Low;
693fd501800SSascha Wildner
694fd501800SSascha Wildner switch(discovery_error_data->ReasonCode) {
695fd501800SSascha Wildner case MPI25_EVENT_SAS_DISC_ERR_SMP_FAILED:
696fd501800SSascha Wildner {
697fd501800SSascha Wildner mpr_printf(sc, "SMP command failed during discovery "
698fd501800SSascha Wildner "for expander with SAS Address %jx and "
699fd501800SSascha Wildner "handle 0x%x.\n", sas_address,
700fd501800SSascha Wildner discovery_error_data->DevHandle);
701fd501800SSascha Wildner break;
702fd501800SSascha Wildner }
703fd501800SSascha Wildner case MPI25_EVENT_SAS_DISC_ERR_SMP_TIMEOUT:
704fd501800SSascha Wildner {
705fd501800SSascha Wildner mpr_printf(sc, "SMP command timed out during "
706fd501800SSascha Wildner "discovery for expander with SAS Address %jx and "
707fd501800SSascha Wildner "handle 0x%x.\n", sas_address,
708fd501800SSascha Wildner discovery_error_data->DevHandle);
709fd501800SSascha Wildner break;
710fd501800SSascha Wildner }
711fd501800SSascha Wildner default:
712fd501800SSascha Wildner break;
713fd501800SSascha Wildner }
714fd501800SSascha Wildner break;
715fd501800SSascha Wildner }
716fd501800SSascha Wildner case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
717fd501800SSascha Wildner {
718fd501800SSascha Wildner MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *data;
719fd501800SSascha Wildner MPI26_EVENT_PCIE_TOPO_PORT_ENTRY *port_entry;
720fd501800SSascha Wildner uint8_t i, link_rate;
721fd501800SSascha Wildner uint16_t handle;
722fd501800SSascha Wildner
723fd501800SSascha Wildner data = (MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *)
724fd501800SSascha Wildner fw_event->event_data;
725fd501800SSascha Wildner
726fd501800SSascha Wildner mpr_mapping_pcie_topology_change_event(sc,
727fd501800SSascha Wildner fw_event->event_data);
728fd501800SSascha Wildner
729fd501800SSascha Wildner for (i = 0; i < data->NumEntries; i++) {
730fd501800SSascha Wildner port_entry = &data->PortEntry[i];
731fd501800SSascha Wildner handle = le16toh(port_entry->AttachedDevHandle);
732fd501800SSascha Wildner link_rate = port_entry->CurrentPortInfo &
733fd501800SSascha Wildner MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK;
734fd501800SSascha Wildner switch (port_entry->PortStatus) {
735fd501800SSascha Wildner case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
736fd501800SSascha Wildner if (link_rate <
737fd501800SSascha Wildner MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) {
738fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "%s: Cannot "
739fd501800SSascha Wildner "add PCIe device with handle 0x%x "
740fd501800SSascha Wildner "with unknown link rate.\n",
741fd501800SSascha Wildner __func__, handle);
742fd501800SSascha Wildner break;
743fd501800SSascha Wildner }
744fd501800SSascha Wildner if (mprsas_add_pcie_device(sc, handle,
745fd501800SSascha Wildner link_rate)) {
746fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "%s: failed "
747fd501800SSascha Wildner "to add PCIe device with handle "
748fd501800SSascha Wildner "0x%x\n", __func__, handle);
749fd501800SSascha Wildner mprsas_prepare_remove(sassc, handle);
750fd501800SSascha Wildner }
751fd501800SSascha Wildner break;
752fd501800SSascha Wildner case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
753fd501800SSascha Wildner mprsas_prepare_remove(sassc, handle);
754fd501800SSascha Wildner break;
755fd501800SSascha Wildner case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
756fd501800SSascha Wildner case MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE:
757fd501800SSascha Wildner case MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
758fd501800SSascha Wildner default:
759fd501800SSascha Wildner break;
760fd501800SSascha Wildner }
761fd501800SSascha Wildner }
762fd501800SSascha Wildner /*
763fd501800SSascha Wildner * refcount was incremented for this event in
764fd501800SSascha Wildner * mprsas_evt_handler. Decrement it here because the event has
765fd501800SSascha Wildner * been processed.
766fd501800SSascha Wildner */
767fd501800SSascha Wildner mprsas_startup_decrement(sassc);
768fd501800SSascha Wildner break;
769fd501800SSascha Wildner }
770fd501800SSascha Wildner case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
771fd501800SSascha Wildner case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
772fd501800SSascha Wildner default:
773fd501800SSascha Wildner mpr_dprint(sc, MPR_TRACE,"Unhandled event 0x%0X\n",
774fd501800SSascha Wildner fw_event->event);
775fd501800SSascha Wildner break;
776fd501800SSascha Wildner
777fd501800SSascha Wildner }
778fd501800SSascha Wildner mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count,
779fd501800SSascha Wildner __func__, fw_event->event);
780fd501800SSascha Wildner mprsas_fw_event_free(sc, fw_event);
781fd501800SSascha Wildner }
782fd501800SSascha Wildner
783fd501800SSascha Wildner void
mprsas_firmware_event_work(void * arg,int pending)784fd501800SSascha Wildner mprsas_firmware_event_work(void *arg, int pending)
785fd501800SSascha Wildner {
786fd501800SSascha Wildner struct mpr_fw_event_work *fw_event;
787fd501800SSascha Wildner struct mpr_softc *sc;
788fd501800SSascha Wildner
789fd501800SSascha Wildner sc = (struct mpr_softc *)arg;
790fd501800SSascha Wildner mpr_lock(sc);
791fd501800SSascha Wildner while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) {
792fd501800SSascha Wildner TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link);
793fd501800SSascha Wildner mprsas_fw_work(sc, fw_event);
794fd501800SSascha Wildner }
795fd501800SSascha Wildner mpr_unlock(sc);
796fd501800SSascha Wildner }
797fd501800SSascha Wildner
798fd501800SSascha Wildner static int
mprsas_add_device(struct mpr_softc * sc,u16 handle,u8 linkrate)799fd501800SSascha Wildner mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
800fd501800SSascha Wildner {
801fd501800SSascha Wildner char devstring[80];
802fd501800SSascha Wildner struct mprsas_softc *sassc;
803fd501800SSascha Wildner struct mprsas_target *targ;
804fd501800SSascha Wildner Mpi2ConfigReply_t mpi_reply;
805fd501800SSascha Wildner Mpi2SasDevicePage0_t config_page;
806fd501800SSascha Wildner uint64_t sas_address, parent_sas_address = 0;
807fd501800SSascha Wildner u32 device_info, parent_devinfo = 0;
808fd501800SSascha Wildner unsigned int id;
809fd501800SSascha Wildner int ret = 1, error = 0, i;
810fd501800SSascha Wildner struct mprsas_lun *lun;
811fd501800SSascha Wildner u8 is_SATA_SSD = 0;
812fd501800SSascha Wildner struct mpr_command *cm;
813fd501800SSascha Wildner
814fd501800SSascha Wildner sassc = sc->sassc;
815fd501800SSascha Wildner mprsas_startup_increment(sassc);
816fd501800SSascha Wildner if (mpr_config_get_sas_device_pg0(sc, &mpi_reply, &config_page,
817fd501800SSascha Wildner MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle) != 0) {
818fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO|MPR_MAPPING|MPR_FAULT,
819fd501800SSascha Wildner "Error reading SAS device %#x page0, iocstatus= 0x%x\n",
820fd501800SSascha Wildner handle, mpi_reply.IOCStatus);
821fd501800SSascha Wildner error = ENXIO;
822fd501800SSascha Wildner goto out;
823fd501800SSascha Wildner }
824fd501800SSascha Wildner
825fd501800SSascha Wildner device_info = le32toh(config_page.DeviceInfo);
826fd501800SSascha Wildner
827fd501800SSascha Wildner if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0)
828fd501800SSascha Wildner && (le16toh(config_page.ParentDevHandle) != 0)) {
829fd501800SSascha Wildner Mpi2ConfigReply_t tmp_mpi_reply;
830fd501800SSascha Wildner Mpi2SasDevicePage0_t parent_config_page;
831fd501800SSascha Wildner
832fd501800SSascha Wildner if (mpr_config_get_sas_device_pg0(sc, &tmp_mpi_reply,
833fd501800SSascha Wildner &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
834fd501800SSascha Wildner le16toh(config_page.ParentDevHandle)) != 0) {
835fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING|MPR_FAULT,
836fd501800SSascha Wildner "Error reading parent SAS device %#x page0, "
837fd501800SSascha Wildner "iocstatus= 0x%x\n",
838fd501800SSascha Wildner le16toh(config_page.ParentDevHandle),
839fd501800SSascha Wildner tmp_mpi_reply.IOCStatus);
840fd501800SSascha Wildner } else {
841fd501800SSascha Wildner parent_sas_address = parent_config_page.SASAddress.High;
842fd501800SSascha Wildner parent_sas_address = (parent_sas_address << 32) |
843fd501800SSascha Wildner parent_config_page.SASAddress.Low;
844fd501800SSascha Wildner parent_devinfo = le32toh(parent_config_page.DeviceInfo);
845fd501800SSascha Wildner }
846fd501800SSascha Wildner }
847fd501800SSascha Wildner /* TODO Check proper endianness */
848fd501800SSascha Wildner sas_address = config_page.SASAddress.High;
849fd501800SSascha Wildner sas_address = (sas_address << 32) | config_page.SASAddress.Low;
850fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "Handle 0x%04x SAS Address from SAS device "
851fd501800SSascha Wildner "page0 = %jx\n", handle, sas_address);
852fd501800SSascha Wildner
853fd501800SSascha Wildner /*
854fd501800SSascha Wildner * Always get SATA Identify information because this is used to
855fd501800SSascha Wildner * determine if Start/Stop Unit should be sent to the drive when the
856fd501800SSascha Wildner * system is shutdown.
857fd501800SSascha Wildner */
858fd501800SSascha Wildner if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
859fd501800SSascha Wildner ret = mprsas_get_sas_address_for_sata_disk(sc, &sas_address,
860fd501800SSascha Wildner handle, device_info, &is_SATA_SSD);
861fd501800SSascha Wildner if (ret) {
862fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING|MPR_ERROR,
863fd501800SSascha Wildner "%s: failed to get disk type (SSD or HDD) for SATA "
864fd501800SSascha Wildner "device with handle 0x%04x\n",
865fd501800SSascha Wildner __func__, handle);
866fd501800SSascha Wildner } else {
867fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "Handle 0x%04x SAS Address "
868fd501800SSascha Wildner "from SATA device = %jx\n", handle, sas_address);
869fd501800SSascha Wildner }
870fd501800SSascha Wildner }
871fd501800SSascha Wildner
872fd501800SSascha Wildner /*
873fd501800SSascha Wildner * use_phynum:
874fd501800SSascha Wildner * 1 - use the PhyNum field as a fallback to the mapping logic
875fd501800SSascha Wildner * 0 - never use the PhyNum field
876fd501800SSascha Wildner * -1 - only use the PhyNum field
877fd501800SSascha Wildner *
878fd501800SSascha Wildner * Note that using the Phy number to map a device can cause device adds
879fd501800SSascha Wildner * to fail if multiple enclosures/expanders are in the topology. For
880fd501800SSascha Wildner * example, if two devices are in the same slot number in two different
881fd501800SSascha Wildner * enclosures within the topology, only one of those devices will be
882fd501800SSascha Wildner * added. PhyNum mapping should not be used if multiple enclosures are
883fd501800SSascha Wildner * in the topology.
884fd501800SSascha Wildner */
885fd501800SSascha Wildner id = MPR_MAP_BAD_ID;
886fd501800SSascha Wildner if (sc->use_phynum != -1)
887fd501800SSascha Wildner id = mpr_mapping_get_tid(sc, sas_address, handle);
888fd501800SSascha Wildner if (id == MPR_MAP_BAD_ID) {
889fd501800SSascha Wildner if ((sc->use_phynum == 0) ||
890fd501800SSascha Wildner ((id = config_page.PhyNum) > sassc->maxtargets)) {
891fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "failure at %s:%d/%s()! "
892fd501800SSascha Wildner "Could not get ID for device with handle 0x%04x\n",
893fd501800SSascha Wildner __FILE__, __LINE__, __func__, handle);
894fd501800SSascha Wildner error = ENXIO;
895fd501800SSascha Wildner goto out;
896fd501800SSascha Wildner }
897fd501800SSascha Wildner }
898fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "%s: Target ID for added device is %d.\n",
899fd501800SSascha Wildner __func__, id);
900fd501800SSascha Wildner
901fd501800SSascha Wildner /*
902fd501800SSascha Wildner * Only do the ID check and reuse check if the target is not from a
903fd501800SSascha Wildner * RAID Component. For Physical Disks of a Volume, the ID will be reused
904fd501800SSascha Wildner * when a volume is deleted because the mapping entry for the PD will
905fd501800SSascha Wildner * still be in the mapping table. The ID check should not be done here
906fd501800SSascha Wildner * either since this PD is already being used.
907fd501800SSascha Wildner */
908fd501800SSascha Wildner targ = &sassc->targets[id];
909fd501800SSascha Wildner if (!(targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT)) {
910fd501800SSascha Wildner if (mprsas_check_id(sassc, id) != 0) {
911fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING|MPR_INFO,
912fd501800SSascha Wildner "Excluding target id %d\n", id);
913fd501800SSascha Wildner error = ENXIO;
914fd501800SSascha Wildner goto out;
915fd501800SSascha Wildner }
916fd501800SSascha Wildner
917fd501800SSascha Wildner if (targ->handle != 0x0) {
918fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "Attempting to reuse "
919fd501800SSascha Wildner "target id %d handle 0x%04x\n", id, targ->handle);
920fd501800SSascha Wildner error = ENXIO;
921fd501800SSascha Wildner goto out;
922fd501800SSascha Wildner }
923fd501800SSascha Wildner }
924fd501800SSascha Wildner
925fd501800SSascha Wildner targ->devinfo = device_info;
926fd501800SSascha Wildner targ->devname = le32toh(config_page.DeviceName.High);
927fd501800SSascha Wildner targ->devname = (targ->devname << 32) |
928fd501800SSascha Wildner le32toh(config_page.DeviceName.Low);
929fd501800SSascha Wildner targ->encl_handle = le16toh(config_page.EnclosureHandle);
930fd501800SSascha Wildner targ->encl_slot = le16toh(config_page.Slot);
931fd501800SSascha Wildner targ->encl_level = config_page.EnclosureLevel;
932fd501800SSascha Wildner targ->connector_name[0] = config_page.ConnectorName[0];
933fd501800SSascha Wildner targ->connector_name[1] = config_page.ConnectorName[1];
934fd501800SSascha Wildner targ->connector_name[2] = config_page.ConnectorName[2];
935fd501800SSascha Wildner targ->connector_name[3] = config_page.ConnectorName[3];
936fd501800SSascha Wildner targ->handle = handle;
937fd501800SSascha Wildner targ->parent_handle = le16toh(config_page.ParentDevHandle);
938fd501800SSascha Wildner targ->sasaddr = mpr_to_u64(&config_page.SASAddress);
939fd501800SSascha Wildner targ->parent_sasaddr = le64toh(parent_sas_address);
940fd501800SSascha Wildner targ->parent_devinfo = parent_devinfo;
941fd501800SSascha Wildner targ->tid = id;
942fd501800SSascha Wildner targ->linkrate = (linkrate>>4);
943fd501800SSascha Wildner targ->flags = 0;
944fd501800SSascha Wildner if (is_SATA_SSD) {
945fd501800SSascha Wildner targ->flags = MPR_TARGET_IS_SATA_SSD;
946fd501800SSascha Wildner }
947fd501800SSascha Wildner if ((le16toh(config_page.Flags) &
948fd501800SSascha Wildner MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
949fd501800SSascha Wildner (le16toh(config_page.Flags) &
950fd501800SSascha Wildner MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE)) {
951fd501800SSascha Wildner targ->scsi_req_desc_type =
952fd501800SSascha Wildner MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
953fd501800SSascha Wildner }
954fd501800SSascha Wildner if (le16toh(config_page.Flags) &
955fd501800SSascha Wildner MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
956fd501800SSascha Wildner targ->encl_level_valid = TRUE;
957fd501800SSascha Wildner }
958fd501800SSascha Wildner TAILQ_INIT(&targ->commands);
959fd501800SSascha Wildner TAILQ_INIT(&targ->timedout_commands);
960fd501800SSascha Wildner while (!SLIST_EMPTY(&targ->luns)) {
961fd501800SSascha Wildner lun = SLIST_FIRST(&targ->luns);
962fd501800SSascha Wildner SLIST_REMOVE_HEAD(&targ->luns, lun_link);
963fd501800SSascha Wildner kfree(lun, M_MPR);
964fd501800SSascha Wildner }
965fd501800SSascha Wildner SLIST_INIT(&targ->luns);
966fd501800SSascha Wildner
967fd501800SSascha Wildner mpr_describe_devinfo(targ->devinfo, devstring, 80);
968fd501800SSascha Wildner mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "Found device <%s> <%s> "
969fd501800SSascha Wildner "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
970fd501800SSascha Wildner mpr_describe_table(mpr_linkrate_names, targ->linkrate),
971fd501800SSascha Wildner targ->handle, targ->encl_handle, targ->encl_slot);
972fd501800SSascha Wildner if (targ->encl_level_valid) {
973fd501800SSascha Wildner mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d "
974fd501800SSascha Wildner "and connector name (%4s)\n", targ->encl_level,
975fd501800SSascha Wildner targ->connector_name);
976fd501800SSascha Wildner }
977b9788dabSSascha Wildner #if 1 /* ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
978b9788dabSSascha Wildner (__FreeBSD_version < 902502) */
979fd501800SSascha Wildner if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
980fd501800SSascha Wildner #endif
981fd501800SSascha Wildner mprsas_rescan_target(sc, targ);
982fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid);
983fd501800SSascha Wildner
984fd501800SSascha Wildner /*
985fd501800SSascha Wildner * Check all commands to see if the SATA_ID_TIMEOUT flag has been set.
986fd501800SSascha Wildner * If so, send a Target Reset TM to the target that was just created.
987fd501800SSascha Wildner * An Abort Task TM should be used instead of a Target Reset, but that
988fd501800SSascha Wildner * would be much more difficult because targets have not been fully
989fd501800SSascha Wildner * discovered yet, and LUN's haven't been setup. So, just reset the
990fd501800SSascha Wildner * target instead of the LUN.
991fd501800SSascha Wildner */
992fd501800SSascha Wildner for (i = 1; i < sc->num_reqs; i++) {
993fd501800SSascha Wildner cm = &sc->commands[i];
994fd501800SSascha Wildner if (cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) {
995fd501800SSascha Wildner targ->timeouts++;
996fd501800SSascha Wildner cm->cm_state = MPR_CM_STATE_TIMEDOUT;
997fd501800SSascha Wildner
998fd501800SSascha Wildner if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) {
999fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "%s: sending Target "
1000fd501800SSascha Wildner "Reset for stuck SATA identify command "
1001fd501800SSascha Wildner "(cm = %p)\n", __func__, cm);
1002fd501800SSascha Wildner targ->tm->cm_targ = targ;
1003fd501800SSascha Wildner mprsas_send_reset(sc, targ->tm,
1004fd501800SSascha Wildner MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1005fd501800SSascha Wildner } else {
1006fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "Failed to allocate "
1007fd501800SSascha Wildner "tm for Target Reset after SATA ID command "
1008fd501800SSascha Wildner "timed out (cm %p)\n", cm);
1009fd501800SSascha Wildner }
1010fd501800SSascha Wildner /*
1011fd501800SSascha Wildner * No need to check for more since the target is
1012fd501800SSascha Wildner * already being reset.
1013fd501800SSascha Wildner */
1014fd501800SSascha Wildner break;
1015fd501800SSascha Wildner }
1016fd501800SSascha Wildner }
1017fd501800SSascha Wildner out:
1018fd501800SSascha Wildner /*
1019fd501800SSascha Wildner * Free the commands that may not have been freed from the SATA ID call
1020fd501800SSascha Wildner */
1021fd501800SSascha Wildner for (i = 1; i < sc->num_reqs; i++) {
1022fd501800SSascha Wildner cm = &sc->commands[i];
1023fd501800SSascha Wildner if (cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) {
1024fd501800SSascha Wildner mpr_free_command(sc, cm);
1025fd501800SSascha Wildner }
1026fd501800SSascha Wildner }
1027fd501800SSascha Wildner mprsas_startup_decrement(sassc);
1028fd501800SSascha Wildner return (error);
1029fd501800SSascha Wildner }
1030fd501800SSascha Wildner
1031fd501800SSascha Wildner int
mprsas_get_sas_address_for_sata_disk(struct mpr_softc * sc,u64 * sas_address,u16 handle,u32 device_info,u8 * is_SATA_SSD)1032fd501800SSascha Wildner mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
1033fd501800SSascha Wildner u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD)
1034fd501800SSascha Wildner {
1035fd501800SSascha Wildner Mpi2SataPassthroughReply_t mpi_reply;
1036fd501800SSascha Wildner int i, rc, try_count;
1037fd501800SSascha Wildner u32 *bufferptr;
1038fd501800SSascha Wildner union _sata_sas_address hash_address;
1039fd501800SSascha Wildner struct _ata_identify_device_data ata_identify;
1040fd501800SSascha Wildner u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN];
1041fd501800SSascha Wildner u32 ioc_status;
1042fd501800SSascha Wildner u8 sas_status;
1043fd501800SSascha Wildner
1044fd501800SSascha Wildner memset(&ata_identify, 0, sizeof(ata_identify));
1045fd501800SSascha Wildner memset(&mpi_reply, 0, sizeof(mpi_reply));
1046fd501800SSascha Wildner try_count = 0;
1047fd501800SSascha Wildner do {
1048fd501800SSascha Wildner rc = mprsas_get_sata_identify(sc, handle, &mpi_reply,
1049fd501800SSascha Wildner (char *)&ata_identify, sizeof(ata_identify), device_info);
1050fd501800SSascha Wildner try_count++;
1051fd501800SSascha Wildner ioc_status = le16toh(mpi_reply.IOCStatus)
1052fd501800SSascha Wildner & MPI2_IOCSTATUS_MASK;
1053fd501800SSascha Wildner sas_status = mpi_reply.SASStatus;
1054fd501800SSascha Wildner switch (ioc_status) {
1055fd501800SSascha Wildner case MPI2_IOCSTATUS_SUCCESS:
1056fd501800SSascha Wildner break;
1057fd501800SSascha Wildner case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
1058fd501800SSascha Wildner /* No sense sleeping. this error won't get better */
1059fd501800SSascha Wildner break;
1060fd501800SSascha Wildner default:
1061fd501800SSascha Wildner if (sc->spinup_wait_time > 0) {
1062fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "Sleeping %d seconds "
1063fd501800SSascha Wildner "after SATA ID error to wait for spinup\n",
1064fd501800SSascha Wildner sc->spinup_wait_time);
1065fd501800SSascha Wildner lksleep(&sc->msleep_fake_chan, &sc->mpr_lock, 0,
1066fd501800SSascha Wildner "mprid", sc->spinup_wait_time * hz);
1067fd501800SSascha Wildner }
1068fd501800SSascha Wildner }
1069fd501800SSascha Wildner } while (((rc && (rc != EWOULDBLOCK)) ||
1070fd501800SSascha Wildner (ioc_status && (ioc_status != MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR))
1071fd501800SSascha Wildner || sas_status) && (try_count < 5));
1072fd501800SSascha Wildner
1073fd501800SSascha Wildner if (rc == 0 && !ioc_status && !sas_status) {
1074fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "%s: got SATA identify "
1075fd501800SSascha Wildner "successfully for handle = 0x%x with try_count = %d\n",
1076fd501800SSascha Wildner __func__, handle, try_count);
1077fd501800SSascha Wildner } else {
1078fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "%s: handle = 0x%x failed\n",
1079fd501800SSascha Wildner __func__, handle);
1080fd501800SSascha Wildner return -1;
1081fd501800SSascha Wildner }
1082fd501800SSascha Wildner /* Copy & byteswap the 40 byte model number to a buffer */
1083fd501800SSascha Wildner for (i = 0; i < MPT2SAS_MN_LEN; i += 2) {
1084fd501800SSascha Wildner buffer[i] = ((u8 *)ata_identify.model_number)[i + 1];
1085fd501800SSascha Wildner buffer[i + 1] = ((u8 *)ata_identify.model_number)[i];
1086fd501800SSascha Wildner }
1087fd501800SSascha Wildner /* Copy & byteswap the 20 byte serial number to a buffer */
1088fd501800SSascha Wildner for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
1089fd501800SSascha Wildner buffer[MPT2SAS_MN_LEN + i] =
1090fd501800SSascha Wildner ((u8 *)ata_identify.serial_number)[i + 1];
1091fd501800SSascha Wildner buffer[MPT2SAS_MN_LEN + i + 1] =
1092fd501800SSascha Wildner ((u8 *)ata_identify.serial_number)[i];
1093fd501800SSascha Wildner }
1094fd501800SSascha Wildner bufferptr = (u32 *)buffer;
1095fd501800SSascha Wildner /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
1096fd501800SSascha Wildner * so loop through the first 56 bytes (7*8),
1097fd501800SSascha Wildner * and then add in the last dword.
1098fd501800SSascha Wildner */
1099fd501800SSascha Wildner hash_address.word.low = 0;
1100fd501800SSascha Wildner hash_address.word.high = 0;
1101fd501800SSascha Wildner for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) {
1102fd501800SSascha Wildner hash_address.word.low += *bufferptr;
1103fd501800SSascha Wildner bufferptr++;
1104fd501800SSascha Wildner hash_address.word.high += *bufferptr;
1105fd501800SSascha Wildner bufferptr++;
1106fd501800SSascha Wildner }
1107fd501800SSascha Wildner /* Add the last dword */
1108fd501800SSascha Wildner hash_address.word.low += *bufferptr;
1109fd501800SSascha Wildner /* Make sure the hash doesn't start with 5, because it could clash
1110fd501800SSascha Wildner * with a SAS address. Change 5 to a D.
1111fd501800SSascha Wildner */
1112fd501800SSascha Wildner if ((hash_address.word.high & 0x000000F0) == (0x00000050))
1113fd501800SSascha Wildner hash_address.word.high |= 0x00000080;
1114fd501800SSascha Wildner *sas_address = (u64)hash_address.wwid[0] << 56 |
1115fd501800SSascha Wildner (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 |
1116fd501800SSascha Wildner (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
1117fd501800SSascha Wildner (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 |
1118fd501800SSascha Wildner (u64)hash_address.wwid[7];
1119fd501800SSascha Wildner if (ata_identify.rotational_speed == 1) {
1120fd501800SSascha Wildner *is_SATA_SSD = 1;
1121fd501800SSascha Wildner }
1122fd501800SSascha Wildner
1123fd501800SSascha Wildner return 0;
1124fd501800SSascha Wildner }
1125fd501800SSascha Wildner
1126fd501800SSascha Wildner static int
mprsas_get_sata_identify(struct mpr_softc * sc,u16 handle,Mpi2SataPassthroughReply_t * mpi_reply,char * id_buffer,int sz,u32 devinfo)1127fd501800SSascha Wildner mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
1128fd501800SSascha Wildner Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
1129fd501800SSascha Wildner {
1130fd501800SSascha Wildner Mpi2SataPassthroughRequest_t *mpi_request;
1131fd501800SSascha Wildner Mpi2SataPassthroughReply_t *reply = NULL; /* XXX swildner: warning fix */
1132fd501800SSascha Wildner struct mpr_command *cm;
1133fd501800SSascha Wildner char *buffer;
1134fd501800SSascha Wildner int error = 0;
1135fd501800SSascha Wildner
1136fd501800SSascha Wildner buffer = kmalloc( sz, M_MPR, M_NOWAIT | M_ZERO);
1137fd501800SSascha Wildner if (!buffer)
1138fd501800SSascha Wildner return ENOMEM;
1139fd501800SSascha Wildner
1140fd501800SSascha Wildner if ((cm = mpr_alloc_command(sc)) == NULL) {
1141fd501800SSascha Wildner kfree(buffer, M_MPR);
1142fd501800SSascha Wildner return (EBUSY);
1143fd501800SSascha Wildner }
1144fd501800SSascha Wildner mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req;
1145fd501800SSascha Wildner bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST));
1146fd501800SSascha Wildner mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH;
1147fd501800SSascha Wildner mpi_request->VF_ID = 0;
1148fd501800SSascha Wildner mpi_request->DevHandle = htole16(handle);
1149fd501800SSascha Wildner mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO |
1150fd501800SSascha Wildner MPI2_SATA_PT_REQ_PT_FLAGS_READ);
1151fd501800SSascha Wildner mpi_request->DataLength = htole32(sz);
1152fd501800SSascha Wildner mpi_request->CommandFIS[0] = 0x27;
1153fd501800SSascha Wildner mpi_request->CommandFIS[1] = 0x80;
1154fd501800SSascha Wildner mpi_request->CommandFIS[2] = (devinfo &
1155fd501800SSascha Wildner MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC;
1156fd501800SSascha Wildner cm->cm_sge = &mpi_request->SGL;
1157fd501800SSascha Wildner cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1158fd501800SSascha Wildner cm->cm_flags = MPR_CM_FLAGS_DATAIN;
1159fd501800SSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1160fd501800SSascha Wildner cm->cm_data = buffer;
1161fd501800SSascha Wildner cm->cm_length = htole32(sz);
1162fd501800SSascha Wildner
1163fd501800SSascha Wildner /*
1164fd501800SSascha Wildner * Start a timeout counter specifically for the SATA ID command. This
1165fd501800SSascha Wildner * is used to fix a problem where the FW does not send a reply sometimes
1166fd501800SSascha Wildner * when a bad disk is in the topology. So, this is used to timeout the
1167fd501800SSascha Wildner * command so that processing can continue normally.
1168fd501800SSascha Wildner */
1169fd501800SSascha Wildner mpr_dprint(sc, MPR_XINFO, "%s start timeout counter for SATA ID "
1170fd501800SSascha Wildner "command\n", __func__);
1171fd501800SSascha Wildner callout_reset(&cm->cm_callout, MPR_ATA_ID_TIMEOUT * hz,
1172fd501800SSascha Wildner mprsas_ata_id_timeout, cm);
1173fd501800SSascha Wildner error = mpr_wait_command(sc, &cm, 60, CAN_SLEEP);
1174fd501800SSascha Wildner mpr_dprint(sc, MPR_XINFO, "%s stop timeout counter for SATA ID "
1175fd501800SSascha Wildner "command\n", __func__);
1176fd501800SSascha Wildner /* XXX KDM need to fix the case where this command is destroyed */
1177fd501800SSascha Wildner callout_stop(&cm->cm_callout);
1178fd501800SSascha Wildner
1179fd501800SSascha Wildner if (cm != NULL)
1180fd501800SSascha Wildner reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
1181fd501800SSascha Wildner if (error || (reply == NULL)) {
1182fd501800SSascha Wildner /* FIXME */
1183fd501800SSascha Wildner /*
1184fd501800SSascha Wildner * If the request returns an error then we need to do a diag
1185fd501800SSascha Wildner * reset
1186fd501800SSascha Wildner */
1187fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO|MPR_FAULT|MPR_MAPPING,
1188fd501800SSascha Wildner "Request for SATA PASSTHROUGH page completed with error %d",
1189fd501800SSascha Wildner error);
1190fd501800SSascha Wildner error = ENXIO;
1191fd501800SSascha Wildner goto out;
1192fd501800SSascha Wildner }
1193fd501800SSascha Wildner bcopy(buffer, id_buffer, sz);
1194fd501800SSascha Wildner bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t));
1195fd501800SSascha Wildner if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
1196fd501800SSascha Wildner MPI2_IOCSTATUS_SUCCESS) {
1197fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO|MPR_MAPPING|MPR_FAULT,
1198fd501800SSascha Wildner "Error reading device %#x SATA PASSTHRU; iocstatus= 0x%x\n",
1199fd501800SSascha Wildner handle, reply->IOCStatus);
1200fd501800SSascha Wildner error = ENXIO;
1201fd501800SSascha Wildner goto out;
1202fd501800SSascha Wildner }
1203fd501800SSascha Wildner out:
1204fd501800SSascha Wildner /*
1205fd501800SSascha Wildner * If the SATA_ID_TIMEOUT flag has been set for this command, don't free
1206fd501800SSascha Wildner * it. The command will be freed after sending a target reset TM. If
1207fd501800SSascha Wildner * the command did timeout, use EWOULDBLOCK.
1208fd501800SSascha Wildner */
1209fd501800SSascha Wildner if ((cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) == 0)
1210fd501800SSascha Wildner mpr_free_command(sc, cm);
1211fd501800SSascha Wildner else if (error == 0)
1212fd501800SSascha Wildner error = EWOULDBLOCK;
1213fd501800SSascha Wildner cm->cm_data = NULL;
1214fd501800SSascha Wildner kfree(buffer, M_MPR);
1215fd501800SSascha Wildner return (error);
1216fd501800SSascha Wildner }
1217fd501800SSascha Wildner
1218fd501800SSascha Wildner static void
mprsas_ata_id_timeout(void * data)1219fd501800SSascha Wildner mprsas_ata_id_timeout(void *data)
1220fd501800SSascha Wildner {
1221fd501800SSascha Wildner struct mpr_softc *sc;
1222fd501800SSascha Wildner struct mpr_command *cm;
1223fd501800SSascha Wildner
1224fd501800SSascha Wildner cm = (struct mpr_command *)data;
1225fd501800SSascha Wildner sc = cm->cm_sc;
1226fd501800SSascha Wildner KKASSERT(lockowned(&sc->mpr_lock));
1227fd501800SSascha Wildner
1228fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "%s checking ATA ID command %p sc %p\n",
1229fd501800SSascha Wildner __func__, cm, sc);
1230fd501800SSascha Wildner if ((callout_pending(&cm->cm_callout)) ||
1231fd501800SSascha Wildner (!callout_active(&cm->cm_callout))) {
1232fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed out\n",
1233fd501800SSascha Wildner __func__);
1234fd501800SSascha Wildner return;
1235fd501800SSascha Wildner }
1236fd501800SSascha Wildner callout_deactivate(&cm->cm_callout);
1237fd501800SSascha Wildner
1238fd501800SSascha Wildner /*
1239fd501800SSascha Wildner * Run the interrupt handler to make sure it's not pending. This
1240fd501800SSascha Wildner * isn't perfect because the command could have already completed
1241fd501800SSascha Wildner * and been re-used, though this is unlikely.
1242fd501800SSascha Wildner */
1243fd501800SSascha Wildner mpr_intr_locked(sc);
1244fd501800SSascha Wildner if (cm->cm_state == MPR_CM_STATE_FREE) {
1245fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed out\n",
1246fd501800SSascha Wildner __func__);
1247fd501800SSascha Wildner return;
1248fd501800SSascha Wildner }
1249fd501800SSascha Wildner
1250fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "ATA ID command timeout cm %p\n", cm);
1251fd501800SSascha Wildner
1252fd501800SSascha Wildner /*
1253fd501800SSascha Wildner * Send wakeup() to the sleeping thread that issued this ATA ID command.
1254fd501800SSascha Wildner * wakeup() will cause msleep to return a 0 (not EWOULDBLOCK), and this
1255fd501800SSascha Wildner * will keep reinit() from being called. This way, an Abort Task TM can
1256fd501800SSascha Wildner * be issued so that the timed out command can be cleared. The Abort
1257fd501800SSascha Wildner * Task cannot be sent from here because the driver has not completed
1258fd501800SSascha Wildner * setting up targets. Instead, the command is flagged so that special
1259fd501800SSascha Wildner * handling will be used to send the abort.
1260fd501800SSascha Wildner */
1261fd501800SSascha Wildner cm->cm_flags |= MPR_CM_FLAGS_SATA_ID_TIMEOUT;
1262fd501800SSascha Wildner wakeup(cm);
1263fd501800SSascha Wildner }
1264fd501800SSascha Wildner
1265fd501800SSascha Wildner static int
mprsas_add_pcie_device(struct mpr_softc * sc,u16 handle,u8 linkrate)1266fd501800SSascha Wildner mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
1267fd501800SSascha Wildner {
1268fd501800SSascha Wildner char devstring[80];
1269fd501800SSascha Wildner struct mprsas_softc *sassc;
1270fd501800SSascha Wildner struct mprsas_target *targ;
1271fd501800SSascha Wildner Mpi2ConfigReply_t mpi_reply;
1272fd501800SSascha Wildner Mpi26PCIeDevicePage0_t config_page;
1273fd501800SSascha Wildner Mpi26PCIeDevicePage2_t config_page2;
1274fd501800SSascha Wildner uint64_t pcie_wwid, parent_wwid = 0;
1275fd501800SSascha Wildner u32 device_info, parent_devinfo = 0;
1276fd501800SSascha Wildner unsigned int id;
1277fd501800SSascha Wildner int error = 0;
1278fd501800SSascha Wildner struct mprsas_lun *lun;
1279fd501800SSascha Wildner
1280fd501800SSascha Wildner sassc = sc->sassc;
1281fd501800SSascha Wildner mprsas_startup_increment(sassc);
1282fd501800SSascha Wildner if ((mpr_config_get_pcie_device_pg0(sc, &mpi_reply, &config_page,
1283fd501800SSascha Wildner MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
1284fd501800SSascha Wildner kprintf("%s: error reading PCIe device page0\n", __func__);
1285fd501800SSascha Wildner error = ENXIO;
1286fd501800SSascha Wildner goto out;
1287fd501800SSascha Wildner }
1288fd501800SSascha Wildner
1289fd501800SSascha Wildner device_info = le32toh(config_page.DeviceInfo);
1290fd501800SSascha Wildner
1291fd501800SSascha Wildner if (((device_info & MPI26_PCIE_DEVINFO_PCI_SWITCH) == 0)
1292fd501800SSascha Wildner && (le16toh(config_page.ParentDevHandle) != 0)) {
1293fd501800SSascha Wildner Mpi2ConfigReply_t tmp_mpi_reply;
1294fd501800SSascha Wildner Mpi26PCIeDevicePage0_t parent_config_page;
1295fd501800SSascha Wildner
1296fd501800SSascha Wildner if ((mpr_config_get_pcie_device_pg0(sc, &tmp_mpi_reply,
1297fd501800SSascha Wildner &parent_config_page, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
1298fd501800SSascha Wildner le16toh(config_page.ParentDevHandle)))) {
1299fd501800SSascha Wildner kprintf("%s: error reading PCIe device %#x page0\n",
1300fd501800SSascha Wildner __func__, le16toh(config_page.ParentDevHandle));
1301fd501800SSascha Wildner } else {
1302fd501800SSascha Wildner parent_wwid = parent_config_page.WWID.High;
1303fd501800SSascha Wildner parent_wwid = (parent_wwid << 32) |
1304fd501800SSascha Wildner parent_config_page.WWID.Low;
1305fd501800SSascha Wildner parent_devinfo = le32toh(parent_config_page.DeviceInfo);
1306fd501800SSascha Wildner }
1307fd501800SSascha Wildner }
1308fd501800SSascha Wildner /* TODO Check proper endianness */
1309fd501800SSascha Wildner pcie_wwid = config_page.WWID.High;
1310fd501800SSascha Wildner pcie_wwid = (pcie_wwid << 32) | config_page.WWID.Low;
1311fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "PCIe WWID from PCIe device page0 = %jx\n",
1312fd501800SSascha Wildner pcie_wwid);
1313fd501800SSascha Wildner
1314fd501800SSascha Wildner if ((mpr_config_get_pcie_device_pg2(sc, &mpi_reply, &config_page2,
1315fd501800SSascha Wildner MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
1316fd501800SSascha Wildner kprintf("%s: error reading PCIe device page2\n", __func__);
1317fd501800SSascha Wildner error = ENXIO;
1318fd501800SSascha Wildner goto out;
1319fd501800SSascha Wildner }
1320fd501800SSascha Wildner
1321fd501800SSascha Wildner id = mpr_mapping_get_tid(sc, pcie_wwid, handle);
1322fd501800SSascha Wildner if (id == MPR_MAP_BAD_ID) {
1323fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR | MPR_INFO, "failure at %s:%d/%s()! "
1324fd501800SSascha Wildner "Could not get ID for device with handle 0x%04x\n",
1325fd501800SSascha Wildner __FILE__, __LINE__, __func__, handle);
1326fd501800SSascha Wildner error = ENXIO;
1327fd501800SSascha Wildner goto out;
1328fd501800SSascha Wildner }
1329fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "%s: Target ID for added device is %d.\n",
1330fd501800SSascha Wildner __func__, id);
1331fd501800SSascha Wildner
1332fd501800SSascha Wildner if (mprsas_check_id(sassc, id) != 0) {
1333fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING|MPR_INFO,
1334fd501800SSascha Wildner "Excluding target id %d\n", id);
1335fd501800SSascha Wildner error = ENXIO;
1336fd501800SSascha Wildner goto out;
1337fd501800SSascha Wildner }
1338fd501800SSascha Wildner
1339fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "WWID from PCIe device page0 = %jx\n",
1340fd501800SSascha Wildner pcie_wwid);
1341fd501800SSascha Wildner targ = &sassc->targets[id];
1342fd501800SSascha Wildner targ->devinfo = device_info;
1343fd501800SSascha Wildner targ->encl_handle = le16toh(config_page.EnclosureHandle);
1344fd501800SSascha Wildner targ->encl_slot = le16toh(config_page.Slot);
1345fd501800SSascha Wildner targ->encl_level = config_page.EnclosureLevel;
1346fd501800SSascha Wildner targ->connector_name[0] = ((char *)&config_page.ConnectorName)[0];
1347fd501800SSascha Wildner targ->connector_name[1] = ((char *)&config_page.ConnectorName)[1];
1348fd501800SSascha Wildner targ->connector_name[2] = ((char *)&config_page.ConnectorName)[2];
1349fd501800SSascha Wildner targ->connector_name[3] = ((char *)&config_page.ConnectorName)[3];
1350fd501800SSascha Wildner targ->is_nvme = device_info & MPI26_PCIE_DEVINFO_NVME;
1351fd501800SSascha Wildner targ->MDTS = config_page2.MaximumDataTransferSize;
1352fd501800SSascha Wildner /*
1353fd501800SSascha Wildner * Assume always TRUE for encl_level_valid because there is no valid
1354fd501800SSascha Wildner * flag for PCIe.
1355fd501800SSascha Wildner */
1356fd501800SSascha Wildner targ->encl_level_valid = TRUE;
1357fd501800SSascha Wildner targ->handle = handle;
1358fd501800SSascha Wildner targ->parent_handle = le16toh(config_page.ParentDevHandle);
1359fd501800SSascha Wildner targ->sasaddr = mpr_to_u64(&config_page.WWID);
1360fd501800SSascha Wildner targ->parent_sasaddr = le64toh(parent_wwid);
1361fd501800SSascha Wildner targ->parent_devinfo = parent_devinfo;
1362fd501800SSascha Wildner targ->tid = id;
1363fd501800SSascha Wildner targ->linkrate = linkrate;
1364fd501800SSascha Wildner targ->flags = 0;
1365fd501800SSascha Wildner if ((le16toh(config_page.Flags) &
1366fd501800SSascha Wildner MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH) &&
1367fd501800SSascha Wildner (le16toh(config_page.Flags) &
1368fd501800SSascha Wildner MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE)) {
1369fd501800SSascha Wildner targ->scsi_req_desc_type =
1370fd501800SSascha Wildner MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
1371fd501800SSascha Wildner }
1372fd501800SSascha Wildner TAILQ_INIT(&targ->commands);
1373fd501800SSascha Wildner TAILQ_INIT(&targ->timedout_commands);
1374fd501800SSascha Wildner while (!SLIST_EMPTY(&targ->luns)) {
1375fd501800SSascha Wildner lun = SLIST_FIRST(&targ->luns);
1376fd501800SSascha Wildner SLIST_REMOVE_HEAD(&targ->luns, lun_link);
1377fd501800SSascha Wildner kfree(lun, M_MPR);
1378fd501800SSascha Wildner }
1379fd501800SSascha Wildner SLIST_INIT(&targ->luns);
1380fd501800SSascha Wildner
1381fd501800SSascha Wildner mpr_describe_devinfo(targ->devinfo, devstring, 80);
1382fd501800SSascha Wildner mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "Found PCIe device <%s> <%s> "
1383fd501800SSascha Wildner "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
1384fd501800SSascha Wildner mpr_describe_table(mpr_pcie_linkrate_names, targ->linkrate),
1385fd501800SSascha Wildner targ->handle, targ->encl_handle, targ->encl_slot);
1386fd501800SSascha Wildner if (targ->encl_level_valid) {
1387fd501800SSascha Wildner mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d "
1388fd501800SSascha Wildner "and connector name (%4s)\n", targ->encl_level,
1389fd501800SSascha Wildner targ->connector_name);
1390fd501800SSascha Wildner }
1391b9788dabSSascha Wildner #if 1 /* ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
1392b9788dabSSascha Wildner (__FreeBSD_version < 902502) */
1393fd501800SSascha Wildner if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
1394fd501800SSascha Wildner #endif
1395fd501800SSascha Wildner mprsas_rescan_target(sc, targ);
1396fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid);
1397fd501800SSascha Wildner
1398fd501800SSascha Wildner out:
1399fd501800SSascha Wildner mprsas_startup_decrement(sassc);
1400fd501800SSascha Wildner return (error);
1401fd501800SSascha Wildner }
1402fd501800SSascha Wildner
1403fd501800SSascha Wildner static int
mprsas_volume_add(struct mpr_softc * sc,u16 handle)1404fd501800SSascha Wildner mprsas_volume_add(struct mpr_softc *sc, u16 handle)
1405fd501800SSascha Wildner {
1406fd501800SSascha Wildner struct mprsas_softc *sassc;
1407fd501800SSascha Wildner struct mprsas_target *targ;
1408fd501800SSascha Wildner u64 wwid;
1409fd501800SSascha Wildner unsigned int id;
1410fd501800SSascha Wildner int error = 0;
1411fd501800SSascha Wildner struct mprsas_lun *lun;
1412fd501800SSascha Wildner
1413fd501800SSascha Wildner sassc = sc->sassc;
1414fd501800SSascha Wildner mprsas_startup_increment(sassc);
1415fd501800SSascha Wildner /* wwid is endian safe */
1416fd501800SSascha Wildner mpr_config_get_volume_wwid(sc, handle, &wwid);
1417fd501800SSascha Wildner if (!wwid) {
1418fd501800SSascha Wildner kprintf("%s: invalid WWID; cannot add volume to mapping table\n",
1419fd501800SSascha Wildner __func__);
1420fd501800SSascha Wildner error = ENXIO;
1421fd501800SSascha Wildner goto out;
1422fd501800SSascha Wildner }
1423fd501800SSascha Wildner
1424fd501800SSascha Wildner id = mpr_mapping_get_raid_tid(sc, wwid, handle);
1425fd501800SSascha Wildner if (id == MPR_MAP_BAD_ID) {
1426fd501800SSascha Wildner kprintf("%s: could not get ID for volume with handle 0x%04x and "
1427fd501800SSascha Wildner "WWID 0x%016llx\n", __func__, handle,
1428fd501800SSascha Wildner (unsigned long long)wwid);
1429fd501800SSascha Wildner error = ENXIO;
1430fd501800SSascha Wildner goto out;
1431fd501800SSascha Wildner }
1432fd501800SSascha Wildner
1433fd501800SSascha Wildner targ = &sassc->targets[id];
1434fd501800SSascha Wildner targ->tid = id;
1435fd501800SSascha Wildner targ->handle = handle;
1436fd501800SSascha Wildner targ->devname = wwid;
1437fd501800SSascha Wildner TAILQ_INIT(&targ->commands);
1438fd501800SSascha Wildner TAILQ_INIT(&targ->timedout_commands);
1439fd501800SSascha Wildner while (!SLIST_EMPTY(&targ->luns)) {
1440fd501800SSascha Wildner lun = SLIST_FIRST(&targ->luns);
1441fd501800SSascha Wildner SLIST_REMOVE_HEAD(&targ->luns, lun_link);
1442fd501800SSascha Wildner kfree(lun, M_MPR);
1443fd501800SSascha Wildner }
1444fd501800SSascha Wildner SLIST_INIT(&targ->luns);
1445b9788dabSSascha Wildner #if 1 /* ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
1446b9788dabSSascha Wildner (__FreeBSD_version < 902502) */
1447fd501800SSascha Wildner if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
1448fd501800SSascha Wildner #endif
1449fd501800SSascha Wildner mprsas_rescan_target(sc, targ);
1450fd501800SSascha Wildner mpr_dprint(sc, MPR_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n",
1451fd501800SSascha Wildner targ->tid, wwid);
1452fd501800SSascha Wildner out:
1453fd501800SSascha Wildner mprsas_startup_decrement(sassc);
1454fd501800SSascha Wildner return (error);
1455fd501800SSascha Wildner }
1456fd501800SSascha Wildner
1457fd501800SSascha Wildner /**
1458fd501800SSascha Wildner * mprsas_SSU_to_SATA_devices
1459fd501800SSascha Wildner * @sc: per adapter object
1460fd501800SSascha Wildner *
1461fd501800SSascha Wildner * Looks through the target list and issues a StartStopUnit SCSI command to each
1462fd501800SSascha Wildner * SATA direct-access device. This helps to ensure that data corruption is
1463fd501800SSascha Wildner * avoided when the system is being shut down. This must be called after the IR
1464fd501800SSascha Wildner * System Shutdown RAID Action is sent if in IR mode.
1465fd501800SSascha Wildner *
1466fd501800SSascha Wildner * Return nothing.
1467fd501800SSascha Wildner */
1468fd501800SSascha Wildner static void
mprsas_SSU_to_SATA_devices(struct mpr_softc * sc)1469fd501800SSascha Wildner mprsas_SSU_to_SATA_devices(struct mpr_softc *sc)
1470fd501800SSascha Wildner {
1471fd501800SSascha Wildner struct mprsas_softc *sassc = sc->sassc;
1472fd501800SSascha Wildner union ccb *ccb;
1473fd501800SSascha Wildner path_id_t pathid = cam_sim_path(sassc->sim);
1474fd501800SSascha Wildner target_id_t targetid;
1475fd501800SSascha Wildner struct mprsas_target *target;
1476fd501800SSascha Wildner char path_str[64];
1477fd501800SSascha Wildner struct timeval cur_time, start_time;
1478fd501800SSascha Wildner
1479fd501800SSascha Wildner mpr_lock(sc);
1480fd501800SSascha Wildner
1481fd501800SSascha Wildner /*
1482fd501800SSascha Wildner * For each target, issue a StartStopUnit command to stop the device.
1483fd501800SSascha Wildner */
1484fd501800SSascha Wildner sc->SSU_started = TRUE;
1485fd501800SSascha Wildner sc->SSU_refcount = 0;
1486fd501800SSascha Wildner for (targetid = 0; targetid < sc->max_devices; targetid++) {
1487fd501800SSascha Wildner target = &sassc->targets[targetid];
1488fd501800SSascha Wildner if (target->handle == 0x0) {
1489fd501800SSascha Wildner continue;
1490fd501800SSascha Wildner }
1491fd501800SSascha Wildner
1492fd501800SSascha Wildner /*
1493fd501800SSascha Wildner * The stop_at_shutdown flag will be set if this device is
1494fd501800SSascha Wildner * a SATA direct-access end device.
1495fd501800SSascha Wildner */
1496fd501800SSascha Wildner if (target->stop_at_shutdown) {
1497fd501800SSascha Wildner ccb = xpt_alloc_ccb();
1498fd501800SSascha Wildner if (ccb == NULL) {
1499fd501800SSascha Wildner mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB "
1500fd501800SSascha Wildner "to stop unit.\n");
1501fd501800SSascha Wildner return;
1502fd501800SSascha Wildner }
1503fd501800SSascha Wildner
1504fd501800SSascha Wildner if (xpt_create_path(&ccb->ccb_h.path, xpt_periph,
1505fd501800SSascha Wildner pathid, targetid, CAM_LUN_WILDCARD) !=
1506fd501800SSascha Wildner CAM_REQ_CMP) {
1507fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "Unable to create "
1508fd501800SSascha Wildner "path to stop unit.\n");
1509*cec957e9SMatthew Dillon xpt_free_ccb(&ccb->ccb_h);
1510fd501800SSascha Wildner return;
1511fd501800SSascha Wildner }
1512fd501800SSascha Wildner xpt_path_string(ccb->ccb_h.path, path_str,
1513fd501800SSascha Wildner sizeof(path_str));
1514fd501800SSascha Wildner
1515fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "Sending StopUnit: path %s "
1516fd501800SSascha Wildner "handle %d\n", path_str, target->handle);
1517fd501800SSascha Wildner
1518fd501800SSascha Wildner /*
1519fd501800SSascha Wildner * Issue a START STOP UNIT command for the target.
1520fd501800SSascha Wildner * Increment the SSU counter to be used to count the
1521fd501800SSascha Wildner * number of required replies.
1522fd501800SSascha Wildner */
1523fd501800SSascha Wildner mpr_dprint(sc, MPR_INFO, "Incrementing SSU count\n");
1524fd501800SSascha Wildner sc->SSU_refcount++;
1525fd501800SSascha Wildner ccb->ccb_h.target_id =
1526fd501800SSascha Wildner xpt_path_target_id(ccb->ccb_h.path);
1527fd501800SSascha Wildner ccb->ccb_h.ppriv_ptr1 = sassc;
1528fd501800SSascha Wildner scsi_start_stop(&ccb->csio,
1529fd501800SSascha Wildner /*retries*/0,
1530fd501800SSascha Wildner mprsas_stop_unit_done,
1531fd501800SSascha Wildner MSG_SIMPLE_Q_TAG,
1532fd501800SSascha Wildner /*start*/FALSE,
1533fd501800SSascha Wildner /*load/eject*/0,
1534fd501800SSascha Wildner /*immediate*/FALSE,
1535fd501800SSascha Wildner MPR_SENSE_LEN,
1536fd501800SSascha Wildner /*timeout*/10000);
1537fd501800SSascha Wildner xpt_action(ccb);
1538fd501800SSascha Wildner }
1539fd501800SSascha Wildner }
1540fd501800SSascha Wildner
1541fd501800SSascha Wildner mpr_unlock(sc);
1542fd501800SSascha Wildner
1543fd501800SSascha Wildner /*
1544fd501800SSascha Wildner * Wait until all of the SSU commands have completed or time has
1545fd501800SSascha Wildner * expired (60 seconds). Pause for 100ms each time through. If any
1546fd501800SSascha Wildner * command times out, the target will be reset in the SCSI command
1547fd501800SSascha Wildner * timeout routine.
1548fd501800SSascha Wildner */
1549fd501800SSascha Wildner getmicrotime(&start_time);
1550fd501800SSascha Wildner while (sc->SSU_refcount) {
1551fd501800SSascha Wildner tsleep(mprsas_SSU_to_SATA_devices, 0, "mprwait", hz/10);
1552fd501800SSascha Wildner
1553fd501800SSascha Wildner getmicrotime(&cur_time);
1554fd501800SSascha Wildner if ((cur_time.tv_sec - start_time.tv_sec) > 60) {
1555fd501800SSascha Wildner mpr_dprint(sc, MPR_ERROR, "Time has expired waiting "
1556fd501800SSascha Wildner "for SSU commands to complete.\n");
1557fd501800SSascha Wildner break;
1558fd501800SSascha Wildner }
1559fd501800SSascha Wildner }
1560fd501800SSascha Wildner }
1561fd501800SSascha Wildner
1562fd501800SSascha Wildner static void
mprsas_stop_unit_done(struct cam_periph * periph,union ccb * done_ccb)1563fd501800SSascha Wildner mprsas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb)
1564fd501800SSascha Wildner {
1565fd501800SSascha Wildner struct mprsas_softc *sassc;
1566fd501800SSascha Wildner char path_str[64];
1567fd501800SSascha Wildner
1568fd501800SSascha Wildner if (done_ccb == NULL)
1569fd501800SSascha Wildner return;
1570fd501800SSascha Wildner
1571fd501800SSascha Wildner sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1;
1572fd501800SSascha Wildner
1573fd501800SSascha Wildner xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str));
1574fd501800SSascha Wildner mpr_dprint(sassc->sc, MPR_INFO, "Completing stop unit for %s\n",
1575fd501800SSascha Wildner path_str);
1576fd501800SSascha Wildner
1577fd501800SSascha Wildner /*
1578fd501800SSascha Wildner * Nothing more to do except free the CCB and path. If the command
1579fd501800SSascha Wildner * timed out, an abort reset, then target reset will be issued during
1580fd501800SSascha Wildner * the SCSI Command process.
1581fd501800SSascha Wildner */
1582fd501800SSascha Wildner xpt_free_path(done_ccb->ccb_h.path);
1583*cec957e9SMatthew Dillon xpt_free_ccb(&done_ccb->ccb_h);
1584fd501800SSascha Wildner }
1585fd501800SSascha Wildner
1586fd501800SSascha Wildner /**
1587fd501800SSascha Wildner * mprsas_ir_shutdown - IR shutdown notification
1588fd501800SSascha Wildner * @sc: per adapter object
1589fd501800SSascha Wildner *
1590fd501800SSascha Wildner * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
1591fd501800SSascha Wildner * the host system is shutting down.
1592fd501800SSascha Wildner *
1593fd501800SSascha Wildner * Return nothing.
1594fd501800SSascha Wildner */
1595fd501800SSascha Wildner void
mprsas_ir_shutdown(struct mpr_softc * sc)1596fd501800SSascha Wildner mprsas_ir_shutdown(struct mpr_softc *sc)
1597fd501800SSascha Wildner {
1598fd501800SSascha Wildner u16 volume_mapping_flags;
1599fd501800SSascha Wildner u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1600fd501800SSascha Wildner struct dev_mapping_table *mt_entry;
1601fd501800SSascha Wildner u32 start_idx, end_idx;
1602fd501800SSascha Wildner unsigned int id, found_volume = 0;
1603fd501800SSascha Wildner struct mpr_command *cm;
1604fd501800SSascha Wildner Mpi2RaidActionRequest_t *action;
1605fd501800SSascha Wildner target_id_t targetid;
1606fd501800SSascha Wildner struct mprsas_target *target;
1607fd501800SSascha Wildner
1608fd501800SSascha Wildner mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
1609fd501800SSascha Wildner
1610fd501800SSascha Wildner /* is IR firmware build loaded? */
1611fd501800SSascha Wildner if (!sc->ir_firmware)
1612fd501800SSascha Wildner goto out;
1613fd501800SSascha Wildner
1614fd501800SSascha Wildner /* are there any volumes? Look at IR target IDs. */
1615fd501800SSascha Wildner // TODO-later, this should be looked up in the RAID config structure
1616fd501800SSascha Wildner // when it is implemented.
1617fd501800SSascha Wildner volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
1618fd501800SSascha Wildner MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
1619fd501800SSascha Wildner if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
1620fd501800SSascha Wildner start_idx = 0;
1621fd501800SSascha Wildner if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
1622fd501800SSascha Wildner start_idx = 1;
1623fd501800SSascha Wildner } else
1624fd501800SSascha Wildner start_idx = sc->max_devices - sc->max_volumes;
1625fd501800SSascha Wildner end_idx = start_idx + sc->max_volumes - 1;
1626fd501800SSascha Wildner
1627fd501800SSascha Wildner for (id = start_idx; id < end_idx; id++) {
1628fd501800SSascha Wildner mt_entry = &sc->mapping_table[id];
1629fd501800SSascha Wildner if ((mt_entry->physical_id != 0) &&
1630fd501800SSascha Wildner (mt_entry->missing_count == 0)) {
1631fd501800SSascha Wildner found_volume = 1;
1632fd501800SSascha Wildner break;
1633fd501800SSascha Wildner }
1634fd501800SSascha Wildner }
1635fd501800SSascha Wildner
1636fd501800SSascha Wildner if (!found_volume)
1637fd501800SSascha Wildner goto out;
1638fd501800SSascha Wildner
1639fd501800SSascha Wildner if ((cm = mpr_alloc_command(sc)) == NULL) {
1640fd501800SSascha Wildner kprintf("%s: command alloc failed\n", __func__);
1641fd501800SSascha Wildner goto out;
1642fd501800SSascha Wildner }
1643fd501800SSascha Wildner
1644fd501800SSascha Wildner action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
1645fd501800SSascha Wildner action->Function = MPI2_FUNCTION_RAID_ACTION;
1646fd501800SSascha Wildner action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
1647fd501800SSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1648fd501800SSascha Wildner mpr_lock(sc);
1649fd501800SSascha Wildner mpr_wait_command(sc, &cm, 5, CAN_SLEEP);
1650fd501800SSascha Wildner mpr_unlock(sc);
1651fd501800SSascha Wildner
1652fd501800SSascha Wildner /*
1653fd501800SSascha Wildner * Don't check for reply, just leave.
1654fd501800SSascha Wildner */
1655fd501800SSascha Wildner if (cm)
1656fd501800SSascha Wildner mpr_free_command(sc, cm);
1657fd501800SSascha Wildner
1658fd501800SSascha Wildner out:
1659fd501800SSascha Wildner /*
1660fd501800SSascha Wildner * All of the targets must have the correct value set for
1661fd501800SSascha Wildner * 'stop_at_shutdown' for the current 'enable_ssu' sysctl variable.
1662fd501800SSascha Wildner *
1663fd501800SSascha Wildner * The possible values for the 'enable_ssu' variable are:
1664fd501800SSascha Wildner * 0: disable to SSD and HDD
1665fd501800SSascha Wildner * 1: disable only to HDD (default)
1666fd501800SSascha Wildner * 2: disable only to SSD
1667fd501800SSascha Wildner * 3: enable to SSD and HDD
1668fd501800SSascha Wildner * anything else will default to 1.
1669fd501800SSascha Wildner */
1670fd501800SSascha Wildner for (targetid = 0; targetid < sc->max_devices; targetid++) {
1671fd501800SSascha Wildner target = &sc->sassc->targets[targetid];
1672fd501800SSascha Wildner if (target->handle == 0x0) {
1673fd501800SSascha Wildner continue;
1674fd501800SSascha Wildner }
1675fd501800SSascha Wildner
1676fd501800SSascha Wildner if (target->supports_SSU) {
1677fd501800SSascha Wildner switch (sc->enable_ssu) {
1678fd501800SSascha Wildner case MPR_SSU_DISABLE_SSD_DISABLE_HDD:
1679fd501800SSascha Wildner target->stop_at_shutdown = FALSE;
1680fd501800SSascha Wildner break;
1681fd501800SSascha Wildner case MPR_SSU_DISABLE_SSD_ENABLE_HDD:
1682fd501800SSascha Wildner target->stop_at_shutdown = TRUE;
1683fd501800SSascha Wildner if (target->flags & MPR_TARGET_IS_SATA_SSD) {
1684fd501800SSascha Wildner target->stop_at_shutdown = FALSE;
1685fd501800SSascha Wildner }
1686fd501800SSascha Wildner break;
1687fd501800SSascha Wildner case MPR_SSU_ENABLE_SSD_ENABLE_HDD:
1688fd501800SSascha Wildner target->stop_at_shutdown = TRUE;
1689fd501800SSascha Wildner break;
1690fd501800SSascha Wildner case MPR_SSU_ENABLE_SSD_DISABLE_HDD:
1691fd501800SSascha Wildner default:
1692fd501800SSascha Wildner target->stop_at_shutdown = TRUE;
1693fd501800SSascha Wildner if ((target->flags &
1694fd501800SSascha Wildner MPR_TARGET_IS_SATA_SSD) == 0) {
1695fd501800SSascha Wildner target->stop_at_shutdown = FALSE;
1696fd501800SSascha Wildner }
1697fd501800SSascha Wildner break;
1698fd501800SSascha Wildner }
1699fd501800SSascha Wildner }
1700fd501800SSascha Wildner }
1701fd501800SSascha Wildner mprsas_SSU_to_SATA_devices(sc);
1702fd501800SSascha Wildner }
1703