1c12c399aSSascha Wildner /*- 2c12c399aSSascha Wildner * Copyright (c) 2011 LSI Corp. 3c12c399aSSascha Wildner * All rights reserved. 4c12c399aSSascha Wildner * 5c12c399aSSascha Wildner * Redistribution and use in source and binary forms, with or without 6c12c399aSSascha Wildner * modification, are permitted provided that the following conditions 7c12c399aSSascha Wildner * are met: 8c12c399aSSascha Wildner * 1. Redistributions of source code must retain the above copyright 9c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer. 10c12c399aSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 11c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer in the 12c12c399aSSascha Wildner * documentation and/or other materials provided with the distribution. 13c12c399aSSascha Wildner * 14c12c399aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c12c399aSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c12c399aSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c12c399aSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c12c399aSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c12c399aSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c12c399aSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c12c399aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c12c399aSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c12c399aSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c12c399aSSascha Wildner * SUCH DAMAGE. 25c12c399aSSascha Wildner * 26c12c399aSSascha Wildner * LSI MPT-Fusion Host Adapter FreeBSD 27c12c399aSSascha Wildner * 28c12c399aSSascha Wildner * $FreeBSD: src/sys/dev/mps/mps_sas_lsi.c,v 1.1 2012/01/26 18:17:21 ken Exp $ 29c12c399aSSascha Wildner */ 30c12c399aSSascha Wildner 31c12c399aSSascha Wildner /* Communications core for LSI MPT2 */ 32c12c399aSSascha Wildner 33c12c399aSSascha Wildner /* TODO Move headers to mpsvar */ 34c12c399aSSascha Wildner #include <sys/types.h> 35c12c399aSSascha Wildner #include <sys/param.h> 36c12c399aSSascha Wildner #include <sys/systm.h> 37c12c399aSSascha Wildner #include <sys/kernel.h> 38c12c399aSSascha Wildner #include <sys/module.h> 39c12c399aSSascha Wildner #include <sys/bus.h> 40c12c399aSSascha Wildner #include <sys/conf.h> 41c12c399aSSascha Wildner #include <sys/eventhandler.h> 42c12c399aSSascha Wildner #include <sys/bio.h> 43c12c399aSSascha Wildner #include <sys/malloc.h> 44c12c399aSSascha Wildner #include <sys/uio.h> 45c12c399aSSascha Wildner #include <sys/sysctl.h> 46c12c399aSSascha Wildner #include <sys/endian.h> 47c12c399aSSascha Wildner #include <sys/queue.h> 48c12c399aSSascha Wildner #include <sys/kthread.h> 49c12c399aSSascha Wildner #include <sys/taskqueue.h> 50c12c399aSSascha Wildner #include <sys/sbuf.h> 51c12c399aSSascha Wildner 52c12c399aSSascha Wildner #include <sys/rman.h> 53c12c399aSSascha Wildner 54c12c399aSSascha Wildner #include <machine/stdarg.h> 55c12c399aSSascha Wildner 56c12c399aSSascha Wildner #include <bus/cam/cam.h> 57c12c399aSSascha Wildner #include <bus/cam/cam_ccb.h> 58c12c399aSSascha Wildner #include <bus/cam/cam_debug.h> 59c12c399aSSascha Wildner #include <bus/cam/cam_sim.h> 60c12c399aSSascha Wildner #include <bus/cam/cam_xpt_sim.h> 61c12c399aSSascha Wildner #include <bus/cam/cam_xpt_periph.h> 62c12c399aSSascha Wildner #include <bus/cam/cam_periph.h> 63c12c399aSSascha Wildner #include <bus/cam/scsi/scsi_all.h> 64c12c399aSSascha Wildner #include <bus/cam/scsi/scsi_message.h> 65c12c399aSSascha Wildner 66c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_type.h> 67c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2.h> 68c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_ioc.h> 69c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_sas.h> 70c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_cnfg.h> 71c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_init.h> 72c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_raid.h> 73c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_tool.h> 74c12c399aSSascha Wildner #include <dev/raid/mps/mps_ioctl.h> 75c12c399aSSascha Wildner #include <dev/raid/mps/mpsvar.h> 76c12c399aSSascha Wildner #include <dev/raid/mps/mps_table.h> 77c12c399aSSascha Wildner #include <dev/raid/mps/mps_sas.h> 78c12c399aSSascha Wildner 79c12c399aSSascha Wildner /* For Hashed SAS Address creation for SATA Drives */ 80c12c399aSSascha Wildner #define MPT2SAS_SN_LEN 20 81c12c399aSSascha Wildner #define MPT2SAS_MN_LEN 40 82c12c399aSSascha Wildner 83c12c399aSSascha Wildner struct mps_fw_event_work { 84c12c399aSSascha Wildner u16 event; 85c12c399aSSascha Wildner void *event_data; 86c12c399aSSascha Wildner TAILQ_ENTRY(mps_fw_event_work) ev_link; 87c12c399aSSascha Wildner }; 88c12c399aSSascha Wildner 89c12c399aSSascha Wildner union _sata_sas_address { 90c12c399aSSascha Wildner u8 wwid[8]; 91c12c399aSSascha Wildner struct { 92c12c399aSSascha Wildner u32 high; 93c12c399aSSascha Wildner u32 low; 94c12c399aSSascha Wildner } word; 95c12c399aSSascha Wildner }; 96c12c399aSSascha Wildner 97c12c399aSSascha Wildner /* 98c12c399aSSascha Wildner * define the IDENTIFY DEVICE structure 99c12c399aSSascha Wildner */ 100c12c399aSSascha Wildner struct _ata_identify_device_data { 101c12c399aSSascha Wildner u16 reserved1[10]; /* 0-9 */ 102c12c399aSSascha Wildner u16 serial_number[10]; /* 10-19 */ 103c12c399aSSascha Wildner u16 reserved2[7]; /* 20-26 */ 104c12c399aSSascha Wildner u16 model_number[20]; /* 27-46*/ 105c12c399aSSascha Wildner u16 reserved3[209]; /* 47-255*/ 106c12c399aSSascha Wildner }; 107c12c399aSSascha Wildner 108c12c399aSSascha Wildner static void mpssas_fw_work(struct mps_softc *sc, 109c12c399aSSascha Wildner struct mps_fw_event_work *fw_event); 110c12c399aSSascha Wildner static void mpssas_fw_event_free(struct mps_softc *, 111c12c399aSSascha Wildner struct mps_fw_event_work *); 112c12c399aSSascha Wildner static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate); 113c12c399aSSascha Wildner static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, 114c12c399aSSascha Wildner Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, 115c12c399aSSascha Wildner u32 devinfo); 116c12c399aSSascha Wildner int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc, 117c12c399aSSascha Wildner u64 *sas_address, u16 handle, u32 device_info); 118c12c399aSSascha Wildner static int mpssas_volume_add(struct mps_softc *sc, 119c12c399aSSascha Wildner Mpi2EventIrConfigElement_t *element); 120c12c399aSSascha Wildner 121c12c399aSSascha Wildner void 122c12c399aSSascha Wildner mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, 123c12c399aSSascha Wildner MPI2_EVENT_NOTIFICATION_REPLY *event) 124c12c399aSSascha Wildner { 125c12c399aSSascha Wildner struct mps_fw_event_work *fw_event; 126c12c399aSSascha Wildner u16 sz; 127c12c399aSSascha Wildner 128c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 129c12c399aSSascha Wildner mps_print_evt_sas(sc, event); 130c12c399aSSascha Wildner mpssas_record_event(sc, event); 131c12c399aSSascha Wildner 132c12c399aSSascha Wildner fw_event = kmalloc(sizeof(struct mps_fw_event_work), M_MPT2, 133c12c399aSSascha Wildner M_ZERO|M_NOWAIT); 134c12c399aSSascha Wildner if (!fw_event) { 135c12c399aSSascha Wildner kprintf("%s: allocate failed for fw_event\n", __func__); 136c12c399aSSascha Wildner return; 137c12c399aSSascha Wildner } 138c12c399aSSascha Wildner sz = le16toh(event->EventDataLength) * 4; 139c12c399aSSascha Wildner fw_event->event_data = kmalloc(sz, M_MPT2, M_ZERO|M_NOWAIT); 140c12c399aSSascha Wildner if (!fw_event->event_data) { 141c12c399aSSascha Wildner kprintf("%s: allocate failed for event_data\n", __func__); 142c12c399aSSascha Wildner kfree(fw_event, M_MPT2); 143c12c399aSSascha Wildner return; 144c12c399aSSascha Wildner } 145c12c399aSSascha Wildner 146c12c399aSSascha Wildner bcopy(event->EventData, fw_event->event_data, sz); 147c12c399aSSascha Wildner fw_event->event = event->Event; 148c12c399aSSascha Wildner if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || 149c12c399aSSascha Wildner event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE || 150c12c399aSSascha Wildner event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && 151c12c399aSSascha Wildner sc->track_mapping_events) 152c12c399aSSascha Wildner sc->pending_map_events++; 153c12c399aSSascha Wildner 154c12c399aSSascha Wildner /* 155c12c399aSSascha Wildner * When wait_for_port_enable flag is set, make sure that all the events 156c12c399aSSascha Wildner * are processed. Increment the startup_refcount and decrement it after 157c12c399aSSascha Wildner * events are processed. 158c12c399aSSascha Wildner */ 159c12c399aSSascha Wildner if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || 160c12c399aSSascha Wildner event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && 161c12c399aSSascha Wildner sc->wait_for_port_enable) 162c12c399aSSascha Wildner mpssas_startup_increment(sc->sassc); 163c12c399aSSascha Wildner 164c12c399aSSascha Wildner TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link); 165c12c399aSSascha Wildner taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task); 166c12c399aSSascha Wildner 167c12c399aSSascha Wildner } 168c12c399aSSascha Wildner 169c12c399aSSascha Wildner static void 170c12c399aSSascha Wildner mpssas_fw_event_free(struct mps_softc *sc, struct mps_fw_event_work *fw_event) 171c12c399aSSascha Wildner { 172c12c399aSSascha Wildner 173c12c399aSSascha Wildner kfree(fw_event->event_data, M_MPT2); 174c12c399aSSascha Wildner kfree(fw_event, M_MPT2); 175c12c399aSSascha Wildner } 176c12c399aSSascha Wildner 177c12c399aSSascha Wildner /** 178c12c399aSSascha Wildner * _mps_fw_work - delayed task for processing firmware events 179c12c399aSSascha Wildner * @sc: per adapter object 180c12c399aSSascha Wildner * @fw_event: The fw_event_work object 181c12c399aSSascha Wildner * Context: user. 182c12c399aSSascha Wildner * 183c12c399aSSascha Wildner * Return nothing. 184c12c399aSSascha Wildner */ 185c12c399aSSascha Wildner static void 186c12c399aSSascha Wildner mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event) 187c12c399aSSascha Wildner { 188c12c399aSSascha Wildner struct mpssas_softc *sassc; 189c12c399aSSascha Wildner sassc = sc->sassc; 190c12c399aSSascha Wildner 191c12c399aSSascha Wildner switch (fw_event->event) { 192c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 193c12c399aSSascha Wildner { 194c12c399aSSascha Wildner MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; 195c12c399aSSascha Wildner MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; 196c12c399aSSascha Wildner int i; 197c12c399aSSascha Wildner 198c12c399aSSascha Wildner data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) 199c12c399aSSascha Wildner fw_event->event_data; 200c12c399aSSascha Wildner 201c12c399aSSascha Wildner mps_mapping_topology_change_event(sc, fw_event->event_data); 202c12c399aSSascha Wildner 203c12c399aSSascha Wildner for (i = 0; i < data->NumEntries; i++) { 204c12c399aSSascha Wildner phy = &data->PHY[i]; 205c12c399aSSascha Wildner switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { 206c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: 207c12c399aSSascha Wildner if (mpssas_add_device(sc, 208c12c399aSSascha Wildner phy->AttachedDevHandle, phy->LinkRate)){ 209c12c399aSSascha Wildner kprintf("%s: failed to add device with " 210c12c399aSSascha Wildner "handle 0x%x\n", __func__, 211c12c399aSSascha Wildner phy->AttachedDevHandle); 212c12c399aSSascha Wildner mpssas_prepare_remove(sassc, phy-> 213c12c399aSSascha Wildner AttachedDevHandle); 214c12c399aSSascha Wildner } 215c12c399aSSascha Wildner break; 216c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: 217c12c399aSSascha Wildner mpssas_prepare_remove(sassc, phy-> 218c12c399aSSascha Wildner AttachedDevHandle); 219c12c399aSSascha Wildner break; 220c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: 221c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: 222c12c399aSSascha Wildner case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: 223c12c399aSSascha Wildner default: 224c12c399aSSascha Wildner break; 225c12c399aSSascha Wildner } 226c12c399aSSascha Wildner } 227c12c399aSSascha Wildner /* 228c12c399aSSascha Wildner * refcount was incremented for this event in 229c12c399aSSascha Wildner * mpssas_evt_handler. Decrement it here because the event has 230c12c399aSSascha Wildner * been processed. 231c12c399aSSascha Wildner */ 232c12c399aSSascha Wildner mpssas_startup_decrement(sassc); 233c12c399aSSascha Wildner break; 234c12c399aSSascha Wildner } 235c12c399aSSascha Wildner case MPI2_EVENT_SAS_DISCOVERY: 236c12c399aSSascha Wildner { 237c12c399aSSascha Wildner MPI2_EVENT_DATA_SAS_DISCOVERY *data; 238c12c399aSSascha Wildner 239c12c399aSSascha Wildner data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data; 240c12c399aSSascha Wildner 241c12c399aSSascha Wildner if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) 242c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n"); 243c12c399aSSascha Wildner if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { 244c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n"); 245c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_IN_DISCOVERY; 246c12c399aSSascha Wildner mpssas_discovery_end(sassc); 247c12c399aSSascha Wildner } 248c12c399aSSascha Wildner break; 249c12c399aSSascha Wildner } 250c12c399aSSascha Wildner case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: 251c12c399aSSascha Wildner { 252c12c399aSSascha Wildner Mpi2EventDataSasEnclDevStatusChange_t *data; 253c12c399aSSascha Wildner data = (Mpi2EventDataSasEnclDevStatusChange_t *) 254c12c399aSSascha Wildner fw_event->event_data; 255*f8fc9ba5SSascha Wildner mps_mapping_enclosure_dev_status_change_event(sc, data); 256c12c399aSSascha Wildner break; 257c12c399aSSascha Wildner } 258c12c399aSSascha Wildner case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: 259c12c399aSSascha Wildner { 260c12c399aSSascha Wildner Mpi2EventIrConfigElement_t *element; 261c12c399aSSascha Wildner int i; 262c12c399aSSascha Wildner u8 foreign_config; 263c12c399aSSascha Wildner Mpi2EventDataIrConfigChangeList_t *event_data; 264c12c399aSSascha Wildner struct mpssas_target *targ; 265c12c399aSSascha Wildner unsigned int id; 266c12c399aSSascha Wildner 267c12c399aSSascha Wildner event_data = fw_event->event_data; 268c12c399aSSascha Wildner foreign_config = (le32toh(event_data->Flags) & 269c12c399aSSascha Wildner MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; 270c12c399aSSascha Wildner 271c12c399aSSascha Wildner element = 272c12c399aSSascha Wildner (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; 273c12c399aSSascha Wildner id = mps_mapping_get_raid_id_from_handle 274c12c399aSSascha Wildner (sc, element->VolDevHandle); 275c12c399aSSascha Wildner 276c12c399aSSascha Wildner mps_mapping_ir_config_change_event(sc, event_data); 277c12c399aSSascha Wildner 278c12c399aSSascha Wildner for (i = 0; i < event_data->NumElements; i++, element++) { 279c12c399aSSascha Wildner switch (element->ReasonCode) { 280c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: 281c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_ADDED: 282c12c399aSSascha Wildner if (!foreign_config) { 283c12c399aSSascha Wildner if (mpssas_volume_add(sc, element)) { 284c12c399aSSascha Wildner kprintf("%s: failed to add RAID " 285c12c399aSSascha Wildner "volume with handle 0x%x\n", 286c12c399aSSascha Wildner __func__, le16toh(element-> 287c12c399aSSascha Wildner VolDevHandle)); 288c12c399aSSascha Wildner } 289c12c399aSSascha Wildner } 290c12c399aSSascha Wildner break; 291c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: 292c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_REMOVED: 293c12c399aSSascha Wildner /* 294c12c399aSSascha Wildner * Rescan after volume is deleted or removed. 295c12c399aSSascha Wildner */ 296c12c399aSSascha Wildner if (!foreign_config) { 297c12c399aSSascha Wildner if (id == MPS_MAP_BAD_ID) { 298c12c399aSSascha Wildner kprintf("%s: could not get ID " 299c12c399aSSascha Wildner "for volume with handle " 300c12c399aSSascha Wildner "0x%04x\n", __func__, 301c12c399aSSascha Wildner element->VolDevHandle); 302c12c399aSSascha Wildner break; 303c12c399aSSascha Wildner } 304c12c399aSSascha Wildner 305c12c399aSSascha Wildner targ = &sassc->targets[id]; 306c12c399aSSascha Wildner targ->handle = 0x0; 307c12c399aSSascha Wildner targ->encl_slot = 0x0; 308c12c399aSSascha Wildner targ->encl_handle = 0x0; 309c12c399aSSascha Wildner targ->exp_dev_handle = 0x0; 310c12c399aSSascha Wildner targ->phy_num = 0x0; 311c12c399aSSascha Wildner targ->linkrate = 0x0; 312c12c399aSSascha Wildner mpssas_rescan_target(sc, targ); 313c12c399aSSascha Wildner kprintf("RAID target id 0x%x removed\n", 314c12c399aSSascha Wildner targ->tid); 315c12c399aSSascha Wildner } 316c12c399aSSascha Wildner break; 317c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: 318c12c399aSSascha Wildner /* 319c12c399aSSascha Wildner * Phys Disk of a volume has been created. Hide 320c12c399aSSascha Wildner * it from the OS. 321c12c399aSSascha Wildner */ 322c12c399aSSascha Wildner mpssas_prepare_remove(sassc, element-> 323c12c399aSSascha Wildner PhysDiskDevHandle); 324c12c399aSSascha Wildner break; 325c12c399aSSascha Wildner case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: 326c12c399aSSascha Wildner /* 327c12c399aSSascha Wildner * Phys Disk of a volume has been deleted. 328c12c399aSSascha Wildner * Expose it to the OS. 329c12c399aSSascha Wildner */ 330c12c399aSSascha Wildner if (mpssas_add_device(sc, 331c12c399aSSascha Wildner element->PhysDiskDevHandle, 0)){ 332c12c399aSSascha Wildner kprintf("%s: failed to add device with " 333c12c399aSSascha Wildner "handle 0x%x\n", __func__, 334c12c399aSSascha Wildner element->PhysDiskDevHandle); 335c12c399aSSascha Wildner mpssas_prepare_remove(sassc, element-> 336c12c399aSSascha Wildner PhysDiskDevHandle); 337c12c399aSSascha Wildner } 338c12c399aSSascha Wildner break; 339c12c399aSSascha Wildner } 340c12c399aSSascha Wildner } 341c12c399aSSascha Wildner /* 342c12c399aSSascha Wildner * refcount was incremented for this event in 343c12c399aSSascha Wildner * mpssas_evt_handler. Decrement it here because the event has 344c12c399aSSascha Wildner * been processed. 345c12c399aSSascha Wildner */ 346c12c399aSSascha Wildner mpssas_startup_decrement(sassc); 347c12c399aSSascha Wildner break; 348c12c399aSSascha Wildner } 349c12c399aSSascha Wildner case MPI2_EVENT_IR_VOLUME: 350c12c399aSSascha Wildner { 351c12c399aSSascha Wildner Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; 352c12c399aSSascha Wildner 353c12c399aSSascha Wildner /* 354c12c399aSSascha Wildner * Informational only. 355c12c399aSSascha Wildner */ 356c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n"); 357c12c399aSSascha Wildner switch (event_data->ReasonCode) { 358c12c399aSSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED: 359c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Volume Settings " 360c12c399aSSascha Wildner "changed from 0x%x to 0x%x for Volome with " 36190ff74f1SSascha Wildner "handle 0x%x", event_data->PreviousValue, 36290ff74f1SSascha Wildner event_data->NewValue, 363c12c399aSSascha Wildner event_data->VolDevHandle); 364c12c399aSSascha Wildner break; 365c12c399aSSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED: 366c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Volume Status " 367c12c399aSSascha Wildner "changed from 0x%x to 0x%x for Volome with " 36890ff74f1SSascha Wildner "handle 0x%x", event_data->PreviousValue, 36990ff74f1SSascha Wildner event_data->NewValue, 370c12c399aSSascha Wildner event_data->VolDevHandle); 371c12c399aSSascha Wildner break; 372c12c399aSSascha Wildner case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED: 373c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Volume State " 374c12c399aSSascha Wildner "changed from 0x%x to 0x%x for Volome with " 37590ff74f1SSascha Wildner "handle 0x%x", event_data->PreviousValue, 37690ff74f1SSascha Wildner event_data->NewValue, 377c12c399aSSascha Wildner event_data->VolDevHandle); 378c12c399aSSascha Wildner break; 379c12c399aSSascha Wildner default: 380c12c399aSSascha Wildner break; 381c12c399aSSascha Wildner } 382c12c399aSSascha Wildner break; 383c12c399aSSascha Wildner } 384c12c399aSSascha Wildner case MPI2_EVENT_IR_PHYSICAL_DISK: 385c12c399aSSascha Wildner { 386c12c399aSSascha Wildner Mpi2EventDataIrPhysicalDisk_t *event_data = 387c12c399aSSascha Wildner fw_event->event_data; 388c12c399aSSascha Wildner 389c12c399aSSascha Wildner /* 390c12c399aSSascha Wildner * Informational only. 391c12c399aSSascha Wildner */ 392c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n"); 393c12c399aSSascha Wildner switch (event_data->ReasonCode) { 394c12c399aSSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED: 395c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Phys Disk Settings " 396c12c399aSSascha Wildner "changed from 0x%x to 0x%x for Phys Disk Number " 397c12c399aSSascha Wildner "%d and handle 0x%x at Enclosure handle 0x%x, Slot " 39890ff74f1SSascha Wildner "%d", event_data->PreviousValue, 39990ff74f1SSascha Wildner event_data->NewValue, event_data->PhysDiskNum, 400c12c399aSSascha Wildner event_data->PhysDiskDevHandle, 401c12c399aSSascha Wildner event_data->EnclosureHandle, event_data->Slot); 402c12c399aSSascha Wildner break; 403c12c399aSSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED: 404c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Phys Disk Status changed " 405c12c399aSSascha Wildner "from 0x%x to 0x%x for Phys Disk Number %d and " 406c12c399aSSascha Wildner "handle 0x%x at Enclosure handle 0x%x, Slot %d", 40790ff74f1SSascha Wildner event_data->PreviousValue, event_data->NewValue, 408c12c399aSSascha Wildner event_data->PhysDiskNum, 409c12c399aSSascha Wildner event_data->PhysDiskDevHandle, 410c12c399aSSascha Wildner event_data->EnclosureHandle, event_data->Slot); 411c12c399aSSascha Wildner break; 412c12c399aSSascha Wildner case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED: 413c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " Phys Disk State changed " 414c12c399aSSascha Wildner "from 0x%x to 0x%x for Phys Disk Number %d and " 415c12c399aSSascha Wildner "handle 0x%x at Enclosure handle 0x%x, Slot %d", 41690ff74f1SSascha Wildner event_data->PreviousValue, event_data->NewValue, 417c12c399aSSascha Wildner event_data->PhysDiskNum, 418c12c399aSSascha Wildner event_data->PhysDiskDevHandle, 419c12c399aSSascha Wildner event_data->EnclosureHandle, event_data->Slot); 420c12c399aSSascha Wildner break; 421c12c399aSSascha Wildner default: 422c12c399aSSascha Wildner break; 423c12c399aSSascha Wildner } 424c12c399aSSascha Wildner break; 425c12c399aSSascha Wildner } 426c12c399aSSascha Wildner case MPI2_EVENT_IR_OPERATION_STATUS: 427c12c399aSSascha Wildner { 428c12c399aSSascha Wildner Mpi2EventDataIrOperationStatus_t *event_data = 429c12c399aSSascha Wildner fw_event->event_data; 430c12c399aSSascha Wildner 431c12c399aSSascha Wildner /* 432c12c399aSSascha Wildner * Informational only. 433c12c399aSSascha Wildner */ 434c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n"); 435c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, " RAID Operation of %d is %d " 436c12c399aSSascha Wildner "percent complete for Volume with handle 0x%x", 437c12c399aSSascha Wildner event_data->RAIDOperation, event_data->PercentComplete, 438c12c399aSSascha Wildner event_data->VolDevHandle); 439c12c399aSSascha Wildner break; 440c12c399aSSascha Wildner } 441c12c399aSSascha Wildner case MPI2_EVENT_LOG_ENTRY_ADDED: 442c12c399aSSascha Wildner { 443c12c399aSSascha Wildner pMpi2EventDataLogEntryAdded_t logEntry; 444c12c399aSSascha Wildner uint16_t logQualifier; 445c12c399aSSascha Wildner uint8_t logCode; 446c12c399aSSascha Wildner 447c12c399aSSascha Wildner logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data; 448c12c399aSSascha Wildner logQualifier = logEntry->LogEntryQualifier; 449c12c399aSSascha Wildner 450c12c399aSSascha Wildner if (logQualifier == MPI2_WD_LOG_ENTRY) { 451c12c399aSSascha Wildner logCode = logEntry->LogData[0]; 452c12c399aSSascha Wildner 453c12c399aSSascha Wildner switch (logCode) { 454c12c399aSSascha Wildner case MPI2_WD_SSD_THROTTLING: 455c12c399aSSascha Wildner kprintf("WarpDrive Warning: IO Throttling has " 456c12c399aSSascha Wildner "occurred in the WarpDrive subsystem. " 457c12c399aSSascha Wildner "Check WarpDrive documentation for " 458c12c399aSSascha Wildner "additional details\n"); 459c12c399aSSascha Wildner break; 460c12c399aSSascha Wildner case MPI2_WD_DRIVE_LIFE_WARN: 461c12c399aSSascha Wildner kprintf("WarpDrive Warning: Program/Erase " 462c12c399aSSascha Wildner "Cycles for the WarpDrive subsystem in " 463c12c399aSSascha Wildner "degraded range. Check WarpDrive " 464c12c399aSSascha Wildner "documentation for additional details\n"); 465c12c399aSSascha Wildner break; 466c12c399aSSascha Wildner case MPI2_WD_DRIVE_LIFE_DEAD: 467c12c399aSSascha Wildner kprintf("WarpDrive Fatal Error: There are no " 468c12c399aSSascha Wildner "Program/Erase Cycles for the WarpDrive " 469c12c399aSSascha Wildner "subsystem. The storage device will be in " 470c12c399aSSascha Wildner "read-only mode. Check WarpDrive " 471c12c399aSSascha Wildner "documentation for additional details\n"); 472c12c399aSSascha Wildner break; 473c12c399aSSascha Wildner case MPI2_WD_RAIL_MON_FAIL: 474c12c399aSSascha Wildner kprintf("WarpDrive Fatal Error: The Backup Rail " 475c12c399aSSascha Wildner "Monitor has failed on the WarpDrive " 476c12c399aSSascha Wildner "subsystem. Check WarpDrive documentation " 477c12c399aSSascha Wildner "for additional details\n"); 478c12c399aSSascha Wildner break; 479c12c399aSSascha Wildner default: 480c12c399aSSascha Wildner break; 481c12c399aSSascha Wildner } 482c12c399aSSascha Wildner } 483c12c399aSSascha Wildner break; 484c12c399aSSascha Wildner } 485c12c399aSSascha Wildner case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: 486c12c399aSSascha Wildner case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: 487c12c399aSSascha Wildner default: 488c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n", 489c12c399aSSascha Wildner fw_event->event); 490c12c399aSSascha Wildner break; 491c12c399aSSascha Wildner 492c12c399aSSascha Wildner } 493c12c399aSSascha Wildner mpssas_fw_event_free(sc, fw_event); 494c12c399aSSascha Wildner } 495c12c399aSSascha Wildner 496c12c399aSSascha Wildner void 497c12c399aSSascha Wildner mpssas_firmware_event_work(void *arg, int pending) 498c12c399aSSascha Wildner { 499c12c399aSSascha Wildner struct mps_fw_event_work *fw_event; 500c12c399aSSascha Wildner struct mps_softc *sc; 501c12c399aSSascha Wildner 502c12c399aSSascha Wildner sc = (struct mps_softc *)arg; 503c12c399aSSascha Wildner mps_lock(sc); 504c12c399aSSascha Wildner while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) { 505c12c399aSSascha Wildner TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link); 506c12c399aSSascha Wildner mpssas_fw_work(sc, fw_event); 507c12c399aSSascha Wildner } 508c12c399aSSascha Wildner mps_unlock(sc); 509c12c399aSSascha Wildner } 510c12c399aSSascha Wildner 511c12c399aSSascha Wildner static int 512c12c399aSSascha Wildner mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){ 513c12c399aSSascha Wildner char devstring[80]; 514c12c399aSSascha Wildner struct mpssas_softc *sassc; 515c12c399aSSascha Wildner struct mpssas_target *targ; 516c12c399aSSascha Wildner Mpi2ConfigReply_t mpi_reply; 517c12c399aSSascha Wildner Mpi2SasDevicePage0_t config_page; 518c12c399aSSascha Wildner uint64_t sas_address, sata_sas_address; 519c12c399aSSascha Wildner uint64_t parent_sas_address = 0; 520c12c399aSSascha Wildner u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); 521c12c399aSSascha Wildner u32 device_info, parent_devinfo = 0; 522c12c399aSSascha Wildner unsigned int id; 523c12c399aSSascha Wildner int ret; 524c12c399aSSascha Wildner int error = 0; 525c12c399aSSascha Wildner 526c12c399aSSascha Wildner sassc = sc->sassc; 527c12c399aSSascha Wildner mpssas_startup_increment(sassc); 528c12c399aSSascha Wildner if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, 529c12c399aSSascha Wildner MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { 530c12c399aSSascha Wildner kprintf("%s: error reading SAS device page0\n", __func__); 531c12c399aSSascha Wildner error = ENXIO; 532c12c399aSSascha Wildner goto out; 533c12c399aSSascha Wildner } 534c12c399aSSascha Wildner 535c12c399aSSascha Wildner device_info = le32toh(config_page.DeviceInfo); 536c12c399aSSascha Wildner 537c12c399aSSascha Wildner if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) 538c12c399aSSascha Wildner && (config_page.ParentDevHandle != 0)) { 539c12c399aSSascha Wildner Mpi2ConfigReply_t tmp_mpi_reply; 540c12c399aSSascha Wildner Mpi2SasDevicePage0_t parent_config_page; 541c12c399aSSascha Wildner 542c12c399aSSascha Wildner if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply, 543c12c399aSSascha Wildner &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, 544c12c399aSSascha Wildner le16toh(config_page.ParentDevHandle)))) { 545c12c399aSSascha Wildner kprintf("%s: error reading SAS device %#x page0\n", 546c12c399aSSascha Wildner __func__, le16toh(config_page.ParentDevHandle)); 547c12c399aSSascha Wildner } else { 548c12c399aSSascha Wildner parent_sas_address = parent_config_page.SASAddress.High; 549c12c399aSSascha Wildner parent_sas_address = (parent_sas_address << 32) | 550c12c399aSSascha Wildner parent_config_page.SASAddress.Low; 551c12c399aSSascha Wildner parent_devinfo = le32toh(parent_config_page.DeviceInfo); 552c12c399aSSascha Wildner } 553c12c399aSSascha Wildner } 554c12c399aSSascha Wildner /* TODO Check proper endianess */ 555c12c399aSSascha Wildner sas_address = config_page.SASAddress.High; 556c12c399aSSascha Wildner sas_address = (sas_address << 32) | 557c12c399aSSascha Wildner config_page.SASAddress.Low; 558c12c399aSSascha Wildner 559c12c399aSSascha Wildner if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) 560c12c399aSSascha Wildner == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { 561c12c399aSSascha Wildner if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { 562c12c399aSSascha Wildner ret = mpssas_get_sas_address_for_sata_disk(sc, 563c12c399aSSascha Wildner &sata_sas_address, handle, device_info); 564c12c399aSSascha Wildner if (!ret) 565c12c399aSSascha Wildner id = mps_mapping_get_sas_id(sc, 566c12c399aSSascha Wildner sata_sas_address, handle); 567c12c399aSSascha Wildner else 568c12c399aSSascha Wildner id = mps_mapping_get_sas_id(sc, 569c12c399aSSascha Wildner sas_address, handle); 570c12c399aSSascha Wildner } else 571c12c399aSSascha Wildner id = mps_mapping_get_sas_id(sc, sas_address, 572c12c399aSSascha Wildner handle); 573c12c399aSSascha Wildner } else 574c12c399aSSascha Wildner id = mps_mapping_get_sas_id(sc, sas_address, handle); 575c12c399aSSascha Wildner 576c12c399aSSascha Wildner if (id == MPS_MAP_BAD_ID) { 577c12c399aSSascha Wildner kprintf("failure at %s:%d/%s()! Could not get ID for device " 578c12c399aSSascha Wildner "with handle 0x%04x\n", __FILE__, __LINE__, __func__, 579c12c399aSSascha Wildner handle); 580c12c399aSSascha Wildner error = ENXIO; 581c12c399aSSascha Wildner goto out; 582c12c399aSSascha Wildner } 583c12c399aSSascha Wildner mps_vprintf(sc, "SAS Address from SAS device page0 = %jx\n", 584c12c399aSSascha Wildner sas_address); 585c12c399aSSascha Wildner targ = &sassc->targets[id]; 586c12c399aSSascha Wildner targ->devinfo = device_info; 587c12c399aSSascha Wildner targ->devname = le32toh(config_page.DeviceName.High); 588c12c399aSSascha Wildner targ->devname = (targ->devname << 32) | 589c12c399aSSascha Wildner le32toh(config_page.DeviceName.Low); 590c12c399aSSascha Wildner targ->encl_handle = le16toh(config_page.EnclosureHandle); 591c12c399aSSascha Wildner targ->encl_slot = le16toh(config_page.Slot); 592c12c399aSSascha Wildner targ->handle = handle; 593c12c399aSSascha Wildner targ->parent_handle = le16toh(config_page.ParentDevHandle); 594c12c399aSSascha Wildner targ->sasaddr = mps_to_u64(&config_page.SASAddress); 595c12c399aSSascha Wildner targ->parent_sasaddr = le64toh(parent_sas_address); 596c12c399aSSascha Wildner targ->parent_devinfo = parent_devinfo; 597c12c399aSSascha Wildner targ->tid = id; 598c12c399aSSascha Wildner targ->linkrate = (linkrate>>4); 599c12c399aSSascha Wildner targ->flags = 0; 600c12c399aSSascha Wildner TAILQ_INIT(&targ->commands); 601c12c399aSSascha Wildner TAILQ_INIT(&targ->timedout_commands); 602c12c399aSSascha Wildner SLIST_INIT(&targ->luns); 603c12c399aSSascha Wildner mps_describe_devinfo(targ->devinfo, devstring, 80); 604c12c399aSSascha Wildner mps_vprintf(sc, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring, 605c12c399aSSascha Wildner mps_describe_table(mps_linkrate_names, targ->linkrate), 606c12c399aSSascha Wildner targ->handle, targ->encl_handle, targ->encl_slot); 607c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) 608c12c399aSSascha Wildner mpssas_rescan_target(sc, targ); 609c12c399aSSascha Wildner mps_vprintf(sc, "Target id 0x%x added\n", targ->tid); 610c12c399aSSascha Wildner out: 611c12c399aSSascha Wildner mpssas_startup_decrement(sassc); 612c12c399aSSascha Wildner return (error); 613c12c399aSSascha Wildner 614c12c399aSSascha Wildner } 615c12c399aSSascha Wildner 616c12c399aSSascha Wildner int 617c12c399aSSascha Wildner mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc, 618c12c399aSSascha Wildner u64 *sas_address, u16 handle, u32 device_info) 619c12c399aSSascha Wildner { 620c12c399aSSascha Wildner Mpi2SataPassthroughReply_t mpi_reply; 621c12c399aSSascha Wildner int i, rc, try_count; 622c12c399aSSascha Wildner u32 *bufferptr; 623c12c399aSSascha Wildner union _sata_sas_address hash_address; 624c12c399aSSascha Wildner struct _ata_identify_device_data ata_identify; 625c12c399aSSascha Wildner u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN]; 626c12c399aSSascha Wildner u32 ioc_status; 627c12c399aSSascha Wildner u8 sas_status; 628c12c399aSSascha Wildner 629c12c399aSSascha Wildner memset(&ata_identify, 0, sizeof(ata_identify)); 630c12c399aSSascha Wildner try_count = 0; 631c12c399aSSascha Wildner do { 632c12c399aSSascha Wildner rc = mpssas_get_sata_identify(sc, handle, &mpi_reply, 633c12c399aSSascha Wildner (char *)&ata_identify, sizeof(ata_identify), device_info); 634c12c399aSSascha Wildner try_count++; 635c12c399aSSascha Wildner ioc_status = le16toh(mpi_reply.IOCStatus) 636c12c399aSSascha Wildner & MPI2_IOCSTATUS_MASK; 637c12c399aSSascha Wildner sas_status = mpi_reply.SASStatus; 638c12c399aSSascha Wildner } while ((rc == -EAGAIN || ioc_status || sas_status) && 639c12c399aSSascha Wildner (try_count < 5)); 640c12c399aSSascha Wildner 641c12c399aSSascha Wildner if (rc == 0 && !ioc_status && !sas_status) { 642c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: got SATA identify successfully " 643c12c399aSSascha Wildner "for handle = 0x%x with try_count = %d\n", 644c12c399aSSascha Wildner __func__, handle, try_count); 645c12c399aSSascha Wildner } else { 646c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: handle = 0x%x failed\n", 647c12c399aSSascha Wildner __func__, handle); 648c12c399aSSascha Wildner return -1; 649c12c399aSSascha Wildner } 650c12c399aSSascha Wildner /* Copy & byteswap the 40 byte model number to a buffer */ 651c12c399aSSascha Wildner for (i = 0; i < MPT2SAS_MN_LEN; i += 2) { 652c12c399aSSascha Wildner buffer[i] = ((u8 *)ata_identify.model_number)[i + 1]; 653c12c399aSSascha Wildner buffer[i + 1] = ((u8 *)ata_identify.model_number)[i]; 654c12c399aSSascha Wildner } 655c12c399aSSascha Wildner /* Copy & byteswap the 20 byte serial number to a buffer */ 656c12c399aSSascha Wildner for (i = 0; i < MPT2SAS_SN_LEN; i += 2) { 657c12c399aSSascha Wildner buffer[MPT2SAS_MN_LEN + i] = 658c12c399aSSascha Wildner ((u8 *)ata_identify.serial_number)[i + 1]; 659c12c399aSSascha Wildner buffer[MPT2SAS_MN_LEN + i + 1] = 660c12c399aSSascha Wildner ((u8 *)ata_identify.serial_number)[i]; 661c12c399aSSascha Wildner } 662c12c399aSSascha Wildner bufferptr = (u32 *)buffer; 663c12c399aSSascha Wildner /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8, 664c12c399aSSascha Wildner * so loop through the first 56 bytes (7*8), 665c12c399aSSascha Wildner * and then add in the last dword. 666c12c399aSSascha Wildner */ 667c12c399aSSascha Wildner hash_address.word.low = 0; 668c12c399aSSascha Wildner hash_address.word.high = 0; 669c12c399aSSascha Wildner for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) { 670c12c399aSSascha Wildner hash_address.word.low += *bufferptr; 671c12c399aSSascha Wildner bufferptr++; 672c12c399aSSascha Wildner hash_address.word.high += *bufferptr; 673c12c399aSSascha Wildner bufferptr++; 674c12c399aSSascha Wildner } 675c12c399aSSascha Wildner /* Add the last dword */ 676c12c399aSSascha Wildner hash_address.word.low += *bufferptr; 677c12c399aSSascha Wildner /* Make sure the hash doesn't start with 5, because it could clash 678c12c399aSSascha Wildner * with a SAS address. Change 5 to a D. 679c12c399aSSascha Wildner */ 680c12c399aSSascha Wildner if ((hash_address.word.high & 0x000000F0) == (0x00000050)) 681c12c399aSSascha Wildner hash_address.word.high |= 0x00000080; 682c12c399aSSascha Wildner *sas_address = (u64)hash_address.wwid[0] << 56 | 683c12c399aSSascha Wildner (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 | 684c12c399aSSascha Wildner (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 | 685c12c399aSSascha Wildner (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 | 686c12c399aSSascha Wildner (u64)hash_address.wwid[7]; 687c12c399aSSascha Wildner return 0; 688c12c399aSSascha Wildner } 689c12c399aSSascha Wildner 690c12c399aSSascha Wildner static int 691c12c399aSSascha Wildner mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, 692c12c399aSSascha Wildner Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo) 693c12c399aSSascha Wildner { 694c12c399aSSascha Wildner Mpi2SataPassthroughRequest_t *mpi_request; 695c12c399aSSascha Wildner Mpi2SataPassthroughReply_t *reply; 696c12c399aSSascha Wildner struct mps_command *cm; 697c12c399aSSascha Wildner char *buffer; 698c12c399aSSascha Wildner int error = 0; 699c12c399aSSascha Wildner 700c12c399aSSascha Wildner buffer = kmalloc( sz, M_MPT2, M_NOWAIT | M_ZERO); 701c12c399aSSascha Wildner if (!buffer) 702c12c399aSSascha Wildner return ENOMEM; 703c12c399aSSascha Wildner 704df8658e0SSascha Wildner if ((cm = mps_alloc_command(sc)) == NULL) { 705df8658e0SSascha Wildner kfree(buffer, M_MPT2); 706c12c399aSSascha Wildner return (EBUSY); 707df8658e0SSascha Wildner } 708c12c399aSSascha Wildner mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req; 709c12c399aSSascha Wildner bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST)); 710c12c399aSSascha Wildner mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH; 711c12c399aSSascha Wildner mpi_request->VF_ID = 0; 712c12c399aSSascha Wildner mpi_request->DevHandle = htole16(handle); 713c12c399aSSascha Wildner mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO | 714c12c399aSSascha Wildner MPI2_SATA_PT_REQ_PT_FLAGS_READ); 715c12c399aSSascha Wildner mpi_request->DataLength = htole32(sz); 716c12c399aSSascha Wildner mpi_request->CommandFIS[0] = 0x27; 717c12c399aSSascha Wildner mpi_request->CommandFIS[1] = 0x80; 718c12c399aSSascha Wildner mpi_request->CommandFIS[2] = (devinfo & 719c12c399aSSascha Wildner MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC; 720c12c399aSSascha Wildner cm->cm_sge = &mpi_request->SGL; 721c12c399aSSascha Wildner cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); 722c12c399aSSascha Wildner cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; 723c12c399aSSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 724c12c399aSSascha Wildner cm->cm_data = buffer; 725c12c399aSSascha Wildner cm->cm_length = htole32(sz); 726c12c399aSSascha Wildner error = mps_request_polled(sc, cm); 727c12c399aSSascha Wildner reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; 728c12c399aSSascha Wildner if (error || (reply == NULL)) { 729c12c399aSSascha Wildner /* FIXME */ 730c12c399aSSascha Wildner /* If the poll returns error then we need to do diag reset */ 731c12c399aSSascha Wildner kprintf("%s: poll for page completed with error %d", 732c12c399aSSascha Wildner __func__, error); 733c12c399aSSascha Wildner error = ENXIO; 734c12c399aSSascha Wildner goto out; 735c12c399aSSascha Wildner } 736c12c399aSSascha Wildner bcopy(buffer, id_buffer, sz); 737c12c399aSSascha Wildner bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t)); 738c12c399aSSascha Wildner if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != 739c12c399aSSascha Wildner MPI2_IOCSTATUS_SUCCESS) { 740c12c399aSSascha Wildner kprintf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n", 741c12c399aSSascha Wildner __func__, reply->IOCStatus); 742c12c399aSSascha Wildner error = ENXIO; 743c12c399aSSascha Wildner goto out; 744c12c399aSSascha Wildner } 745c12c399aSSascha Wildner out: 746c12c399aSSascha Wildner mps_free_command(sc, cm); 747c12c399aSSascha Wildner kfree(buffer, M_MPT2); 748c12c399aSSascha Wildner return (error); 749c12c399aSSascha Wildner } 750c12c399aSSascha Wildner 751c12c399aSSascha Wildner static int 752c12c399aSSascha Wildner mpssas_volume_add(struct mps_softc *sc, Mpi2EventIrConfigElement_t *element) 753c12c399aSSascha Wildner { 754c12c399aSSascha Wildner struct mpssas_softc *sassc; 755c12c399aSSascha Wildner struct mpssas_target *targ; 756c12c399aSSascha Wildner u64 wwid; 757c12c399aSSascha Wildner u16 handle = le16toh(element->VolDevHandle); 758c12c399aSSascha Wildner unsigned int id; 759c12c399aSSascha Wildner int error = 0; 760c12c399aSSascha Wildner 761c12c399aSSascha Wildner sassc = sc->sassc; 762c12c399aSSascha Wildner mpssas_startup_increment(sassc); 763c12c399aSSascha Wildner mps_config_get_volume_wwid(sc, handle, &wwid); 764c12c399aSSascha Wildner if (!wwid) { 765c12c399aSSascha Wildner kprintf("%s: invalid WWID; cannot add volume to mapping table\n", 766c12c399aSSascha Wildner __func__); 767c12c399aSSascha Wildner error = ENXIO; 768c12c399aSSascha Wildner goto out; 769c12c399aSSascha Wildner } 770c12c399aSSascha Wildner 771c12c399aSSascha Wildner id = mps_mapping_get_raid_id(sc, wwid, handle); 772c12c399aSSascha Wildner if (id == MPS_MAP_BAD_ID) { 773c12c399aSSascha Wildner kprintf("%s: could not get ID for volume with handle 0x%04x and " 774c12c399aSSascha Wildner "WWID 0x%016llx\n", __func__, handle, 775c12c399aSSascha Wildner (unsigned long long)wwid); 776c12c399aSSascha Wildner error = ENXIO; 777c12c399aSSascha Wildner goto out; 778c12c399aSSascha Wildner } 779c12c399aSSascha Wildner 780c12c399aSSascha Wildner targ = &sassc->targets[id]; 781c12c399aSSascha Wildner targ->tid = id; 782c12c399aSSascha Wildner targ->handle = handle; 783c12c399aSSascha Wildner targ->devname = wwid; 784c12c399aSSascha Wildner TAILQ_INIT(&targ->commands); 785c12c399aSSascha Wildner TAILQ_INIT(&targ->timedout_commands); 786c12c399aSSascha Wildner SLIST_INIT(&targ->luns); 787c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) 788c12c399aSSascha Wildner mpssas_rescan_target(sc, targ); 789c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n", 790c12c399aSSascha Wildner targ->tid, wwid); 791c12c399aSSascha Wildner out: 792c12c399aSSascha Wildner mpssas_startup_decrement(sassc); 793c12c399aSSascha Wildner return (error); 794c12c399aSSascha Wildner } 795c12c399aSSascha Wildner 796c12c399aSSascha Wildner /** 797c12c399aSSascha Wildner * mpssas_ir_shutdown - IR shutdown notification 798c12c399aSSascha Wildner * @sc: per adapter object 799c12c399aSSascha Wildner * 800c12c399aSSascha Wildner * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that 801c12c399aSSascha Wildner * the host system is shutting down. 802c12c399aSSascha Wildner * 803c12c399aSSascha Wildner * Return nothing. 804c12c399aSSascha Wildner */ 805c12c399aSSascha Wildner void 806c12c399aSSascha Wildner mpssas_ir_shutdown(struct mps_softc *sc) 807c12c399aSSascha Wildner { 808c12c399aSSascha Wildner u16 volume_mapping_flags; 809c12c399aSSascha Wildner u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); 810c12c399aSSascha Wildner struct dev_mapping_table *mt_entry; 811c12c399aSSascha Wildner u32 start_idx, end_idx; 812c12c399aSSascha Wildner unsigned int id, found_volume = 0; 813c12c399aSSascha Wildner struct mps_command *cm; 814c12c399aSSascha Wildner Mpi2RaidActionRequest_t *action; 815c12c399aSSascha Wildner 816cb7593b0SSepherosa Ziehau mps_lock(sc); 817cb7593b0SSepherosa Ziehau 818c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 819c12c399aSSascha Wildner 820c12c399aSSascha Wildner /* is IR firmware build loaded? */ 821c12c399aSSascha Wildner if (!sc->ir_firmware) 822cb7593b0SSepherosa Ziehau goto back; 823c12c399aSSascha Wildner 824c12c399aSSascha Wildner /* are there any volumes? Look at IR target IDs. */ 825c12c399aSSascha Wildner // TODO-later, this should be looked up in the RAID config structure 826c12c399aSSascha Wildner // when it is implemented. 827c12c399aSSascha Wildner volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & 828c12c399aSSascha Wildner MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; 829c12c399aSSascha Wildner if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { 830c12c399aSSascha Wildner start_idx = 0; 831c12c399aSSascha Wildner if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) 832c12c399aSSascha Wildner start_idx = 1; 833c12c399aSSascha Wildner } else 834c12c399aSSascha Wildner start_idx = sc->max_devices - sc->max_volumes; 835c12c399aSSascha Wildner end_idx = start_idx + sc->max_volumes - 1; 836c12c399aSSascha Wildner 837c12c399aSSascha Wildner for (id = start_idx; id < end_idx; id++) { 838c12c399aSSascha Wildner mt_entry = &sc->mapping_table[id]; 839c12c399aSSascha Wildner if ((mt_entry->physical_id != 0) && 840c12c399aSSascha Wildner (mt_entry->missing_count == 0)) { 841c12c399aSSascha Wildner found_volume = 1; 842c12c399aSSascha Wildner break; 843c12c399aSSascha Wildner } 844c12c399aSSascha Wildner } 845c12c399aSSascha Wildner 846c12c399aSSascha Wildner if (!found_volume) 847cb7593b0SSepherosa Ziehau goto back; 848c12c399aSSascha Wildner 849c12c399aSSascha Wildner if ((cm = mps_alloc_command(sc)) == NULL) { 850c12c399aSSascha Wildner kprintf("%s: command alloc failed\n", __func__); 851cb7593b0SSepherosa Ziehau goto back; 852c12c399aSSascha Wildner } 853c12c399aSSascha Wildner 854c12c399aSSascha Wildner action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; 855c12c399aSSascha Wildner action->Function = MPI2_FUNCTION_RAID_ACTION; 856c12c399aSSascha Wildner action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; 857c12c399aSSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 858c12c399aSSascha Wildner mps_request_polled(sc, cm); 859c12c399aSSascha Wildner 860c12c399aSSascha Wildner /* 861c12c399aSSascha Wildner * Don't check for reply, just leave. 862c12c399aSSascha Wildner */ 863c12c399aSSascha Wildner if (cm) 864c12c399aSSascha Wildner mps_free_command(sc, cm); 865cb7593b0SSepherosa Ziehau 866cb7593b0SSepherosa Ziehau back: 867cb7593b0SSepherosa Ziehau mps_unlock(sc); 868c12c399aSSascha Wildner } 869