*** src/sbin/camcontrol/camcontrol.c.orig --- src/sbin/camcontrol/camcontrol.c *************** *** 4232,4238 **** /*lba*/ 0, /*reladdr*/ 0, /*pmi*/ 0, ! &rcaplong, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ timeout ? timeout : 5000); --- 4232,4239 ---- /*lba*/ 0, /*reladdr*/ 0, /*pmi*/ 0, ! /*rcap_buf*/ (uint8_t *)&rcaplong, ! /*rcap_buf_len*/ sizeof(rcaplong), /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ timeout ? timeout : 5000); *** src/sys/cam/cam_ccb.h.orig --- src/sys/cam/cam_ccb.h *************** *** 1118,1123 **** --- 1118,1124 ---- #define CDAI_TYPE_SCSI_DEVID 1 #define CDAI_TYPE_SERIAL_NUM 2 #define CDAI_TYPE_PHYS_PATH 3 + #define CDAI_TYPE_RCAPLONG 4 off_t bufsiz; /* IN: Size of external buffer */ #define CAM_SCSI_DEVID_MAXLEN 65536 /* length in buffer is an uint16_t */ off_t provsiz; /* OUT: Size required/used */ *** src/sys/cam/cam_xpt.c.orig --- src/sys/cam/cam_xpt.c *************** *** 4588,4593 **** --- 4588,4604 ---- cam_devq_resize(devq, devq->alloc_queue.array_size - 1); camq_fini(&device->drvq); cam_ccbq_fini(&device->ccbq); + /* + * Free allocated memory. free(9) does nothing if the + * supplied pointer is NULL, so it is safe to call without + * checking. + */ + free(device->supported_vpds, M_CAMXPT); + free(device->device_id, M_CAMXPT); + free(device->physpath, M_CAMXPT); + free(device->rcap_buf, M_CAMXPT); + free(device->serial_num, M_CAMXPT); + xpt_release_target(device->target); free(device, M_CAMXPT); } else *** src/sys/cam/cam_xpt_internal.h.orig --- src/sys/cam/cam_xpt_internal.h *************** *** 99,104 **** --- 99,106 ---- uint8_t *device_id; uint8_t physpath_len; uint8_t *physpath; /* physical path string form */ + uint32_t rcap_len; + uint8_t *rcap_buf; struct ata_params ident_data; u_int8_t inq_flags; /* * Current settings for inquiry flags. *** src/sys/cam/scsi/scsi_all.c.orig --- src/sys/cam/scsi/scsi_all.c *************** *** 5325,5332 **** scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, uint64_t lba, int reladr, int pmi, ! struct scsi_read_capacity_data_long *rcap_buf, ! uint8_t sense_len, uint32_t timeout) { struct scsi_read_capacity_16 *scsi_cmd; --- 5325,5332 ---- scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, uint64_t lba, int reladr, int pmi, ! uint8_t *rcap_buf, int rcap_buf_len, uint8_t sense_len, ! uint32_t timeout) { struct scsi_read_capacity_16 *scsi_cmd; *************** *** 5337,5343 **** /*flags*/CAM_DIR_IN, tag_action, /*data_ptr*/(u_int8_t *)rcap_buf, ! /*dxfer_len*/sizeof(*rcap_buf), sense_len, sizeof(*scsi_cmd), timeout); --- 5337,5343 ---- /*flags*/CAM_DIR_IN, tag_action, /*data_ptr*/(u_int8_t *)rcap_buf, ! /*dxfer_len*/rcap_buf_len, sense_len, sizeof(*scsi_cmd), timeout); *************** *** 5346,5352 **** scsi_cmd->opcode = SERVICE_ACTION_IN; scsi_cmd->service_action = SRC16_SERVICE_ACTION; scsi_u64to8b(lba, scsi_cmd->addr); ! scsi_ulto4b(sizeof(*rcap_buf), scsi_cmd->alloc_len); if (pmi) reladr |= SRC16_PMI; if (reladr) --- 5346,5352 ---- scsi_cmd->opcode = SERVICE_ACTION_IN; scsi_cmd->service_action = SRC16_SERVICE_ACTION; scsi_u64to8b(lba, scsi_cmd->addr); ! scsi_ulto4b(rcap_buf_len, scsi_cmd->alloc_len); if (pmi) reladr |= SRC16_PMI; if (reladr) *** src/sys/cam/scsi/scsi_all.h.orig --- src/sys/cam/scsi/scsi_all.h *************** *** 1437,1451 **** uint8_t length[4]; #define SRC16_PROT_EN 0x01 #define SRC16_P_TYPE 0x0e uint8_t prot; #define SRC16_LBPPBE 0x0f #define SRC16_PI_EXPONENT 0xf0 #define SRC16_PI_EXPONENT_SHIFT 4 uint8_t prot_lbppbe; ! #define SRC16_LALBA 0x3fff ! #define SRC16_LBPRZ 0x4000 ! #define SRC16_LBPME 0x8000 uint8_t lalba_lbp[2]; }; struct scsi_report_luns --- 1437,1462 ---- uint8_t length[4]; #define SRC16_PROT_EN 0x01 #define SRC16_P_TYPE 0x0e + #define SRC16_PTYPE_1 0x00 + #define SRC16_PTYPE_2 0x02 + #define SRC16_PTYPE_3 0x04 uint8_t prot; #define SRC16_LBPPBE 0x0f #define SRC16_PI_EXPONENT 0xf0 #define SRC16_PI_EXPONENT_SHIFT 4 uint8_t prot_lbppbe; ! #define SRC16_LALBA 0x3f ! #define SRC16_LBPRZ 0x40 ! #define SRC16_LBPME 0x80 ! /* ! * Alternate versions of these macros that are intended for use on a 16-bit ! * version of the lalba_lbp field instead of the array of 2 8 bit numbers. ! */ ! #define SRC16_LALBA_A 0x3fff ! #define SRC16_LBPRZ_A 0x4000 ! #define SRC16_LBPME_A 0x8000 uint8_t lalba_lbp[2]; + uint8_t reserved[16]; }; struct scsi_report_luns *************** *** 2293,2301 **** void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, uint64_t lba, int reladr, int pmi, ! struct scsi_read_capacity_data_long ! *rcap_buf, uint8_t sense_len, ! uint32_t timeout); void scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, --- 2304,2311 ---- void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, uint64_t lba, int reladr, int pmi, ! uint8_t *rcap_buf, int rcap_buf_len, ! uint8_t sense_len, uint32_t timeout); void scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, *** src/sys/cam/scsi/scsi_da.c.orig --- src/sys/cam/scsi/scsi_da.c *************** *** 160,165 **** --- 160,166 ---- struct callout sendordered_c; uint64_t wwpn; uint8_t unmap_buf[UNMAP_MAX_RANGES * 16 + 8]; + struct scsi_read_capacity_data_long rcaplong; }; struct da_quirk_entry { *************** *** 830,836 **** static void daprevent(struct cam_periph *periph, int action); static int dagetcapacity(struct cam_periph *periph); static void dasetgeom(struct cam_periph *periph, uint32_t block_len, ! uint64_t maxsector, u_int lbppbe, u_int lalba); static timeout_t dasendorderedtag; static void dashutdown(void *arg, int howto); --- 831,839 ---- static void daprevent(struct cam_periph *periph, int action); static int dagetcapacity(struct cam_periph *periph); static void dasetgeom(struct cam_periph *periph, uint32_t block_len, ! uint64_t maxsector, ! struct scsi_read_capacity_data_long *rcaplong, ! size_t rcap_size); static timeout_t dasendorderedtag; static void dashutdown(void *arg, int howto); *************** *** 1948,1954 **** /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, ! rcaplong, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); start_ccb->ccb_h.ccb_bp = NULL; --- 1951,1958 ---- /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, ! /*rcap_buf*/ (uint8_t *)rcaplong, ! /*rcap_buf_len*/ sizeof(*rcaplong), /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); start_ccb->ccb_h.ccb_bp = NULL; *************** *** 2227,2236 **** announce_buf[0] = '\0'; cam_periph_invalidate(periph); } else { dasetgeom(periph, block_size, maxsector, ! lbppbe, lalba & SRC16_LALBA); ! if ((lalba & SRC16_LBPME) && ! softc->delete_method == DA_DELETE_NONE) softc->delete_method = DA_DELETE_UNMAP; dp = &softc->params; snprintf(announce_buf, sizeof(announce_buf), --- 2231,2245 ---- announce_buf[0] = '\0'; cam_periph_invalidate(periph); } else { + /* + * We pass rcaplong into dasetgeom(), + * because it will only use it if it is + * non-NULL. + */ dasetgeom(periph, block_size, maxsector, ! rcaplong, sizeof(*rcaplong)); ! if ((lalba & SRC16_LBPME_A) ! && softc->delete_method == DA_DELETE_NONE) softc->delete_method = DA_DELETE_UNMAP; dp = &softc->params; snprintf(announce_buf, sizeof(announce_buf), *************** *** 2504,2509 **** --- 2513,2519 ---- lalba = 0; error = 0; rc16failed = 0; + rcaplong = NULL; sense_flags = SF_RETRY_UA; if (softc->flags & DA_FLAG_PACK_REMOVABLE) sense_flags |= SF_NO_PRINT; *************** *** 2521,2559 **** /* Try READ CAPACITY(16) first if we think it should work. */ if (softc->flags & DA_FLAG_CAN_RC16) { scsi_read_capacity_16(&ccb->csio, ! /*retries*/ 4, ! /*cbfcnp*/ dadone, ! /*tag_action*/ MSG_SIMPLE_Q_TAG, ! /*lba*/ 0, ! /*reladr*/ 0, ! /*pmi*/ 0, ! rcaplong, ! /*sense_len*/ SSD_FULL_SIZE, ! /*timeout*/ 60000); ccb->ccb_h.ccb_bp = NULL; error = cam_periph_runccb(ccb, daerror, ! /*cam_flags*/CAM_RETRY_SELTO, ! sense_flags, ! softc->disk->d_devstat); if (error == 0) goto rc16ok; /* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */ ! if ((ccb->ccb_h.status & CAM_STATUS_MASK) == ! CAM_REQ_INVALID) { softc->flags &= ~DA_FLAG_CAN_RC16; } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) == ! CAM_SCSI_STATUS_ERROR) && ! (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) && ! (ccb->ccb_h.status & CAM_AUTOSNS_VALID) && ! ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) && ! ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { int sense_key, error_code, asc, ascq; ! scsi_extract_sense(&ccb->csio.sense_data, ! &error_code, &sense_key, &asc, &ascq); ! if (sense_key == SSD_KEY_ILLEGAL_REQUEST) softc->flags &= ~DA_FLAG_CAN_RC16; } rc16failed = 1; --- 2531,2577 ---- /* Try READ CAPACITY(16) first if we think it should work. */ if (softc->flags & DA_FLAG_CAN_RC16) { scsi_read_capacity_16(&ccb->csio, ! /*retries*/ 4, ! /*cbfcnp*/ dadone, ! /*tag_action*/ MSG_SIMPLE_Q_TAG, ! /*lba*/ 0, ! /*reladr*/ 0, ! /*pmi*/ 0, ! /*rcap_buf*/ (uint8_t *)rcaplong, ! /*rcap_buf_len*/ sizeof(*rcaplong), ! /*sense_len*/ SSD_FULL_SIZE, ! /*timeout*/ 60000); ccb->ccb_h.ccb_bp = NULL; error = cam_periph_runccb(ccb, daerror, ! /*cam_flags*/CAM_RETRY_SELTO, ! sense_flags, softc->disk->d_devstat); if (error == 0) goto rc16ok; /* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */ ! if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { softc->flags &= ~DA_FLAG_CAN_RC16; } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) == ! CAM_SCSI_STATUS_ERROR) ! && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) ! && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) ! && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) ! && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { int sense_key, error_code, asc, ascq; ! scsi_extract_sense_len(&ccb->csio.sense_data, ! ccb->csio.sense_len - ! ccb->csio.sense_resid, ! &error_code, &sense_key, ! &asc, &ascq, /*show_errors*/1); ! /* ! * If we don't have enough sense to get the sense ! * key, or if it's illegal request, turn off ! * READ CAPACITY (16). ! */ ! if ((sense_key == -1) ! || (sense_key == SSD_KEY_ILLEGAL_REQUEST)) softc->flags &= ~DA_FLAG_CAN_RC16; } rc16failed = 1; *************** *** 2590,2596 **** /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, ! rcaplong, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); ccb->ccb_h.ccb_bp = NULL; --- 2608,2615 ---- /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, ! /*rcap_buf*/ (uint8_t *)rcaplong, ! /*rcap_buf_len*/ sizeof(*rcaplong), /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); ccb->ccb_h.ccb_bp = NULL; *************** *** 2617,2625 **** error = EINVAL; } else { dasetgeom(periph, block_len, maxsector, ! lbppbe, lalba & SRC16_LALBA); ! if ((lalba & SRC16_LBPME) && ! softc->delete_method == DA_DELETE_NONE) softc->delete_method = DA_DELETE_UNMAP; } } --- 2636,2644 ---- error = EINVAL; } else { dasetgeom(periph, block_len, maxsector, ! rcaplong, sizeof(*rcaplong)); ! if ((lalba & SRC16_LBPME) ! && softc->delete_method == DA_DELETE_NONE) softc->delete_method = DA_DELETE_UNMAP; } } *************** *** 2633,2649 **** static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector, ! u_int lbppbe, u_int lalba) { struct ccb_calc_geometry ccg; struct da_softc *softc; struct disk_params *dp; softc = (struct da_softc *)periph->softc; dp = &softc->params; dp->secsize = block_len; dp->sectors = maxsector + 1; if (lbppbe > 0) { dp->stripesize = block_len << lbppbe; dp->stripeoffset = (dp->stripesize - block_len * lalba) % --- 2652,2678 ---- static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector, ! struct scsi_read_capacity_data_long *rcaplong, size_t rcap_len) { struct ccb_calc_geometry ccg; struct da_softc *softc; struct disk_params *dp; + u_int lbppbe, lalba; softc = (struct da_softc *)periph->softc; dp = &softc->params; dp->secsize = block_len; dp->sectors = maxsector + 1; + if (rcaplong != NULL) { + lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE; + lalba = scsi_2btoul(rcaplong->lalba_lbp); + lalba &= SRC16_LALBA_A; + } else { + lbppbe = 0; + lalba = 0; + } + if (lbppbe > 0) { dp->stripesize = block_len << lbppbe; dp->stripeoffset = (dp->stripesize - block_len * lalba) % *************** *** 2688,2693 **** --- 2717,2754 ---- dp->secs_per_track = ccg.secs_per_track; dp->cylinders = ccg.cylinders; } + + /* + * If the user supplied a read capacity buffer, and if it is + * different than the previous buffer, update the data in the EDT. + * If it's the same, we don't bother. This avoids sending an + * update every time someone opens this device. + */ + if ((rcaplong != NULL) + && (bcmp(rcaplong, &softc->rcaplong, + min(sizeof(softc->rcaplong), rcap_len)) != 0)) { + struct ccb_dev_advinfo cdai; + + xpt_setup_ccb(&cdai.ccb_h, periph->path, CAM_PRIORITY_NORMAL); + cdai.ccb_h.func_code = XPT_DEV_ADVINFO; + cdai.buftype = CDAI_TYPE_RCAPLONG; + cdai.flags |= CDAI_FLAG_STORE; + cdai.bufsiz = rcap_len; + cdai.buf = (uint8_t *)rcaplong; + xpt_action((union ccb *)&cdai); + if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); + if (cdai.ccb_h.status != CAM_REQ_CMP) { + xpt_print(periph->path, "%s: failed to set read " + "capacity advinfo\n", __func__); + /* Use cam_error_print() to decode the status */ + cam_error_print((union ccb *)&cdai, CAM_ESF_CAM_STATUS, + CAM_EPF_ALL); + } else { + bcopy(rcaplong, &softc->rcaplong, + min(sizeof(softc->rcaplong), rcap_len)); + } + } } static void *** src/sys/cam/scsi/scsi_xpt.c.orig --- src/sys/cam/scsi/scsi_xpt.c *************** *** 2468,2475 **** break; case CDAI_TYPE_PHYS_PATH: if (cdai->flags & CDAI_FLAG_STORE) { ! if (device->physpath != NULL) free(device->physpath, M_CAMXPT); device->physpath_len = cdai->bufsiz; /* Clear existing buffer if zero length */ if (cdai->bufsiz == 0) --- 2468,2477 ---- break; case CDAI_TYPE_PHYS_PATH: if (cdai->flags & CDAI_FLAG_STORE) { ! if (device->physpath != NULL) { free(device->physpath, M_CAMXPT); + device->physpath = NULL; + } device->physpath_len = cdai->bufsiz; /* Clear existing buffer if zero length */ if (cdai->bufsiz == 0) *************** *** 2490,2495 **** --- 2492,2527 ---- memcpy(cdai->buf, device->physpath, amt); } break; + case CDAI_TYPE_RCAPLONG: + if (cdai->flags & CDAI_FLAG_STORE) { + if (device->rcap_buf != NULL) { + free(device->rcap_buf, M_CAMXPT); + device->rcap_buf = NULL; + } + + device->rcap_len = cdai->bufsiz; + /* Clear existing buffer if zero length */ + if (cdai->bufsiz == 0) + break; + + device->rcap_buf = malloc(cdai->bufsiz, M_CAMXPT, + M_NOWAIT); + if (device->rcap_buf == NULL) { + start_ccb->ccb_h.status = CAM_REQ_ABORTED; + return; + } + + memcpy(device->rcap_buf, cdai->buf, cdai->bufsiz); + } else { + cdai->provsiz = device->rcap_len; + if (device->rcap_len == 0) + break; + amt = device->rcap_len; + if (cdai->provsiz > cdai->bufsiz) + amt = cdai->bufsiz; + memcpy(cdai->buf, device->rcap_buf, amt); + } + break; default: return; } *** src/sys/conf/files.orig --- src/sys/conf/files *************** *** 1469,1476 **** --- 1469,1479 ---- dev/mmc/mmcsd.c optional mmcsd dev/mn/if_mn.c optional mn pci dev/mps/mps.c optional mps + dev/mps/mps_config.c optional mps + dev/mps/mps_mapping.c optional mps dev/mps/mps_pci.c optional mps pci dev/mps/mps_sas.c optional mps + dev/mps/mps_sas_lsi.c optional mps dev/mps/mps_table.c optional mps dev/mps/mps_user.c optional mps dev/mpt/mpt.c optional mpt *** src/sys/dev/mps/mpi/mpi2.h.orig --- src/sys/dev/mps/mpi/mpi2.h *************** *** 1,6 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2009 LSI Corporation. * * * Name: mpi2.h --- 1,35 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2.h *************** *** 9,15 **** * scatter/gather formats. * Creation Date: June 21, 2006 * ! * mpi2.h Version: 02.00.14 * * Version History * --------------- --- 38,44 ---- * scatter/gather formats. * Creation Date: June 21, 2006 * ! * mpi2.h Version: 02.00.18 * * Version History * --------------- *************** *** 58,63 **** --- 87,101 ---- * Added MSI-x index mask and shift for Reply Post Host * Index register. * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. + * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. + * Added alternative defines for the SGE Direction bit. + * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. * -------------------------------------------------------------------------- */ *************** *** 83,89 **** #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ ! #define MPI2_HEADER_VERSION_UNIT (0x0E) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) --- 121,127 ---- #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ ! #define MPI2_HEADER_VERSION_UNIT (0x12) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) *************** *** 476,484 **** /***************************************************************************** * * Message Functions - * 0x80 -> 0x8F reserved for private message use per product * - * *****************************************************************************/ #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ --- 514,520 ---- *************** *** 508,513 **** --- 544,552 ---- #define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ #define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */ #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */ + #define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */ + #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */ + #define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */ *************** *** 922,927 **** --- 961,969 ---- #define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) #define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) + #define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) + #define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) + /* Address Size */ #define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) *************** *** 1046,1056 **** /* Data Location Address Space */ #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) ! #define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) ! #define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) ! #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) ! /**************************************************************************** * IEEE SGE operation Macros --- 1088,1098 ---- /* Data Location Address Space */ #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) ! #define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) /* IEEE Simple Element only */ ! #define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) /* IEEE Simple Element only */ #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) ! #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) /* IEEE Simple Element only */ ! #define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (0x03) /* IEEE Chain Element only */ /**************************************************************************** * IEEE SGE operation Macros *** src/sys/dev/mps/mpi/mpi2_cnfg.h.orig --- src/sys/dev/mps/mpi/mpi2_cnfg.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_cnfg.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2009 LSI Corporation. * * * Name: mpi2_cnfg.h * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * ! * mpi2_cnfg.h Version: 02.00.13 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_cnfg.h * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * ! * mpi2_cnfg.h Version: 02.00.17 * * Version History * --------------- *************** *** 110,115 **** --- 139,169 ---- * Added Ethernet configuration pages. * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + * define. + * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. + * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) + * defines. + * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to + * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for + * the Pinout field. + * Added BoardTemperature and BoardTemperatureUnits fields + * to MPI2_CONFIG_PAGE_IO_UNIT_7. + * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define + * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. * -------------------------------------------------------------------------- */ *************** *** 193,198 **** --- 247,253 ---- #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) + #define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) /***************************************************************************** *************** *** 322,328 **** #define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) #define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) ! /* values for SGLFlags field are in the SGL section of mpi2.h */ /* Config Reply Message */ --- 377,383 ---- #define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) #define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) ! /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* Config Reply Message */ *************** *** 368,381 **** #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) #define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) #define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) #define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) #define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) #define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) #define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) ! #define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) ! #define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) /* Manufacturing Page 0 */ --- 423,441 ---- #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) + #define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) + #define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) #define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) #define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) #define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) #define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) #define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) ! #define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) ! #define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) ! #define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) ! ! /* Manufacturing Page 0 */ *************** *** 541,547 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.PageLength or NumPhys at runtime. */ #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES #define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) --- 601,607 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES #define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) *************** *** 590,612 **** U32 Pinout; /* 0x00 */ U8 Connector[16]; /* 0x04 */ U8 Location; /* 0x14 */ ! U8 Reserved1; /* 0x15 */ U16 Slot; /* 0x16 */ U32 Reserved2; /* 0x18 */ } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; /* defines for the Pinout field */ ! #define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) ! #define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) ! #define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) ! #define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) ! #define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) ! #define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) ! #define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) ! #define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) ! #define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002) ! #define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) /* defines for the Location field */ #define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) --- 650,680 ---- U32 Pinout; /* 0x00 */ U8 Connector[16]; /* 0x04 */ U8 Location; /* 0x14 */ ! U8 ReceptacleID; /* 0x15 */ U16 Slot; /* 0x16 */ U32 Reserved2; /* 0x18 */ } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; /* defines for the Pinout field */ ! #define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) ! #define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) ! ! #define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) ! #define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) ! #define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) ! #define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) ! #define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) ! #define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) ! #define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) ! #define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) ! #define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) ! #define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) ! #define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) ! #define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) ! #define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) ! #define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) ! #define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) /* defines for the Location field */ #define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) *************** *** 619,625 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check NumPhys at runtime. */ #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) --- 687,693 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) *************** *** 640,646 **** MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; ! #define MPI2_MANUFACTURING7_PAGEVERSION (0x00) /* defines for the Flags field */ #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) --- 708,714 ---- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; ! #define MPI2_MANUFACTURING7_PAGEVERSION (0x01) /* defines for the Flags field */ #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) *************** *** 717,722 **** --- 785,791 ---- /* IO Unit Page 1 Flags defines */ #define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) + #define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) #define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) *************** *** 724,738 **** #define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) #define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) - #define MPI2_IOUNITPAGE1_MULTI_PATHING (0x00000002) - #define MPI2_IOUNITPAGE1_SINGLE_PATHING (0x00000000) /* IO Unit Page 3 */ /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.PageLength at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) --- 793,805 ---- #define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) #define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) /* IO Unit Page 3 */ /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for GPIOCount at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) *************** *** 761,767 **** /* * Upper layer code (drivers, utilities, etc.) should leave this define set to ! * one and check Header.PageLength or NumDmaEngines at runtime. */ #ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES #define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) --- 828,834 ---- /* * Upper layer code (drivers, utilities, etc.) should leave this define set to ! * one and check the value returned for NumDmaEngines at runtime. */ #ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES #define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) *************** *** 826,840 **** U8 PCIeWidth; /* 0x06 */ U8 PCIeSpeed; /* 0x07 */ U32 ProcessorState; /* 0x08 */ ! U32 Reserved2; /* 0x0C */ U16 IOCTemperature; /* 0x10 */ U8 IOCTemperatureUnits; /* 0x12 */ U8 IOCSpeed; /* 0x13 */ ! U32 Reserved3; /* 0x14 */ } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; ! #define MPI2_IOUNITPAGE7_PAGEVERSION (0x00) /* defines for IO Unit Page 7 PCIeWidth field */ #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) --- 893,909 ---- U8 PCIeWidth; /* 0x06 */ U8 PCIeSpeed; /* 0x07 */ U32 ProcessorState; /* 0x08 */ ! U32 PowerManagementCapabilities; /* 0x0C */ U16 IOCTemperature; /* 0x10 */ U8 IOCTemperatureUnits; /* 0x12 */ U8 IOCSpeed; /* 0x13 */ ! U16 BoardTemperature; /* 0x14 */ ! U8 BoardTemperatureUnits; /* 0x16 */ ! U8 Reserved3; /* 0x17 */ } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; ! #define MPI2_IOUNITPAGE7_PAGEVERSION (0x02) /* defines for IO Unit Page 7 PCIeWidth field */ #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) *************** *** 855,860 **** --- 924,936 ---- #define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) #define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) + /* defines for IO Unit Page 7 PowerManagementCapabilities field */ + #define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) + #define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) + #define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) + #define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) + #define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) + /* defines for IO Unit Page 7 IOCTemperatureUnits field */ #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) *************** *** 866,871 **** --- 942,952 ---- #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) + /* defines for IO Unit Page 7 BoardTemperatureUnits field */ + #define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) + #define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) + #define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) + /**************************************************************************** *************** *** 1198,1204 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.PageLength or NumPhys at runtime. */ #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES #define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) --- 1279,1285 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES #define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) *************** *** 1272,1278 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.PageLength at runtime. */ #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) --- 1353,1359 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhysDisks at runtime. */ #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) *************** *** 1329,1334 **** --- 1410,1416 ---- #define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) #define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) #define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) + #define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) #define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) #define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) #define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) *************** *** 1451,1461 **** --- 1533,1547 ---- #define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) #define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) #define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) + #define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) #define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) /* PhysDiskAttributes defines */ + #define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) #define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) #define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) + + #define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) #define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) #define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) *************** *** 1474,1480 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.PageLength or NumPhysDiskPaths at runtime. */ #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX #define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) --- 1560,1566 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhysDiskPaths at runtime. */ #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX #define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) *************** *** 1527,1532 **** --- 1613,1619 ---- #define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) #define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) #define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) + #define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) #define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) #define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) #define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) *************** *** 1553,1558 **** --- 1640,1646 ---- #define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) #define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) + #define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) #define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) #define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) #define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) *************** *** 1636,1642 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT0_PHY_MAX #define MPI2_SAS_IOUNIT0_PHY_MAX (1) --- 1724,1730 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT0_PHY_MAX #define MPI2_SAS_IOUNIT0_PHY_MAX (1) *************** *** 1707,1713 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT1_PHY_MAX #define MPI2_SAS_IOUNIT1_PHY_MAX (1) --- 1795,1801 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT1_PHY_MAX #define MPI2_SAS_IOUNIT1_PHY_MAX (1) *************** *** 1798,1804 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * four and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT4_PHY_MAX #define MPI2_SAS_IOUNIT4_PHY_MAX (4) --- 1886,1892 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT4_PHY_MAX #define MPI2_SAS_IOUNIT4_PHY_MAX (4) *************** *** 1837,1843 **** typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { U8 ControlFlags; /* 0x00 */ ! U8 Reserved1; /* 0x01 */ U16 InactivityTimerExponent; /* 0x02 */ U8 SATAPartialTimeout; /* 0x04 */ U8 Reserved2; /* 0x05 */ --- 1925,1931 ---- typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { U8 ControlFlags; /* 0x00 */ ! U8 PortWidthModGroup; /* 0x01 */ U16 InactivityTimerExponent; /* 0x02 */ U8 SATAPartialTimeout; /* 0x04 */ U8 Reserved2; /* 0x05 */ *************** *** 1857,1862 **** --- 1945,1953 ---- #define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) #define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) + /* defines for PortWidthModeGroup field */ + #define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) + /* defines for InactivityTimerExponent field */ #define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) #define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) *************** *** 1878,1884 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT5_PHY_MAX #define MPI2_SAS_IOUNIT5_PHY_MAX (1) --- 1969,1975 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT5_PHY_MAX #define MPI2_SAS_IOUNIT5_PHY_MAX (1) *************** *** 1896,1902 **** MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; ! #define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00) --- 1987,2123 ---- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; ! #define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) ! ! ! /* SAS IO Unit Page 6 */ ! ! typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS ! { ! U8 CurrentStatus; /* 0x00 */ ! U8 CurrentModulation; /* 0x01 */ ! U8 CurrentUtilization; /* 0x02 */ ! U8 Reserved1; /* 0x03 */ ! U32 Reserved2; /* 0x04 */ ! } MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, ! MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, ! Mpi2SasIOUnit6PortWidthModGroupStatus_t, ! MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; ! ! /* defines for CurrentStatus field */ ! #define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) ! #define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) ! #define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) ! #define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) ! #define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) ! #define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) ! #define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) ! #define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) ! ! /* defines for CurrentModulation field */ ! #define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) ! #define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) ! #define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) ! #define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) ! ! /* ! * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumGroups at runtime. ! */ ! #ifndef MPI2_SAS_IOUNIT6_GROUP_MAX ! #define MPI2_SAS_IOUNIT6_GROUP_MAX (1) ! #endif ! ! typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 ! { ! MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ ! U32 Reserved1; /* 0x08 */ ! U32 Reserved2; /* 0x0C */ ! U8 NumGroups; /* 0x10 */ ! U8 Reserved3; /* 0x11 */ ! U16 Reserved4; /* 0x12 */ ! MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS ! PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ ! } MPI2_CONFIG_PAGE_SASIOUNIT_6, ! MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, ! Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; ! ! #define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) ! ! ! /* SAS IO Unit Page 7 */ ! ! typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS ! { ! U8 Flags; /* 0x00 */ ! U8 Reserved1; /* 0x01 */ ! U16 Reserved2; /* 0x02 */ ! U8 Threshold75Pct; /* 0x04 */ ! U8 Threshold50Pct; /* 0x05 */ ! U8 Threshold25Pct; /* 0x06 */ ! U8 Reserved3; /* 0x07 */ ! } MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, ! MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, ! Mpi2SasIOUnit7PortWidthModGroupSettings_t, ! MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; ! ! /* defines for Flags field */ ! #define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) ! ! ! /* ! * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumGroups at runtime. ! */ ! #ifndef MPI2_SAS_IOUNIT7_GROUP_MAX ! #define MPI2_SAS_IOUNIT7_GROUP_MAX (1) ! #endif ! ! typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 ! { ! MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ ! U8 SamplingInterval; /* 0x08 */ ! U8 WindowLength; /* 0x09 */ ! U16 Reserved1; /* 0x0A */ ! U32 Reserved2; /* 0x0C */ ! U32 Reserved3; /* 0x10 */ ! U8 NumGroups; /* 0x14 */ ! U8 Reserved4; /* 0x15 */ ! U16 Reserved5; /* 0x16 */ ! MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS ! PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ ! } MPI2_CONFIG_PAGE_SASIOUNIT_7, ! MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, ! Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; ! ! #define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) ! ! ! /* SAS IO Unit Page 8 */ ! ! typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 ! { ! MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ ! U32 Reserved1; /* 0x08 */ ! U32 PowerManagementCapabilities; /* 0x0C */ ! U32 Reserved2; /* 0x10 */ ! } MPI2_CONFIG_PAGE_SASIOUNIT_8, ! MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, ! Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; ! ! #define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) ! ! /* defines for PowerManagementCapabilities field */ ! #define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000) ! #define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800) ! #define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400) ! #define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200) ! #define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100) ! #define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010) ! #define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008) ! #define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004) ! #define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002) ! #define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001) *************** *** 2187,2193 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY2_PHY_EVENT_MAX #define MPI2_SASPHY2_PHY_EVENT_MAX (1) --- 2408,2414 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY2_PHY_EVENT_MAX #define MPI2_SASPHY2_PHY_EVENT_MAX (1) *************** *** 2280,2286 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY3_PHY_EVENT_MAX #define MPI2_SASPHY3_PHY_EVENT_MAX (1) --- 2501,2507 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY3_PHY_EVENT_MAX #define MPI2_SASPHY3_PHY_EVENT_MAX (1) *************** *** 2392,2398 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES #define MPI2_LOG_0_NUM_LOG_ENTRIES (1) --- 2613,2619 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumLogEntries at runtime. */ #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES #define MPI2_LOG_0_NUM_LOG_ENTRIES (1) *************** *** 2442,2448 **** /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check Header.ExtPageLength or NumPhys at runtime. */ #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS #define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) --- 2663,2669 ---- /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ! * one and check the value returned for NumElements at runtime. */ #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS #define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) *************** *** 2642,2646 **** --- 2863,2887 ---- #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) + /**************************************************************************** + * Extended Manufacturing Config Pages + ****************************************************************************/ + + /* + * Generic structure to use for product-specific extended manufacturing pages + * (currently Extended Manufacturing Page 40 through Extended Manufacturing + * Page 60). + */ + + typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS + { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo; /* 0x08 */ + } MPI2_CONFIG_PAGE_EXT_MAN_PS, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, + Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t; + + /* PageVersion should be provided by product-specific code */ + #endif *** src/sys/dev/mps/mpi/mpi2_hbd.h.orig --- src/sys/dev/mps/mpi/mpi2_hbd.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_hbd.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2009 LSI Corporation. * * * Name: mpi2_hbd.h * Title: MPI Host Based Discovery messages and structures * Creation Date: October 21, 2009 * ! * mpi2_hbd.h Version: 02.00.00 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2009-2011 LSI Corporation. * * * Name: mpi2_hbd.h * Title: MPI Host Based Discovery messages and structures * Creation Date: October 21, 2009 * ! * mpi2_hbd.h Version: 02.00.01 * * Version History * --------------- *************** *** 15,20 **** --- 44,51 ---- * Date Version Description * -------- -------- ------------------------------------------------------ * 10-28-09 02.00.00 Initial version. + * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from + * HBD Action request, replaced by AdditionalInfo field. * -------------------------------------------------------------------------- */ *************** *** 48,57 **** U8 Port; /* 0x25 */ U8 MaxConnections; /* 0x26 */ U8 MaxRate; /* 0x27 */ ! U8 PortGroups; /* 0x28 */ ! U8 DmaGroup; /* 0x29 */ ! U8 ControlGroup; /* 0x2A */ ! U8 Reserved6; /* 0x2B */ U16 InitialAWT; /* 0x2C */ U16 Reserved7; /* 0x2E */ U32 Reserved8; /* 0x30 */ --- 79,85 ---- U8 Port; /* 0x25 */ U8 MaxConnections; /* 0x26 */ U8 MaxRate; /* 0x27 */ ! U32 AdditionalInfo; /* 0x28 */ U16 InitialAWT; /* 0x2C */ U16 Reserved7; /* 0x2E */ U32 Reserved8; /* 0x30 */ *** src/sys/dev/mps/mpi/mpi2_history.txt.orig --- src/sys/dev/mps/mpi/mpi2_history.txt *************** *** 1,29 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_history.txt 212420 2010-09-10 15:03:56Z ken $ */ ============================== Fusion-MPT MPI 2.0 Header File Change History ============================== ! Copyright (c) 2000-2009 LSI Corporation. --------------------------------------- ! Header Set Release Version: 02.00.14 ! Header Set Release Date: 10-28-09 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- ! mpi2.h 02.00.14 02.00.13 ! mpi2_cnfg.h 02.00.13 02.00.12 ! mpi2_init.h 02.00.08 02.00.07 ! mpi2_ioc.h 02.00.13 02.00.12 ! mpi2_raid.h 02.00.04 02.00.04 ! mpi2_sas.h 02.00.03 02.00.02 ! mpi2_targ.h 02.00.03 02.00.03 ! mpi2_tool.h 02.00.04 02.00.04 mpi2_type.h 02.00.00 02.00.00 mpi2_ra.h 02.00.00 02.00.00 ! mpi2_hbd.h 02.00.00 ! mpi2_history.txt 02.00.14 02.00.13 * Date Version Description --- 1,58 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! ============================== Fusion-MPT MPI 2.0 Header File Change History ============================== ! Copyright (c) 2000-2011 LSI Corporation. --------------------------------------- ! Header Set Release Version: 02.00.18 ! Header Set Release Date: 11-10-10 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- ! mpi2.h 02.00.18 02.00.17 ! mpi2_cnfg.h 02.00.17 02.00.16 ! mpi2_init.h 02.00.11 02.00.10 ! mpi2_ioc.h 02.00.16 02.00.15 ! mpi2_raid.h 02.00.05 02.00.05 ! mpi2_sas.h 02.00.05 02.00.05 ! mpi2_targ.h 02.00.04 02.00.04 ! mpi2_tool.h 02.00.06 02.00.06 mpi2_type.h 02.00.00 02.00.00 mpi2_ra.h 02.00.00 02.00.00 ! mpi2_hbd.h 02.00.01 02.00.01 ! mpi2_history.txt 02.00.18 02.00.17 * Date Version Description *************** *** 72,77 **** --- 101,115 ---- * Added MSI-x index mask and shift for Reply Post Host * Index register. * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. + * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. + * Added alternative defines for the SGE Direction bit. + * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. * -------------------------------------------------------------------------- mpi2_cnfg.h *************** *** 171,176 **** --- 209,239 ---- * Added Ethernet configuration pages. * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + * define. + * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. + * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) + * defines. + * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to + * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for + * the Pinout field. + * Added BoardTemperature and BoardTemperatureUnits fields + * to MPI2_CONFIG_PAGE_IO_UNIT_7. + * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define + * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. * -------------------------------------------------------------------------- mpi2_init.h *************** *** 192,197 **** --- 255,263 ---- * both SCSI IO Error Reply and SCSI Task Management Reply. * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. + * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. + * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. * -------------------------------------------------------------------------- mpi2_ioc.h *************** *** 280,285 **** --- 346,357 ---- * (MPI2_FW_HEADER_PID_). * Modified values for SAS ProductID Family * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. + * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. + * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. + * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- mpi2_raid.h *************** *** 292,297 **** --- 364,370 ---- * can be sized by the build environment. * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. * -------------------------------------------------------------------------- mpi2_sas.h *************** *** 302,307 **** --- 375,382 ---- * Request. * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. + * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. * -------------------------------------------------------------------------- mpi2_targ.h *************** *** 313,318 **** --- 388,394 ---- * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. * Target Status Send Request only takes a single SGE for * response data. + * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure. * -------------------------------------------------------------------------- mpi2_tool.h *************** *** 325,330 **** --- 401,409 ---- * and reply messages. * Added MPI2_DIAG_BUF_TYPE_EXTENDED. * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. + * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer + * Post Request. * -------------------------------------------------------------------------- mpi2_type.h *************** *** 337,360 **** mpi2_hbd.h * 10-28-09 02.00.00 Initial version. * -------------------------------------------------------------------------- mpi2_history.txt Parts list history ! Filename 02.00.14 02.00.13 02.00.12 ! ---------- -------- -------- -------- ! mpi2.h 02.00.14 02.00.13 02.00.12 ! mpi2_cnfg.h 02.00.13 02.00.12 02.00.11 ! mpi2_init.h 02.00.08 02.00.07 02.00.07 ! mpi2_ioc.h 02.00.13 02.00.12 02.00.11 ! mpi2_raid.h 02.00.04 02.00.04 02.00.03 ! mpi2_sas.h 02.00.03 02.00.02 02.00.02 ! mpi2_targ.h 02.00.03 02.00.03 02.00.03 ! mpi2_tool.h 02.00.04 02.00.04 02.00.03 ! mpi2_type.h 02.00.00 02.00.00 02.00.00 ! mpi2_ra.h 02.00.00 02.00.00 02.00.00 ! mpi2_hbd.h 02.00.00 Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 ---------- -------- -------- -------- -------- -------- -------- --- 416,455 ---- mpi2_hbd.h * 10-28-09 02.00.00 Initial version. + * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from + * HBD Action request, replaced by AdditionalInfo field. * -------------------------------------------------------------------------- mpi2_history.txt Parts list history ! Filename 02.00.18 ! ---------- -------- ! mpi2.h 02.00.18 ! mpi2_cnfg.h 02.00.17 ! mpi2_init.h 02.00.11 ! mpi2_ioc.h 02.00.16 ! mpi2_raid.h 02.00.05 ! mpi2_sas.h 02.00.05 ! mpi2_targ.h 02.00.04 ! mpi2_tool.h 02.00.06 ! mpi2_type.h 02.00.00 ! mpi2_ra.h 02.00.00 ! mpi2_hbd.h 02.00.01 ! ! Filename 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 ! ---------- -------- -------- -------- -------- -------- -------- ! mpi2.h 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 ! mpi2_cnfg.h 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11 ! mpi2_init.h 02.00.10 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 ! mpi2_ioc.h 02.00.15 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11 ! mpi2_raid.h 02.00.05 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03 ! mpi2_sas.h 02.00.05 02.00.04 02.00.03 02.00.03 02.00.02 02.00.02 ! mpi2_targ.h 02.00.04 02.00.04 02.00.04 02.00.03 02.00.03 02.00.03 ! mpi2_tool.h 02.00.06 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03 ! mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 ! mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 ! mpi2_hbd.h 02.00.01 02.00.00 02.00.00 02.00.00 Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 ---------- -------- -------- -------- -------- -------- -------- *** src/sys/dev/mps/mpi/mpi2_init.h.orig --- src/sys/dev/mps/mpi/mpi2_init.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_init.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2009 LSI Corporation. * * * Name: mpi2_init.h * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * ! * mpi2_init.h Version: 02.00.08 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_init.h * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * ! * mpi2_init.h Version: 02.00.11 * * Version History * --------------- *************** *** 32,37 **** --- 61,69 ---- * both SCSI IO Error Reply and SCSI Task Management Reply. * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. + * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. + * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. * -------------------------------------------------------------------------- */ *************** *** 58,77 **** } MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; - /* TBD: I don't think this is needed for MPI2/Gen2 */ - #if 0 - typedef struct - { - U8 CDB[16]; /* 0x00 */ - U32 DataLength; /* 0x10 */ - U32 PrimaryReferenceTag; /* 0x14 */ - U16 PrimaryApplicationTag; /* 0x18 */ - U16 PrimaryApplicationTagMask; /* 0x1A */ - U32 TransferLength; /* 0x1C */ - } MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16, - Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t; - #endif - typedef union { U8 CDB32[32]; --- 90,95 ---- *************** *** 112,118 **** --- 130,142 ---- U8 LUN[8]; /* 0x34 */ U32 Control; /* 0x3C */ MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + + #ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ + MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; + #endif + MPI2_SGE_IO_UNION SGL; /* 0x60 */ + } MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; *************** *** 146,151 **** --- 170,178 ---- #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) + /* number of SGLOffset fields */ + #define MPI2_SCSIIO_NUM_SGLOFFSETS (4) + /* SCSI IO IoFlags bits */ /* Large CDB Address Space */ *** src/sys/dev/mps/mpi/mpi2_ioc.h.orig --- src/sys/dev/mps/mpi/mpi2_ioc.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_ioc.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2009 LSI Corporation. * * * Name: mpi2_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * ! * mpi2_ioc.h Version: 02.00.13 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * ! * mpi2_ioc.h Version: 02.00.16 * * Version History * --------------- *************** *** 99,104 **** --- 128,139 ---- * (MPI2_FW_HEADER_PID_). * Modified values for SAS ProductID Family * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. + * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. + * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. + * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ *************** *** 454,460 **** #define MPI2_EVENT_STATE_CHANGE (0x0002) #define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) #define MPI2_EVENT_EVENT_CHANGE (0x000A) ! #define MPI2_EVENT_TASK_SET_FULL (0x000E) #define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) #define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) #define MPI2_EVENT_SAS_DISCOVERY (0x0016) --- 489,495 ---- #define MPI2_EVENT_STATE_CHANGE (0x0002) #define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) #define MPI2_EVENT_EVENT_CHANGE (0x000A) ! #define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */ #define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) #define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) #define MPI2_EVENT_SAS_DISCOVERY (0x0016) *************** *** 470,475 **** --- 505,511 ---- #define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) #define MPI2_EVENT_GPIO_INTERRUPT (0x0023) #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) + #define MPI2_EVENT_SAS_QUIESCE (0x0025) /* Log Entry Added Event data */ *************** *** 515,520 **** --- 551,557 ---- MPI2_POINTER pMpi2EventDataHardResetReceived_t; /* Task Set Full Event data */ + /* this event is obsolete */ typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL { *************** *** 829,834 **** --- 866,872 ---- #define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) #define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) #define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) + #define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) #define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) #define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) #define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) *************** *** 896,901 **** --- 934,956 ---- /* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */ + /* SAS Quiesce Event data */ + + typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE + { + U8 ReasonCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + } MPI2_EVENT_DATA_SAS_QUIESCE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, + Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; + + /* SAS Quiesce Event data ReasonCode values */ + #define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) + #define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) + + /* Host Based Discovery Phy Event data */ typedef struct _MPI2_EVENT_HBD_PHY_SAS *************** *** 1009,1015 **** --- 1064,1072 ---- #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) + #define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + #define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) /* FWDownload TransactionContext Element */ typedef struct _MPI2_FW_DOWNLOAD_TCSGE *************** *** 1186,1192 **** #define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI2_FW_HEADER_PID_PROD_A (0x0000) - #define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) #define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) --- 1243,1248 ---- *************** *** 1410,1414 **** --- 1466,1566 ---- #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) + /**************************************************************************** + * PowerManagementControl message + ****************************************************************************/ + + /* PowerManagementControl Request message */ + typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST + { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Parameter1; /* 0x0C */ + U8 Parameter2; /* 0x0D */ + U8 Parameter3; /* 0x0E */ + U8 Parameter4; /* 0x0F */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ + } MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, + Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; + + /* defines for the Feature field */ + #define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) + #define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) + #define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) + #define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) + #define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) + #define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) + + /* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ + /* Parameter1 contains a PHY number */ + /* Parameter2 indicates power condition action using these defines */ + #define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) + #define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) + #define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) + /* Parameter3 and Parameter4 are reserved */ + + /* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */ + /* Parameter1 contains SAS port width modulation group number */ + /* Parameter2 indicates IOC action using these defines */ + #define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) + #define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) + #define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) + /* Parameter3 indicates desired modulation level using these defines */ + #define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) + #define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) + #define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) + #define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) + /* Parameter4 is reserved */ + + /* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ + /* Parameter1 indicates desired PCIe link speed using these defines */ + #define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) + #define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) + #define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) + /* Parameter2 indicates desired PCIe link width using these defines */ + #define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) + #define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) + #define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) + #define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) + /* Parameter3 and Parameter4 are reserved */ + + /* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ + /* Parameter1 indicates desired IOC hardware clock speed using these defines */ + #define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) + #define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) + #define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) + #define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) + /* Parameter2, Parameter3, and Parameter4 are reserved */ + + + /* PowerManagementControl Reply message */ + typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY + { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + } MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, + Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; + + #endif *** src/sys/dev/mps/mpi/mpi2_ra.h.orig --- src/sys/dev/mps/mpi/mpi2_ra.h *************** *** 1,6 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_ra.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2009 LSI Corporation. * * * Name: mpi2_ra.h --- 1,35 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2011 LSI Corporation. * * * Name: mpi2_ra.h *** src/sys/dev/mps/mpi/mpi2_raid.h.orig --- src/sys/dev/mps/mpi/mpi2_raid.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_raid.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi2_raid.h * Title: MPI Integrated RAID messages and structures * Creation Date: April 26, 2007 * ! * mpi2_raid.h Version: 02.00.04 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_raid.h * Title: MPI Integrated RAID messages and structures * Creation Date: April 26, 2007 * ! * mpi2_raid.h Version: 02.00.05 * * Version History * --------------- *************** *** 23,28 **** --- 52,58 ---- * can be sized by the build environment. * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. * -------------------------------------------------------------------------- */ *************** *** 261,266 **** --- 291,297 ---- #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) #define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) #define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) + #define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) /* RAID Action Reply ActionData union */ *** src/sys/dev/mps/mpi/mpi2_sas.h.orig --- src/sys/dev/mps/mpi/mpi2_sas.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_sas.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi2_sas.h * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: February 9, 2007 * ! * mpi2.h Version: 02.00.03 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_sas.h * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: February 9, 2007 * ! * mpi2_sas.h Version: 02.00.05 * * Version History * --------------- *************** *** 21,26 **** --- 50,57 ---- * Request. * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. + * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. * -------------------------------------------------------------------------- */ *************** *** 111,117 **** /* values for PassthroughFlags field */ #define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) ! /* values for SGLFlags field are in the SGL section of mpi2.h */ /* SMP Passthrough Reply Message */ --- 142,148 ---- /* values for PassthroughFlags field */ #define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) ! /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* SMP Passthrough Reply Message */ *************** *** 163,169 **** U32 Reserved4; /* 0x14 */ U32 DataLength; /* 0x18 */ U8 CommandFIS[20]; /* 0x1C */ ! MPI2_SGE_IO_UNION SGL; /* 0x20 */ } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; --- 194,200 ---- U32 Reserved4; /* 0x14 */ U32 DataLength; /* 0x18 */ U8 CommandFIS[20]; /* 0x1C */ ! MPI2_SGE_IO_UNION SGL; /* 0x30 */ } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; *************** *** 175,181 **** #define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) #define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) ! /* values for SGLFlags field are in the SGL section of mpi2.h */ /* SATA Passthrough Reply Message */ --- 206,212 ---- #define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) #define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) ! /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* SATA Passthrough Reply Message */ *************** *** 246,251 **** --- 277,284 ---- #define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) #define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) #define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) + #define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) + #define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) #define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) /* values for the PrimFlags field */ *** src/sys/dev/mps/mpi/mpi2_targ.h.orig --- src/sys/dev/mps/mpi/mpi2_targ.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_targ.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi2_targ.h * Title: MPI Target mode messages and structures * Creation Date: September 8, 2006 * ! * mpi2_targ.h Version: 02.00.03 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_targ.h * Title: MPI Target mode messages and structures * Creation Date: September 8, 2006 * ! * mpi2_targ.h Version: 02.00.04 * * Version History * --------------- *************** *** 22,27 **** --- 51,57 ---- * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. * Target Status Send Request only takes a single SGE for * response data. + * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure. * -------------------------------------------------------------------------- */ *************** *** 343,348 **** --- 373,379 ---- typedef struct _MPI2_TARGET_SSP_RSP_IU { U32 Reserved0[6]; /* reserved for SSP header */ /* 0x00 */ + /* start of RESPONSE information unit */ U32 Reserved1; /* 0x18 */ U32 Reserved2; /* 0x1C */ *************** *** 352,357 **** --- 383,390 ---- U32 Reserved4; /* 0x24 */ U32 SenseDataLength; /* 0x28 */ U32 ResponseDataLength; /* 0x2C */ + + /* start of Response or Sense Data (size may vary dynamically) */ U8 ResponseSenseData[4]; /* 0x30 */ } MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU, Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t; *** src/sys/dev/mps/mpi/mpi2_tool.h.orig --- src/sys/dev/mps/mpi/mpi2_tool.h *************** *** 1,13 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_tool.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2009 LSI Corporation. * * * Name: mpi2_tool.h * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * ! * mpi2_tool.h Version: 02.00.04 * * Version History * --------------- --- 1,42 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_tool.h * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * ! * mpi2_tool.h Version: 02.00.06 * * Version History * --------------- *************** *** 23,28 **** --- 52,60 ---- * and reply messages. * Added MPI2_DIAG_BUF_TYPE_EXTENDED. * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. + * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer + * Post Request. * -------------------------------------------------------------------------- */ *************** *** 38,43 **** --- 70,76 ---- /* defines for the Tools */ #define MPI2_TOOLBOX_CLEAN_TOOL (0x00) #define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) + #define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) #define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) #define MPI2_TOOLBOX_BEACON_TOOL (0x05) #define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) *************** *** 121,126 **** --- 154,199 ---- /**************************************************************************** + * Toolbox Diagnostic Data Upload request + ****************************************************************************/ + + typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST + { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 Flags; /* 0x10 */ + U32 DataLength; /* 0x14 */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ + } MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + Mpi2ToolboxDiagDataUploadRequest_t, + MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; + + /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + + typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER + { + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ + } MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, + Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; + + + /**************************************************************************** * Toolbox ISTWI Read Write Tool ****************************************************************************/ *************** *** 164,170 **** #define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) #define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) ! /* values for SGLFlags field are in the SGL section of mpi2.h */ /* Toolbox ISTWI Read Write Tool reply message */ --- 237,243 ---- #define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) #define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) ! /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* Toolbox ISTWI Read Write Tool reply message */ *************** *** 251,257 **** Mpi2ToolboxDiagnosticCliRequest_t, MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; ! /* values for SGLFlags field are in the SGL section of mpi2.h */ /* Toolbox Diagnostic CLI Tool reply message */ --- 324,330 ---- Mpi2ToolboxDiagnosticCliRequest_t, MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; ! /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* Toolbox Diagnostic CLI Tool reply message */ *************** *** 319,324 **** --- 392,401 ---- /* count of the number of buffer types */ #define MPI2_DIAG_BUF_TYPE_COUNT (0x03) + /* values for the Flags field */ + #define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) + #define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) + /**************************************************************************** * Diagnostic Buffer Post reply *** src/sys/dev/mps/mpi/mpi2_type.h.orig --- src/sys/dev/mps/mpi/mpi2_type.h *************** *** 1,6 **** ! /* $FreeBSD: head/sys/dev/mps/mpi/mpi2_type.h 212420 2010-09-10 15:03:56Z ken $ */ /* ! * Copyright (c) 2000-2007 LSI Corporation. * * * Name: mpi2_type.h --- 1,35 ---- ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ ! */ ! /* ! * Copyright (c) 2000-2011 LSI Corporation. * * * Name: mpi2_type.h *** src/sys/dev/mps/mps.c.orig --- src/sys/dev/mps/mps.c *************** *** 22,34 **** * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include ! __FBSDID("$FreeBSD: head/sys/dev/mps/mps.c 219036 2011-02-25 17:30:25Z ken $"); /* Communications core for LSI MPT2 */ #include #include #include --- 22,65 ---- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + */ + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ */ #include ! __FBSDID("$FreeBSD$"); /* Communications core for LSI MPT2 */ + /* TODO Move headers to mpsvar */ #include #include #include *************** *** 43,71 **** #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void mps_startup(void *arg); - static void mps_startup_complete(struct mps_softc *sc, struct mps_command *cm); static int mps_send_iocinit(struct mps_softc *sc); static int mps_attach_log(struct mps_softc *sc); static __inline void mps_complete_command(struct mps_command *cm); ! static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *reply); static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm); static void mps_periodic(void *); SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters"); --- 74,117 ---- #include #include #include + #include + #include #include + #include #include #include #include + #include + #include #include #include #include + #include #include + #include + #include + #include #include #include + static int mps_diag_reset(struct mps_softc *sc); + static int mps_init_queues(struct mps_softc *sc); + static int mps_message_unit_reset(struct mps_softc *sc); + static int mps_transition_operational(struct mps_softc *sc); static void mps_startup(void *arg); static int mps_send_iocinit(struct mps_softc *sc); static int mps_attach_log(struct mps_softc *sc); static __inline void mps_complete_command(struct mps_command *cm); ! static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, ! MPI2_EVENT_NOTIFICATION_REPLY *reply); static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm); static void mps_periodic(void *); + static int mps_reregister_events(struct mps_softc *sc); + static void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm); SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters"); *************** *** 78,84 **** static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; static int ! mps_hard_reset(struct mps_softc *sc) { uint32_t reg; int i, error, tries = 0; --- 124,130 ---- static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; static int ! mps_diag_reset(struct mps_softc *sc) { uint32_t reg; int i, error, tries = 0; *************** *** 129,135 **** } static int ! mps_soft_reset(struct mps_softc *sc) { mps_dprint(sc, MPS_TRACE, "%s\n", __func__); --- 175,181 ---- } static int ! mps_message_unit_reset(struct mps_softc *sc) { mps_dprint(sc, MPS_TRACE, "%s\n", __func__); *************** *** 160,166 **** * resetting it. */ if (reg & MPI2_DOORBELL_USED) { ! mps_hard_reset(sc); DELAY(50000); continue; } --- 206,212 ---- * resetting it. */ if (reg & MPI2_DOORBELL_USED) { ! mps_diag_reset(sc); DELAY(50000); continue; } *************** *** 181,190 **** } else if (state == MPI2_IOC_STATE_FAULT) { mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n", state & MPI2_DOORBELL_FAULT_CODE_MASK); ! mps_hard_reset(sc); } else if (state == MPI2_IOC_STATE_OPERATIONAL) { /* Need to take ownership */ ! mps_soft_reset(sc); } else if (state == MPI2_IOC_STATE_RESET) { /* Wait a bit, IOC might be in transition */ mps_dprint(sc, MPS_FAULT, --- 227,236 ---- } else if (state == MPI2_IOC_STATE_FAULT) { mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n", state & MPI2_DOORBELL_FAULT_CODE_MASK); ! mps_diag_reset(sc); } else if (state == MPI2_IOC_STATE_OPERATIONAL) { /* Need to take ownership */ ! mps_message_unit_reset(sc); } else if (state == MPI2_IOC_STATE_RESET) { /* Wait a bit, IOC might be in transition */ mps_dprint(sc, MPS_FAULT, *************** *** 220,233 **** state = reg & MPI2_IOC_STATE_MASK; if (state != MPI2_IOC_STATE_READY) { ! if ((error = mps_transition_ready(sc)) != 0) return (error); } error = mps_send_iocinit(sc); return (error); } /* Wait for the chip to ACK a word that we've put into its FIFO */ static int mps_wait_db_ack(struct mps_softc *sc) --- 266,373 ---- state = reg & MPI2_IOC_STATE_MASK; if (state != MPI2_IOC_STATE_READY) { ! if ((error = mps_transition_ready(sc)) != 0) { ! mps_dprint(sc, MPS_FAULT, ! "%s failed to transition ready\n", __func__); return (error); + } } error = mps_send_iocinit(sc); return (error); } + /* + * XXX Some of this should probably move to mps.c + * + * The terms diag reset and hard reset are used interchangeably in the MPI + * docs to mean resetting the controller chip. In this code diag reset + * cleans everything up, and the hard reset function just sends the reset + * sequence to the chip. This should probably be refactored so that every + * subsystem gets a reset notification of some sort, and can clean up + * appropriately. + */ + int + mps_reinit(struct mps_softc *sc) + { + int error; + uint32_t db; + + mps_printf(sc, "%s sc %p\n", __func__, sc); + + mtx_assert(&sc->mps_mtx, MA_OWNED); + + if (sc->mps_flags & MPS_FLAGS_DIAGRESET) { + mps_printf(sc, "%s reset already in progress\n", __func__); + return 0; + } + + /* make sure the completion callbacks can recognize they're getting + * a NULL cm_reply due to a reset. + */ + sc->mps_flags |= MPS_FLAGS_DIAGRESET; + + mps_printf(sc, "%s mask interrupts\n", __func__); + mps_mask_intr(sc); + + error = mps_diag_reset(sc); + if (error != 0) { + panic("%s hard reset failed with error %d\n", + __func__, error); + } + + /* Restore the PCI state, including the MSI-X registers */ + mps_pci_restore(sc); + + /* Give the I/O subsystem special priority to get itself prepared */ + mpssas_handle_reinit(sc); + + /* reinitialize queues after the reset */ + bzero(sc->free_queue, sc->fqdepth * 4); + mps_init_queues(sc); + + /* get the chip out of the reset state */ + error = mps_transition_operational(sc); + if (error != 0) + panic("%s transition operational failed with error %d\n", + __func__, error); + + /* Reinitialize the reply queue. This is delicate because this + * function is typically invoked by task mgmt completion callbacks, + * which are called by the interrupt thread. We need to make sure + * the interrupt handler loop will exit when we return to it, and + * that it will recognize the indexes we've changed. + */ + sc->replypostindex = 0; + mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); + mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex); + + db = mps_regread(sc, MPI2_DOORBELL_OFFSET); + mps_printf(sc, "%s doorbell 0x%08x\n", __func__, db); + + mps_printf(sc, "%s unmask interrupts post %u free %u\n", __func__, + sc->replypostindex, sc->replyfreeindex); + + mps_unmask_intr(sc); + + mps_printf(sc, "%s restarting post %u free %u\n", __func__, + sc->replypostindex, sc->replyfreeindex); + + /* restart will reload the event masks clobbered by the reset, and + * then enable the port. + */ + mps_reregister_events(sc); + + /* the end of discovery will release the simq, so we're done. */ + mps_printf(sc, "%s finished sc %p post %u free %u\n", + __func__, sc, + sc->replypostindex, sc->replyfreeindex); + + sc->mps_flags &= ~MPS_FLAGS_DIAGRESET; + + return 0; + } + /* Wait for the chip to ACK a word that we've put into its FIFO */ static int mps_wait_db_ack(struct mps_softc *sc) *************** *** 382,432 **** return (0); } ! void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm) { ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE) mtx_assert(&sc->mps_mtx, MA_OWNED); ! if ((cm->cm_desc.Default.SMID < 1) ! || (cm->cm_desc.Default.SMID >= sc->num_reqs)) { ! mps_printf(sc, "%s: invalid SMID %d, desc %#x %#x\n", ! __func__, cm->cm_desc.Default.SMID, ! cm->cm_desc.Words.High, cm->cm_desc.Words.Low); ! } mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, cm->cm_desc.Words.Low); mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, cm->cm_desc.Words.High); } - int - mps_request_polled(struct mps_softc *sc, struct mps_command *cm) - { - int error, timeout = 0; - - error = 0; - - cm->cm_flags |= MPS_CM_FLAGS_POLLED; - cm->cm_complete = NULL; - mps_map_command(sc, cm); - - while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { - mps_intr(sc); - DELAY(50 * 1000); - if (timeout++ > 1000) { - mps_dprint(sc, MPS_FAULT, "polling failed\n"); - error = ETIMEDOUT; - break; - } - } - - return (error); - } - /* * Just the FACTS, ma'am. */ --- 522,546 ---- return (0); } ! static void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm) { ! mps_dprint(sc, MPS_TRACE, "%s SMID %u cm %p ccb %p\n", __func__, ! cm->cm_desc.Default.SMID, cm, cm->cm_ccb); if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE) mtx_assert(&sc->mps_mtx, MA_OWNED); ! if (++sc->io_cmds_active > sc->io_cmds_highwater) ! sc->io_cmds_highwater++; ! mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, cm->cm_desc.Words.Low); mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, cm->cm_desc.Words.High); } /* * Just the FACTS, ma'am. */ *************** *** 469,477 **** cm->cm_data = NULL; error = mps_request_polled(sc, cm); reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply; ! if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) error = ENXIO; bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY)); mps_free_command(sc, cm); return (error); --- 583,601 ---- cm->cm_data = NULL; error = mps_request_polled(sc, cm); reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply; ! if (reply == NULL) { ! mps_printf(sc, "%s NULL reply\n", __func__); ! goto done; ! } ! if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { ! mps_printf(sc, ! "%s error %d iocstatus 0x%x iocloginfo 0x%x type 0x%x\n", ! __func__, error, reply->IOCStatus, reply->IOCLogInfo, ! reply->PortType); error = ENXIO; + } bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY)); + done: mps_free_command(sc, cm); return (error); *************** *** 522,556 **** return (error); } - static int - mps_send_portenable(struct mps_softc *sc) - { - MPI2_PORT_ENABLE_REQUEST *request; - struct mps_command *cm; - - mps_dprint(sc, MPS_TRACE, "%s\n", __func__); - - if ((cm = mps_alloc_command(sc)) == NULL) - return (EBUSY); - request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; - request->Function = MPI2_FUNCTION_PORT_ENABLE; - request->MsgFlags = 0; - request->VP_ID = 0; - cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - cm->cm_complete = mps_startup_complete; - - mps_enqueue_request(sc, cm); - return (0); - } - - static int - mps_send_mur(struct mps_softc *sc) - { - - /* Placeholder */ - return (0); - } - void mps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { --- 646,651 ---- *************** *** 685,691 **** bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, mps_memaddr_cb, &sc->req_busaddr, 0); ! rsize = sc->facts->IOCRequestFrameSize * MPS_CHAIN_FRAMES * 4; if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ --- 780,786 ---- bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, mps_memaddr_cb, &sc->req_busaddr, 0); ! rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4; if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ *************** *** 733,741 **** bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, mps_memaddr_cb, &sc->sense_busaddr, 0); ! sc->chains = malloc(sizeof(struct mps_chain) * MPS_CHAIN_FRAMES, ! M_MPT2, M_WAITOK | M_ZERO); ! for (i = 0; i < MPS_CHAIN_FRAMES; i++) { chain = &sc->chains[i]; chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + i * sc->facts->IOCRequestFrameSize * 4); --- 828,836 ---- bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, mps_memaddr_cb, &sc->sense_busaddr, 0); ! sc->chains = malloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2, ! M_WAITOK | M_ZERO); ! for (i = 0; i < sc->max_chains; i++) { chain = &sc->chains[i]; chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + i * sc->facts->IOCRequestFrameSize * 4); *************** *** 759,765 **** busdma_lock_mutex, /* lockfunc */ &sc->mps_mtx, /* lockarg */ &sc->buffer_dmat)) { ! device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n"); return (ENOMEM); } --- 854,860 ---- busdma_lock_mutex, /* lockfunc */ &sc->mps_mtx, /* lockarg */ &sc->buffer_dmat)) { ! device_printf(sc->mps_dev, "Cannot allocate buffer DMA tag\n"); return (ENOMEM); } *************** *** 780,791 **** cm->cm_desc.Default.SMID = i; cm->cm_sc = sc; TAILQ_INIT(&cm->cm_chain_list); ! callout_init(&cm->cm_callout, 1 /*MPSAFE*/); /* XXX Is a failure here a critical problem? */ if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) ! mps_free_command(sc, cm); else { sc->num_reqs = i; break; } --- 875,890 ---- cm->cm_desc.Default.SMID = i; cm->cm_sc = sc; TAILQ_INIT(&cm->cm_chain_list); ! callout_init_mtx(&cm->cm_callout, &sc->mps_mtx, 0); /* XXX Is a failure here a critical problem? */ if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) ! if (i <= sc->facts->HighPriorityCredit) ! mps_free_high_priority_command(sc, cm); ! else ! mps_free_command(sc, cm); else { + panic("failed to allocate command %d\n", i); sc->num_reqs = i; break; } *************** *** 819,846 **** return (0); } ! int ! mps_attach(struct mps_softc *sc) { ! int i, error; ! char tmpstr[80], tmpstr2[80]; /* ! * Grab any tunable-set debug level so that tracing works as early ! * as possible. */ ! snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.debug_level", device_get_unit(sc->mps_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug); ! snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.allow_multiple_tm_cmds", device_get_unit(sc->mps_dev)); ! TUNABLE_INT_FETCH(tmpstr, &sc->allow_multiple_tm_cmds); ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF); ! callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0); ! TAILQ_INIT(&sc->event_list); /* * Setup the sysctl variable so the user can change the debug level --- 918,970 ---- return (0); } ! /* Get the driver parameter tunables. Lowest priority are the driver defaults. ! * Next are the global settings, if they exist. Highest are the per-unit ! * settings, if they exist. ! */ ! static void ! mps_get_tunables(struct mps_softc *sc) { ! char tmpstr[80]; ! ! /* XXX default to some debugging for now */ ! sc->mps_debug = MPS_FAULT; ! sc->disable_msix = 0; ! sc->disable_msi = 0; ! sc->max_chains = MPS_CHAIN_FRAMES; /* ! * Grab the global variables. */ ! TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug); ! TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix); ! TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi); ! TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains); ! ! /* Grab the unit-instance variables */ ! snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level", device_get_unit(sc->mps_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug); ! ! snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msix", ! device_get_unit(sc->mps_dev)); ! TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix); ! ! snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msi", device_get_unit(sc->mps_dev)); ! TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); ! snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains", ! device_get_unit(sc->mps_dev)); ! TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); ! } ! static void ! mps_setup_sysctl(struct mps_softc *sc) ! { ! struct sysctl_ctx_list *sysctl_ctx = NULL; ! struct sysctl_oid *sysctl_tree = NULL; ! char tmpstr[80], tmpstr2[80]; /* * Setup the sysctl variable so the user can change the debug level *************** *** 850,893 **** device_get_unit(sc->mps_dev)); snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mps_dev)); ! sysctl_ctx_init(&sc->sysctl_ctx); ! sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, ! SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, CTLFLAG_RD, ! 0, tmpstr); ! if (sc->sysctl_tree == NULL) ! return (ENOMEM); ! SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0, "mps debug level"); ! SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), ! OID_AUTO, "allow_multiple_tm_cmds", CTLFLAG_RW, ! &sc->allow_multiple_tm_cmds, 0, ! "allow multiple simultaneous task management cmds"); ! SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "io_cmds_active", CTLFLAG_RD, &sc->io_cmds_active, 0, "number of currently active commands"); ! SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, &sc->io_cmds_highwater, 0, "maximum active commands seen"); ! SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "chain_free", CTLFLAG_RD, &sc->chain_free, 0, "number of free chain elements"); ! SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); ! SYSCTL_ADD_UQUAD(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, &sc->chain_alloc_fail, "chain allocation failures"); ! if ((error = mps_transition_ready(sc)) != 0) return (error); sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2, M_ZERO|M_NOWAIT); --- 974,1058 ---- device_get_unit(sc->mps_dev)); snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mps_dev)); ! sysctl_ctx = device_get_sysctl_ctx(sc->mps_dev); ! if (sysctl_ctx != NULL) ! sysctl_tree = device_get_sysctl_tree(sc->mps_dev); ! ! if (sysctl_tree == NULL) { ! sysctl_ctx_init(&sc->sysctl_ctx); ! sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, ! SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, ! CTLFLAG_RD, 0, tmpstr); ! if (sc->sysctl_tree == NULL) ! return; ! sysctl_ctx = &sc->sysctl_ctx; ! sysctl_tree = sc->sysctl_tree; ! } ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0, "mps debug level"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), ! OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0, ! "Disable the use of MSI-X interrupts"); ! ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), ! OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, ! "Disable the use of MSI interrupts"); ! ! SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), ! OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version, ! strlen(sc->fw_version), "firmware version"); ! ! SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), ! OID_AUTO, "driver_version", CTLFLAG_RW, MPS_DRIVER_VERSION, ! strlen(MPS_DRIVER_VERSION), "driver version"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "io_cmds_active", CTLFLAG_RD, &sc->io_cmds_active, 0, "number of currently active commands"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, &sc->io_cmds_highwater, 0, "maximum active commands seen"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "chain_free", CTLFLAG_RD, &sc->chain_free, 0, "number of free chain elements"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); ! SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), ! OID_AUTO, "max_chains", CTLFLAG_RD, ! &sc->max_chains, 0,"maximum chain frames that will be allocated"); ! ! #if __FreeBSD_version >= 900030 ! SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, &sc->chain_alloc_fail, "chain allocation failures"); + #endif //FreeBSD_version >= 900030 + } + + int + mps_attach(struct mps_softc *sc) + { + int i, error; + + mps_get_tunables(sc); ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! ! mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF); ! callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0); ! TAILQ_INIT(&sc->event_list); ! ! if ((error = mps_transition_ready(sc)) != 0) { ! mps_printf(sc, "%s failed to transition ready\n", __func__); return (error); + } sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2, M_ZERO|M_NOWAIT); *************** *** 896,906 **** mps_print_iocfacts(sc, sc->facts); ! mps_printf(sc, "Firmware: %02d.%02d.%02d.%02d\n", sc->facts->FWVersion.Struct.Major, sc->facts->FWVersion.Struct.Minor, sc->facts->FWVersion.Struct.Unit, sc->facts->FWVersion.Struct.Dev); mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" --- 1061,1075 ---- mps_print_iocfacts(sc, sc->facts); ! snprintf(sc->fw_version, sizeof(sc->fw_version), ! "%02d.%02d.%02d.%02d", sc->facts->FWVersion.Struct.Major, sc->facts->FWVersion.Struct.Minor, sc->facts->FWVersion.Struct.Unit, sc->facts->FWVersion.Struct.Dev); + + mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version, + MPS_DRIVER_VERSION); mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" *************** *** 914,947 **** */ if ((sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { ! mps_hard_reset(sc); if ((error = mps_transition_ready(sc)) != 0) return (error); } /* * Size the queues. Since the reply queues always need one free entry, * we'll just deduct one reply message here. */ sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit); sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES, sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; - mps_dprint(sc, MPS_INFO, "num_reqs %d, num_replies %d\n", sc->num_reqs, - sc->num_replies); TAILQ_INIT(&sc->req_list); TAILQ_INIT(&sc->chain_list); TAILQ_INIT(&sc->tm_list); - TAILQ_INIT(&sc->io_list); if (((error = mps_alloc_queues(sc)) != 0) || ((error = mps_alloc_replies(sc)) != 0) || ((error = mps_alloc_requests(sc)) != 0)) { mps_free(sc); return (error); } if (((error = mps_init_queues(sc)) != 0) || ((error = mps_transition_operational(sc)) != 0)) { mps_free(sc); return (error); } --- 1083,1148 ---- */ if ((sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { ! mps_diag_reset(sc); if ((error = mps_transition_ready(sc)) != 0) return (error); } /* + * Set flag if IR Firmware is loaded. + */ + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) + sc->ir_firmware = 1; + + /* + * Check if controller supports FW diag buffers and set flag to enable + * each type. + */ + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled = + TRUE; + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].enabled = + TRUE; + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].enabled = + TRUE; + + /* + * Set flag if EEDP is supported and if TLR is supported. + */ + if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) + sc->eedp_enabled = TRUE; + if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) + sc->control_TLR = TRUE; + + /* * Size the queues. Since the reply queues always need one free entry, * we'll just deduct one reply message here. */ sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit); sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES, sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; TAILQ_INIT(&sc->req_list); + TAILQ_INIT(&sc->high_priority_req_list); TAILQ_INIT(&sc->chain_list); TAILQ_INIT(&sc->tm_list); if (((error = mps_alloc_queues(sc)) != 0) || ((error = mps_alloc_replies(sc)) != 0) || ((error = mps_alloc_requests(sc)) != 0)) { + mps_printf(sc, "%s failed to alloc\n", __func__); mps_free(sc); return (error); } if (((error = mps_init_queues(sc)) != 0) || ((error = mps_transition_operational(sc)) != 0)) { + mps_printf(sc, "%s failed to transition operational\n", __func__); mps_free(sc); return (error); } *************** *** 964,969 **** --- 1165,1172 ---- sc->facts->NumberOfPorts, M_MPT2, M_ZERO|M_WAITOK); for (i = 0; i < sc->facts->NumberOfPorts; i++) { if ((error = mps_get_portfacts(sc, &sc->pfacts[i], i)) != 0) { + mps_printf(sc, "%s failed to get portfacts for port %d\n", + __func__, i); mps_free(sc); return (error); } *************** *** 982,991 **** --- 1185,1201 ---- } if ((error = mps_pci_setup_interrupts(sc)) != 0) { + mps_printf(sc, "%s failed to setup interrupts\n", __func__); mps_free(sc); return (error); } + /* + * The static page function currently read is ioc page8. Others can be + * added in future. + */ + mps_base_static_config_pages(sc); + /* Start the periodic watchdog check on the IOC Doorbell */ mps_periodic(sc); *************** *** 1001,1011 **** --- 1211,1234 ---- error = EINVAL; } + /* + * Allow IR to shutdown gracefully when shutdown occurs. + */ + sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final, + mpssas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT); + + if (sc->shutdown_eh == NULL) + mps_dprint(sc, MPS_FAULT, "shutdown event registration " + "failed\n"); + + mps_setup_sysctl(sc); + sc->mps_flags |= MPS_FLAGS_ATTACH_DONE; return (error); } + /* Run through any late-start handlers. */ static void mps_startup(void *arg) { *************** *** 1015,1021 **** mps_lock(sc); mps_unmask_intr(sc); ! mps_send_portenable(sc); mps_unlock(sc); } --- 1238,1246 ---- mps_lock(sc); mps_unmask_intr(sc); ! /* initialize device mapping tables */ ! mps_mapping_initialize(sc); ! mpssas_startup(sc); mps_unlock(sc); } *************** *** 1033,1068 **** db = mps_regread(sc, MPI2_DOORBELL_OFFSET); if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db); ! /* XXX Need to broaden this to re-initialize the chip */ ! mps_hard_reset(sc); ! db = mps_regread(sc, MPI2_DOORBELL_OFFSET); ! if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { ! device_printf(sc->mps_dev, "Second IOC Fault 0x%08x, " ! "Giving up!\n", db); ! return; ! } } callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc); } static void - mps_startup_complete(struct mps_softc *sc, struct mps_command *cm) - { - MPI2_PORT_ENABLE_REPLY *reply; - - mps_dprint(sc, MPS_TRACE, "%s\n", __func__); - - reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; - if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) - mps_dprint(sc, MPS_FAULT, "Portenable failed\n"); - - mps_free_command(sc, cm); - config_intrhook_disestablish(&sc->mps_ich); - - } - - static void mps_log_evt_handler(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *event) { --- 1258,1271 ---- db = mps_regread(sc, MPI2_DOORBELL_OFFSET); if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db); ! ! mps_reinit(sc); } callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc); } static void mps_log_evt_handler(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *event) { *************** *** 1134,1140 **** /* Put the IOC back in the READY state. */ mps_lock(sc); ! if ((error = mps_send_mur(sc)) != 0) { mps_unlock(sc); return (error); } --- 1337,1343 ---- /* Put the IOC back in the READY state. */ mps_lock(sc); ! if ((error = mps_transition_ready(sc)) != 0) { mps_unlock(sc); return (error); } *************** *** 1197,1202 **** --- 1400,1411 ---- if (sc->sysctl_tree != NULL) sysctl_ctx_free(&sc->sysctl_ctx); + mps_mapping_free_memory(sc); + + /* Deregister the shutdown function */ + if (sc->shutdown_eh != NULL) + EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh); + mtx_destroy(&sc->mps_mtx); return (0); *************** *** 1208,1221 **** if (cm->cm_flags & MPS_CM_FLAGS_POLLED) cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; ! if (cm->cm_complete != NULL) cm->cm_complete(cm->cm_sc, cm); if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) { mps_dprint(cm->cm_sc, MPS_TRACE, "%s: waking up %p\n", __func__, cm); wakeup(cm); } } void --- 1417,1442 ---- if (cm->cm_flags & MPS_CM_FLAGS_POLLED) cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; ! if (cm->cm_complete != NULL) { ! mps_dprint(cm->cm_sc, MPS_TRACE, ! "%s cm %p calling cm_complete %p data %p reply %p\n", ! __func__, cm, cm->cm_complete, cm->cm_complete_data, ! cm->cm_reply); cm->cm_complete(cm->cm_sc, cm); + } if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) { mps_dprint(cm->cm_sc, MPS_TRACE, "%s: waking up %p\n", __func__, cm); wakeup(cm); } + + if (cm->cm_sc->io_cmds_active != 0) { + cm->cm_sc->io_cmds_active--; + } else { + mps_dprint(cm->cm_sc, MPS_INFO, "Warning: io_cmds_active is " + "out of sync - resynching to 0\n"); + } } void *************** *** 1251,1256 **** --- 1472,1478 ---- struct mps_softc *sc; sc = (struct mps_softc *)data; + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); mps_lock(sc); mps_intr_locked(data); mps_unlock(sc); *************** *** 1268,1287 **** struct mps_command *cm = NULL; uint8_t flags; u_int pq; sc = (struct mps_softc *)data; pq = sc->replypostindex; for ( ;; ) { cm = NULL; ! desc = &sc->post_queue[pq]; flags = desc->Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) || (desc->Words.High == 0xffffffff)) break; switch (flags) { case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: cm = &sc->commands[desc->SCSIIOSuccess.SMID]; --- 1490,1524 ---- struct mps_command *cm = NULL; uint8_t flags; u_int pq; + MPI2_DIAG_RELEASE_REPLY *rel_rep; + mps_fw_diagnostic_buffer_t *pBuffer; sc = (struct mps_softc *)data; pq = sc->replypostindex; + mps_dprint(sc, MPS_TRACE, + "%s sc %p starting with replypostindex %u\n", + __func__, sc, sc->replypostindex); for ( ;; ) { cm = NULL; ! desc = &sc->post_queue[sc->replypostindex]; flags = desc->Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) || (desc->Words.High == 0xffffffff)) break; + /* increment the replypostindex now, so that event handlers + * and cm completion handlers which decide to do a diag + * reset can zero it without it getting incremented again + * afterwards, and we break out of this loop on the next + * iteration since the reply post queue has been cleared to + * 0xFF and all descriptors look unused (which they are). + */ + if (++sc->replypostindex >= sc->pqdepth) + sc->replypostindex = 0; + switch (flags) { case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: cm = &sc->commands[desc->SCSIIOSuccess.SMID]; *************** *** 1323,1330 **** panic("Reply address out of range"); } if (desc->AddressReply.SMID == 0) { ! mps_dispatch_event(sc, baddr, ! (MPI2_EVENT_NOTIFICATION_REPLY *) reply); } else { cm = &sc->commands[desc->AddressReply.SMID]; cm->cm_reply = reply; --- 1560,1591 ---- panic("Reply address out of range"); } if (desc->AddressReply.SMID == 0) { ! if (((MPI2_DEFAULT_REPLY *)reply)->Function == ! MPI2_FUNCTION_DIAG_BUFFER_POST) { ! /* ! * If SMID is 0 for Diag Buffer Post, ! * this implies that the reply is due to ! * a release function with a status that ! * the buffer has been released. Set ! * the buffer flags accordingly. ! */ ! rel_rep = ! (MPI2_DIAG_RELEASE_REPLY *)reply; ! if (rel_rep->IOCStatus == ! MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED) ! { ! pBuffer = ! &sc->fw_diag_buffer_list[ ! rel_rep->BufferType]; ! pBuffer->valid_data = TRUE; ! pBuffer->owned_by_firmware = ! FALSE; ! pBuffer->immediate = FALSE; ! } ! } else ! mps_dispatch_event(sc, baddr, ! (MPI2_EVENT_NOTIFICATION_REPLY *) ! reply); } else { cm = &sc->commands[desc->AddressReply.SMID]; cm->cm_reply = reply; *************** *** 1349,1362 **** desc->Words.Low = 0xffffffff; desc->Words.High = 0xffffffff; - if (++pq >= sc->pqdepth) - pq = 0; } if (pq != sc->replypostindex) { ! mps_dprint(sc, MPS_INFO, "writing postindex %d\n", pq); ! mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, pq); ! sc->replypostindex = pq; } return; --- 1610,1622 ---- desc->Words.Low = 0xffffffff; desc->Words.High = 0xffffffff; } if (pq != sc->replypostindex) { ! mps_dprint(sc, MPS_TRACE, ! "%s sc %p writing postindex %d\n", ! __func__, sc, sc->replypostindex); ! mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex); } return; *************** *** 1379,1386 **** --- 1639,1668 ---- if (handled == 0) device_printf(sc->mps_dev, "Unhandled event 0x%x\n", event); + + /* + * This is the only place that the event/reply should be freed. + * Anything wanting to hold onto the event data should have + * already copied it into their own storage. + */ + mps_free_reply(sc, data); } + static void + mps_reregister_events_complete(struct mps_softc *sc, struct mps_command *cm) + { + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if (cm->cm_reply) + mps_print_event(sc, + (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply); + + mps_free_command(sc, cm); + + /* next, send a port enable */ + mpssas_startup(sc); + } + /* * For both register_events and update_events, the caller supplies a bitmap * of events that it _wants_. These functions then turn that into a bitmask *************** *** 1445,1458 **** error = mps_request_polled(sc, cm); reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; ! if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) error = ENXIO; mps_print_event(sc, reply); mps_free_command(sc, cm); return (error); } int mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle) { --- 1727,1786 ---- error = mps_request_polled(sc, cm); reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; ! if ((reply == NULL) || ! (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) error = ENXIO; mps_print_event(sc, reply); + mps_dprint(sc, MPS_TRACE, "%s finished error %d\n", __func__, error); mps_free_command(sc, cm); return (error); } + static int + mps_reregister_events(struct mps_softc *sc) + { + MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; + struct mps_command *cm; + struct mps_event_handle *eh; + int error, i; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + /* first, reregister events */ + + memset(sc->event_mask, 0xff, 16); + + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + for (i = 0; i < 16; i++) + sc->event_mask[i] &= ~eh->mask[i]; + } + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; + evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + evtreq->MsgFlags = 0; + evtreq->SASBroadcastPrimitiveMasks = 0; + #ifdef MPS_DEBUG_ALL_EVENTS + { + u_char fullmask[16]; + memset(fullmask, 0x00, 16); + bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); + } + #else + bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); + #endif + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + cm->cm_complete = mps_reregister_events_complete; + + error = mps_map_command(sc, cm); + + mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__, error); + return (error); + } + int mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle) { *************** *** 1511,1516 **** --- 1839,1845 ---- MPI2_SGE_TRANSACTION_UNION *tc = sgep; MPI2_SGE_SIMPLE64 *sge = sgep; int error, type; + uint32_t saved_buf_len, saved_address_low, saved_address_high; type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK); *************** *** 1609,1620 **** if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { /* ! * Last element of the last segment of the entire ! * buffer. */ ! sge->FlagsLength |= ((MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | ! MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT); } cm->cm_sglsize -= len; --- 1938,1985 ---- if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { /* ! * If this is a bi-directional request, need to account for that ! * here. Save the pre-filled sge values. These will be used ! * either for the 2nd SGL or for a single direction SGL. If ! * cm_out_len is non-zero, this is a bi-directional request, so ! * fill in the OUT SGL first, then the IN SGL, otherwise just ! * fill in the IN SGL. Note that at this time, when filling in ! * 2 SGL's for a bi-directional request, they both use the same ! * DMA buffer (same cm command). */ ! saved_buf_len = sge->FlagsLength & 0x00FFFFFF; ! saved_address_low = sge->Address.Low; ! saved_address_high = sge->Address.High; ! if (cm->cm_out_len) { ! sge->FlagsLength = cm->cm_out_len | ! ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_END_OF_BUFFER | ! MPI2_SGE_FLAGS_HOST_TO_IOC | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); ! cm->cm_sglsize -= len; ! bcopy(sgep, cm->cm_sge, len); ! cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge ! + len); ! } ! sge->FlagsLength = saved_buf_len | ! ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | ! MPI2_SGE_FLAGS_LAST_ELEMENT | ! MPI2_SGE_FLAGS_END_OF_LIST | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); ! if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) { ! sge->FlagsLength |= ! ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << ! MPI2_SGE_FLAGS_SHIFT); ! } else { ! sge->FlagsLength |= ! ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << ! MPI2_SGE_FLAGS_SHIFT); ! } ! sge->Address.Low = saved_address_low; ! sge->Address.High = saved_address_high; } cm->cm_sglsize -= len; *************** *** 1633,1642 **** MPI2_SGE_SIMPLE64 sge; /* ! * This driver always uses 64-bit address elements for ! * simplicity. */ ! flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_ADDRESS_SIZE; sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); mps_from_u64(pa, &sge.Address); --- 1998,2007 ---- MPI2_SGE_SIMPLE64 sge; /* ! * This driver always uses 64-bit address elements for simplicity. */ ! flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING; sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); mps_from_u64(pa, &sge.Address); *************** *** 1664,1671 **** } /* ! * Set up DMA direction flags. Note that we don't support ! * bi-directional transfers, with the exception of SMP passthrough. */ sflags = 0; if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) { --- 2029,2036 ---- } /* ! * Set up DMA direction flags. Bi-directional requests are also handled ! * here. In that case, both direction flags will be set. */ sflags = 0; if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) { *************** *** 1691,1704 **** sflags |= MPI2_SGE_FLAGS_DIRECTION | MPI2_SGE_FLAGS_END_OF_BUFFER; } else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) { ! sflags |= MPI2_SGE_FLAGS_DIRECTION; dir = BUS_DMASYNC_PREWRITE; } else dir = BUS_DMASYNC_PREREAD; for (i = 0; i < nsegs; i++) { ! if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) ! && (i != 0)) { sflags &= ~MPI2_SGE_FLAGS_DIRECTION; } error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, --- 2056,2068 ---- sflags |= MPI2_SGE_FLAGS_DIRECTION | MPI2_SGE_FLAGS_END_OF_BUFFER; } else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) { ! sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC; dir = BUS_DMASYNC_PREWRITE; } else dir = BUS_DMASYNC_PREREAD; for (i = 0; i < nsegs; i++) { ! if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) && (i != 0)) { sflags &= ~MPI2_SGE_FLAGS_DIRECTION; } error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, *************** *** 1726,1733 **** } /* * Note that the only error path here is from bus_dmamap_load(), which can ! * return EINPROGRESS if it is waiting for resources. */ int mps_map_command(struct mps_softc *sc, struct mps_command *cm) --- 2090,2100 ---- } /* + * This is the routine to enqueue commands ansynchronously. * Note that the only error path here is from bus_dmamap_load(), which can ! * return EINPROGRESS if it is waiting for resources. Other than this, it's ! * assumed that if you have a command in-hand, then you have enough credits ! * to use it. */ int mps_map_command(struct mps_softc *sc, struct mps_command *cm) *************** *** 1752,1758 **** MPI2_SGE_FLAGS_SHIFT; sge->Address = 0; } ! mps_enqueue_request(sc, cm); } return (error); --- 2119,2176 ---- MPI2_SGE_FLAGS_SHIFT; sge->Address = 0; } ! mps_enqueue_request(sc, cm); ! } ! ! return (error); ! } ! ! /* ! * This is the routine to enqueue commands synchronously. An error of ! * EINPROGRESS from mps_map_command() is ignored since the command will ! * be executed and enqueued automatically. Other errors come from msleep(). ! */ ! int ! mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout) ! { ! int error; ! ! mtx_assert(&sc->mps_mtx, MA_OWNED); ! ! cm->cm_complete = NULL; ! cm->cm_flags |= MPS_CM_FLAGS_WAKEUP; ! error = mps_map_command(sc, cm); ! if ((error != 0) && (error != EINPROGRESS)) ! return (error); ! error = msleep(cm, &sc->mps_mtx, 0, "mpswait", timeout); ! if (error == EWOULDBLOCK) ! error = ETIMEDOUT; ! return (error); ! } ! ! /* ! * This is the routine to enqueue a command synchonously and poll for ! * completion. Its use should be rare. ! */ ! int ! mps_request_polled(struct mps_softc *sc, struct mps_command *cm) ! { ! int error, timeout = 0; ! ! error = 0; ! ! cm->cm_flags |= MPS_CM_FLAGS_POLLED; ! cm->cm_complete = NULL; ! mps_map_command(sc, cm); ! ! while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { ! mps_intr_locked(sc); ! DELAY(50 * 1000); ! if (timeout++ > 1000) { ! mps_dprint(sc, MPS_FAULT, "polling failed\n"); ! error = ETIMEDOUT; ! break; ! } } return (error); *************** *** 1816,1826 **** cm->cm_complete = mps_config_complete; return (mps_map_command(sc, cm)); } else { ! cm->cm_complete = NULL; ! cm->cm_flags |= MPS_CM_FLAGS_WAKEUP; ! if ((error = mps_map_command(sc, cm)) != 0) return (error); ! msleep(cm, &sc->mps_mtx, 0, "mpswait", 0); mps_config_complete(sc, cm); } --- 2234,2246 ---- cm->cm_complete = mps_config_complete; return (mps_map_command(sc, cm)); } else { ! error = mps_wait_command(sc, cm, 0); ! if (error) { ! mps_dprint(sc, MPS_FAULT, ! "Error %d reading config page\n", error); ! mps_free_command(sc, cm); return (error); ! } mps_config_complete(sc, cm); } *************** *** 1853,1862 **** */ if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { params->status = MPI2_IOCSTATUS_BUSY; ! goto bailout; } reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; params->status = reply->IOCStatus; if (params->hdr.Ext.ExtPageType != 0) { params->hdr.Ext.ExtPageType = reply->ExtPageType; --- 2273,2286 ---- */ if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { params->status = MPI2_IOCSTATUS_BUSY; ! goto done; } reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (reply == NULL) { + params->status = MPI2_IOCSTATUS_BUSY; + goto done; + } params->status = reply->IOCStatus; if (params->hdr.Ext.ExtPageType != 0) { params->hdr.Ext.ExtPageType = reply->ExtPageType; *************** *** 1868,1875 **** params->hdr.Struct.PageVersion = reply->Header.PageVersion; } ! bailout: ! mps_free_command(sc, cm); if (params->callback != NULL) params->callback(sc, params); --- 2292,2298 ---- params->hdr.Struct.PageVersion = reply->Header.PageVersion; } ! done: mps_free_command(sc, cm); if (params->callback != NULL) params->callback(sc, params); *** /dev/null Fri Jan 20 13:16:35 2012 --- src/sys/dev/mps/mps_config.c Fri Jan 20 13:16:35 2012 *************** *** 0 **** --- 1,1393 ---- + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + + #include + __FBSDID("$FreeBSD$"); + + /* TODO Move headers to mpsvar */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + /** + * mps_config_get_ioc_pg8 - obtain ioc page 8 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2IOCPage8_t *config_page) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + MPI2_CONFIG_PAGE_IOC_8 *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t)))); + + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags + * accordingly. Currently, this page does not need to return to caller. + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + pMpi2ManufacturingPagePS_t page = NULL; + uint32_t *pPS_info; + uint8_t OEM_Value = 0; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; + request->Header.PageNumber = 10; + request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; + request->Header.PageNumber = 10; + request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + + /* + * If OEM ID is unknown, fail the request. + */ + sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS; + OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF); + if (OEM_Value != MPS_WD_LSI_OEM) { + mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive " + "(0x%x)\n", OEM_Value); + error = ENXIO; + goto out; + } + + /* + * Set the phys disks hide/expose value. + */ + pPS_info = &page->ProductSpecificInfo; + sc->WD_hide_expose = (uint8_t)(pPS_info[5]); + sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK; + if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) && + (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) && + (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) { + mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive " + "hide/expose: 0x%x\n", sc->WD_hide_expose); + error = ENXIO; + goto out; + } + + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_base_static_config_pages - static start of day config pages. + * @sc: per adapter object + * + * Return nothing. + */ + void + mps_base_static_config_pages(struct mps_softc *sc) + { + Mpi2ConfigReply_t mpi_reply; + int retry; + + retry = 0; + while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) { + retry++; + if (retry > 5) { + /* We need to Handle this situation */ + /*FIXME*/ + break; + } + } + } + + /** + * mps_wd_config_pages - get info required to support WarpDrive. This needs to + * be called after discovery is complete to guarentee that IR info is there. + * @sc: per adapter object + * + * Return nothing. + */ + void + mps_wd_config_pages(struct mps_softc *sc) + { + Mpi2ConfigReply_t mpi_reply; + pMpi2RaidVolPage0_t raid_vol_pg0 = NULL; + Mpi2RaidPhysDiskPage0_t phys_disk_pg0; + pMpi2RaidVol0PhysDisk_t pRVPD; + uint32_t stripe_size, phys_disk_page_address; + uint16_t block_size; + uint8_t index, stripe_exp = 0, block_exp = 0; + + /* + * Get the WD settings from manufacturing page 10 if using a WD HBA. + * This will be used to determine if phys disks should always be + * hidden, hidden only if part of a WD volume, or never hidden. Also, + * get the WD RAID Volume info and fail if volume does not exist or if + * volume does not meet the requirements for a WD volume. No retry + * here. Just default to HIDE ALWAYS if man Page10 fails, or clear WD + * Valid flag if Volume info fails. + */ + sc->WD_valid_config = FALSE; + if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) { + if (mps_config_get_man_pg10(sc, &mpi_reply)) { + mps_dprint(sc, MPS_FAULT, + "mps_config_get_man_pg10 failed! Using 0 (Hide " + "Always) for WarpDrive hide/expose value.\n"); + sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS; + } + + /* + * Get first RAID Volume Page0 using GET_NEXT_HANDLE. + */ + raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) + + (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL), + M_MPT2, M_ZERO | M_NOWAIT); + if (!raid_vol_pg0) { + printf("%s: page alloc failed\n", __func__); + goto out; + } + + if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0, + 0x0000FFFF)) { + mps_dprint(sc, MPS_INFO, + "mps_config_get_raid_volume_pg0 failed! Assuming " + "WarpDrive IT mode.\n"); + goto out; + } + + /* + * Check for valid WD configuration: + * volume type is RAID0 + * number of phys disks in the volume is no more than 8 + */ + if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) || + (raid_vol_pg0->NumPhysDisks > 8)) { + mps_dprint(sc, MPS_FAULT, + "Invalid WarpDrive configuration. Direct Drive I/O " + "will not be used.\n"); + goto out; + } + + /* + * Save the WD RAID data to be used during WD I/O. + */ + sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High << + 32 | (uint64_t)raid_vol_pg0->MaxLBA.Low); + sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks; + sc->DD_dev_handle = raid_vol_pg0->DevHandle; + sc->DD_stripe_size = raid_vol_pg0->StripeSize; + sc->DD_block_size = raid_vol_pg0->BlockSize; + + /* + * Find power of 2 of stripe size and set this as the exponent. + * Fail if stripe size is 0. + */ + stripe_size = raid_vol_pg0->StripeSize; + for (index = 0; index < 32; index++) { + if (stripe_size & 1) + break; + stripe_exp++; + stripe_size >>= 1; + } + if (index == 32) { + mps_dprint(sc, MPS_FAULT, + "RAID Volume's stripe size is 0. Direct Drive I/O " + "will not be used.\n"); + goto out; + } + sc->DD_stripe_exponent = stripe_exp; + + /* + * Find power of 2 of block size and set this as the exponent. + * Fail if block size is 0. + */ + block_size = raid_vol_pg0->BlockSize; + for (index = 0; index < 16; index++) { + if (block_size & 1) + break; + block_exp++; + block_size >>= 1; + } + if (index == 16) { + mps_dprint(sc, MPS_FAULT, + "RAID Volume's block size is 0. Direct Drive I/O " + "will not be used.\n"); + goto out; + } + sc->DD_block_exponent = block_exp; + + /* + * Loop through all of the volume's Phys Disks to map the phys + * disk number into the columm map. This is used during Direct + * Drive I/O to send the request to the correct SSD. + */ + pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk; + for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) { + sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num = + pRVPD->PhysDiskNum; + pRVPD++; + } + + /* + * Get second RAID Volume Page0 using previous handle. This + * page should not exist. If it does, must not proceed with WD + * handling. + */ + if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, + raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) { + if (mpi_reply.IOCStatus != + MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) { + mps_dprint(sc, MPS_FAULT, + "Multiple RAID Volume Page0! Direct Drive " + "I/O will not be used.\n"); + goto out; + } + } else { + mps_dprint(sc, MPS_FAULT, + "Multiple volumes! Direct Drive I/O will not be " + "used.\n"); + goto out; + } + + /* + * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume. + */ + for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) { + phys_disk_page_address = + MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM + + sc->DD_column_map[index].phys_disk_num; + if (mps_config_get_raid_pd_pg0(sc, &mpi_reply, + &phys_disk_pg0, phys_disk_page_address)) { + mps_dprint(sc, MPS_FAULT, + "mps_config_get_raid_pd_pg0 failed! Direct " + "Drive I/O will not be used.\n"); + goto out; + } + if (phys_disk_pg0.DevHandle == 0xFFFF) { + mps_dprint(sc, MPS_FAULT, + "Invalid Phys Disk DevHandle! Direct Drive " + "I/O will not be used.\n"); + goto out; + } + sc->DD_column_map[index].dev_handle = + phys_disk_pg0.DevHandle; + } + sc->WD_valid_config = TRUE; + out: + if (raid_vol_pg0) + free(raid_vol_pg0, M_MPT2); + } + } + + /** + * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2DriverMappingPage0_t *config_page, u16 sz) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2DriverMappingPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + memset(config_page, 0, sz); + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->PageAddress = sc->max_dpm_entries << + MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->PageAddress = sc->max_dpm_entries << + MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->ExtPageLength = mpi_reply->ExtPageLength; + cm->cm_length = le16toh(request->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, sz)); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @entry_idx: entry index in DPM Page0 to be modified + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + + int mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2DriverMappingPage0_t *config_page, u16 entry_idx) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->PageAddress |= htole16(entry_idx); + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->ExtPageLength = mpi_reply->ExtPageLength; + request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->PageAddress |= htole16(entry_idx); + cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + bcopy(config_page, page, MIN(cm->cm_length, + (sizeof(Mpi2DriverMappingPage0_t)))); + cm->cm_data = page; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page written with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_sas_device_pg0 - obtain sas device page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2SasDevicePage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; + request->ExtPageLength = mpi_reply->ExtPageLength; + request->PageAddress = htole32(form | handle); + cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2SasDevicePage0_t))); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_bios_pg3 - obtain BIOS page 3 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2BiosPage3_t *config_page) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2BiosPage3_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + request->Header.PageNumber = 3; + request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + request->Header.PageNumber = 3; + request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t))); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_raid_volume_pg0 - obtain raid volume page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @page_address: form and handle value used to get page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2RaidVolPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 0; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = page_address; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, cm->cm_length); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_raid_volume_pg1 - obtain raid volume page 1 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: volume handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2RaidVolPage1_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 1; + request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 1; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = htole32(form | handle); + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2RaidVolPage1_t))); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } + + /** + * mps_config_get_volume_wwid - returns wwid given the volume handle + * @sc: per adapter object + * @volume_handle: volume handle + * @wwid: volume wwid + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid) + { + Mpi2ConfigReply_t mpi_reply; + Mpi2RaidVolPage1_t raid_vol_pg1; + + *wwid = 0; + if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) { + *wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 | + raid_vol_pg1.WWID.Low); + return 0; + } else + return -1; + } + + /** + * mps_config_get_pd_pg0 - obtain raid phys disk page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @page_address: form and handle value used to get page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + int + mps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address) + { + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mps_command *cm; + Mpi2RaidPhysDiskPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mps_free_command(sc, cm); + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; + request->Header.PageNumber = 0; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = page_address; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mps_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2RaidPhysDiskPage0_t))); + out: + free(page, M_MPT2); + if (cm) + mps_free_command(sc, cm); + return (error); + } ==== - //depot/users/kenm/FreeBSD-test/sys/dev/mps/mps_config.c#2 ==== *** src/sys/dev/mps/mps_ioctl.h.orig --- src/sys/dev/mps/mps_ioctl.h *************** *** 29,35 **** * * LSI MPT-Fusion Host Adapter FreeBSD userland interface * ! * $FreeBSD: head/sys/dev/mps/mps_ioctl.h 213702 2010-10-11 21:26:24Z mdf $ */ #ifndef _MPS_IOCTL_H_ --- 29,64 ---- * * LSI MPT-Fusion Host Adapter FreeBSD userland interface * ! * $FreeBSD$ ! */ ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ */ #ifndef _MPS_IOCTL_H_ *************** *** 93,100 **** uint32_t flags; }; ! #define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01 ! #define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02 #define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req) #define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req) #define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req) --- 122,358 ---- uint32_t flags; }; ! typedef struct mps_pci_bits ! { ! union { ! struct { ! uint32_t DeviceNumber :5; ! uint32_t FunctionNumber :3; ! uint32_t BusNumber :24; ! } bits; ! uint32_t AsDWORD; ! } u; ! uint32_t PciSegmentId; ! } mps_pci_bits_t; ! ! /* ! * The following is the MPSIOCTL_GET_ADAPTER_DATA data structure. This data ! * structure is setup so that we hopefully are properly aligned for both ! * 32-bit and 64-bit mode applications. ! * ! * Adapter Type - Value = 4 = SCSI Protocol through SAS-2 adapter ! * ! * MPI Port Number - The PCI Function number for this device ! * ! * PCI Device HW Id - The PCI device number for this device ! * ! */ ! #define MPSIOCTL_ADAPTER_TYPE_SAS2 4 ! #define MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200 5 ! typedef struct mps_adapter_data ! { ! uint32_t StructureLength; ! uint32_t AdapterType; ! uint32_t MpiPortNumber; ! uint32_t PCIDeviceHwId; ! uint32_t PCIDeviceHwRev; ! uint32_t SubSystemId; ! uint32_t SubsystemVendorId; ! uint32_t Reserved1; ! uint32_t MpiFirmwareVersion; ! uint32_t BiosVersion; ! uint8_t DriverVersion[32]; ! uint8_t Reserved2; ! uint8_t ScsiId; ! uint16_t Reserved3; ! mps_pci_bits_t PciInformation; ! } mps_adapter_data_t; ! ! ! typedef struct mps_update_flash ! { ! uint64_t PtrBuffer; ! uint32_t ImageChecksum; ! uint32_t ImageOffset; ! uint32_t ImageSize; ! uint32_t ImageType; ! } mps_update_flash_t; ! ! ! #define MPS_PASS_THRU_DIRECTION_NONE 0 ! #define MPS_PASS_THRU_DIRECTION_READ 1 ! #define MPS_PASS_THRU_DIRECTION_WRITE 2 ! #define MPS_PASS_THRU_DIRECTION_BOTH 3 ! ! typedef struct mps_pass_thru ! { ! uint64_t PtrRequest; ! uint64_t PtrReply; ! uint64_t PtrData; ! uint32_t RequestSize; ! uint32_t ReplySize; ! uint32_t DataSize; ! uint32_t DataDirection; ! uint64_t PtrDataOut; ! uint32_t DataOutSize; ! uint32_t Timeout; ! } mps_pass_thru_t; ! ! ! /* ! * Event queue defines ! */ ! #define MPS_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */ ! #define MPS_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */ ! ! typedef struct mps_event_query ! { ! uint16_t Entries; ! uint16_t Reserved; ! uint32_t Types[4]; ! } mps_event_query_t; ! ! typedef struct mps_event_enable ! { ! uint32_t Types[4]; ! } mps_event_enable_t; ! ! /* ! * Event record entry for ioctl. ! */ ! typedef struct mps_event_entry ! { ! uint32_t Type; ! uint32_t Number; ! uint32_t Data[MPS_MAX_EVENT_DATA_LENGTH]; ! } mps_event_entry_t; ! ! typedef struct mps_event_report ! { ! uint32_t Size; ! uint64_t PtrEvents; ! } mps_event_report_t; ! ! ! typedef struct mps_pci_info ! { ! uint32_t BusNumber; ! uint8_t DeviceNumber; ! uint8_t FunctionNumber; ! uint16_t InterruptVector; ! uint8_t PciHeader[256]; ! } mps_pci_info_t; ! ! ! typedef struct mps_diag_action ! { ! uint32_t Action; ! uint32_t Length; ! uint64_t PtrDiagAction; ! uint32_t ReturnCode; ! } mps_diag_action_t; ! ! #define MPS_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF) ! ! #define MPS_FW_DIAG_NEW (0x806E6577) ! ! #define MPS_FW_DIAG_TYPE_REGISTER (0x00000001) ! #define MPS_FW_DIAG_TYPE_UNREGISTER (0x00000002) ! #define MPS_FW_DIAG_TYPE_QUERY (0x00000003) ! #define MPS_FW_DIAG_TYPE_READ_BUFFER (0x00000004) ! #define MPS_FW_DIAG_TYPE_RELEASE (0x00000005) ! ! #define MPS_FW_DIAG_INVALID_UID (0x00000000) ! ! #define MPS_DIAG_SUCCESS 0 ! #define MPS_DIAG_FAILURE 1 ! ! #define MPS_FW_DIAG_ERROR_SUCCESS (0x00000000) ! #define MPS_FW_DIAG_ERROR_FAILURE (0x00000001) ! #define MPS_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002) ! #define MPS_FW_DIAG_ERROR_POST_FAILED (0x00000010) ! #define MPS_FW_DIAG_ERROR_INVALID_UID (0x00000011) ! #define MPS_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012) ! #define MPS_FW_DIAG_ERROR_NO_BUFFER (0x00000013) ! #define MPS_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014) ! ! ! typedef struct mps_fw_diag_register ! { ! uint8_t ExtendedType; ! uint8_t BufferType; ! uint16_t ApplicationFlags; ! uint32_t DiagnosticFlags; ! uint32_t ProductSpecific[23]; ! uint32_t RequestedBufferSize; ! uint32_t UniqueId; ! } mps_fw_diag_register_t; ! ! typedef struct mps_fw_diag_unregister ! { ! uint32_t UniqueId; ! } mps_fw_diag_unregister_t; ! ! #define MPS_FW_DIAG_FLAG_APP_OWNED (0x0001) ! #define MPS_FW_DIAG_FLAG_BUFFER_VALID (0x0002) ! #define MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004) ! ! typedef struct mps_fw_diag_query ! { ! uint8_t ExtendedType; ! uint8_t BufferType; ! uint16_t ApplicationFlags; ! uint32_t DiagnosticFlags; ! uint32_t ProductSpecific[23]; ! uint32_t TotalBufferSize; ! uint32_t DriverAddedBufferSize; ! uint32_t UniqueId; ! } mps_fw_diag_query_t; ! ! typedef struct mps_fw_diag_release ! { ! uint32_t UniqueId; ! } mps_fw_diag_release_t; ! ! #define MPS_FW_DIAG_FLAG_REREGISTER (0x0001) ! #define MPS_FW_DIAG_FLAG_FORCE_RELEASE (0x0002) ! ! typedef struct mps_diag_read_buffer ! { ! uint8_t Status; ! uint8_t Reserved; ! uint16_t Flags; ! uint32_t StartingOffset; ! uint32_t BytesToRead; ! uint32_t UniqueId; ! uint64_t PtrDataBuffer; ! } mps_diag_read_buffer_t; ! ! /* ! * Register Access ! */ ! #define REG_IO_READ 1 ! #define REG_IO_WRITE 2 ! #define REG_MEM_READ 3 ! #define REG_MEM_WRITE 4 ! ! typedef struct mps_reg_access ! { ! uint32_t Command; ! uint32_t RegOffset; ! uint32_t RegData; ! } mps_reg_access_t; ! ! typedef struct mps_btdh_mapping ! { ! uint16_t TargetID; ! uint16_t Bus; ! uint16_t DevHandle; ! uint16_t Reserved; ! } mps_btdh_mapping_t; ! ! #define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01 ! #define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02 #define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req) #define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req) #define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req) *************** *** 103,106 **** --- 361,387 ---- #define MPSIO_RAID_ACTION _IOWR('M', 205, struct mps_raid_action) #define MPSIO_MPS_COMMAND _IOWR('M', 210, struct mps_usr_command) + #define MPTIOCTL ('I') + #define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\ + struct mps_adapter_data) + #define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\ + struct mps_update_flash) + #define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3) + #define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\ + struct mps_pass_thru) + #define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\ + struct mps_event_query) + #define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\ + struct mps_event_enable) + #define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\ + struct mps_event_report) + #define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\ + struct mps_pci_info) + #define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\ + struct mps_diag_action) + #define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\ + struct mps_reg_access) + #define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\ + struct mps_btdh_mapping) + #endif /* !_MPS_IOCTL_H_ */ *** /dev/null Fri Jan 20 13:16:35 2012 --- src/sys/dev/mps/mps_mapping.c Fri Jan 20 13:16:35 2012 *************** *** 0 **** --- 1,2268 ---- + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + + #include + __FBSDID("$FreeBSD$"); + + /* TODO Move headers to mpsvar */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + /** + * _mapping_clear_entry - Clear a particular mapping entry. + * @map_entry: map table entry + * + * Returns nothing. + */ + static inline void + _mapping_clear_map_entry(struct dev_mapping_table *map_entry) + { + map_entry->physical_id = 0; + map_entry->device_info = 0; + map_entry->phy_bits = 0; + map_entry->dpm_entry_num = MPS_DPM_BAD_IDX; + map_entry->dev_handle = 0; + map_entry->channel = -1; + map_entry->id = -1; + map_entry->missing_count = 0; + map_entry->init_complete = 0; + map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; + } + + /** + * _mapping_clear_enc_entry - Clear a particular enclosure table entry. + * @enc_entry: enclosure table entry + * + * Returns nothing. + */ + static inline void + _mapping_clear_enc_entry(struct enc_mapping_table *enc_entry) + { + enc_entry->enclosure_id = 0; + enc_entry->start_index = MPS_MAPTABLE_BAD_IDX; + enc_entry->phy_bits = 0; + enc_entry->dpm_entry_num = MPS_DPM_BAD_IDX; + enc_entry->enc_handle = 0; + enc_entry->num_slots = 0; + enc_entry->start_slot = 0; + enc_entry->missing_count = 0; + enc_entry->removal_flag = 0; + enc_entry->skip_search = 0; + enc_entry->init_complete = 0; + } + + /** + * _mapping_commit_enc_entry - write a particular enc entry in DPM page0. + * @sc: per adapter object + * @enc_entry: enclosure table entry + * + * Returns 0 for success, non-zero for failure. + */ + static int + _mapping_commit_enc_entry(struct mps_softc *sc, + struct enc_mapping_table *et_entry) + { + Mpi2DriverMap0Entry_t *dpm_entry; + struct dev_mapping_table *mt_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + + if (!sc->is_dpm_enable) + return 0; + + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *) sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += et_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = + ( 0xFFFFFFFF & et_entry->enclosure_id); + dpm_entry->PhysicalIdentifier.High = + ( et_entry->enclosure_id >> 32); + mt_entry = &sc->mapping_table[et_entry->start_index]; + dpm_entry->DeviceIndex = htole16(mt_entry->id); + dpm_entry->MappingInformation = et_entry->num_slots; + dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + dpm_entry->MappingInformation |= et_entry->missing_count; + dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); + dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits); + dpm_entry->Reserved1 = 0; + + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + et_entry->dpm_entry_num)) { + printf("%s: write of dpm entry %d for enclosure failed\n", + __func__, et_entry->dpm_entry_num); + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = + le32toh(dpm_entry->PhysicalBitsMapping); + return -1; + } + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = + le32toh(dpm_entry->PhysicalBitsMapping); + return 0; + } + + /** + * _mapping_commit_map_entry - write a particular map table entry in DPM page0. + * @sc: per adapter object + * @enc_entry: enclosure table entry + * + * Returns 0 for success, non-zero for failure. + */ + + static int + _mapping_commit_map_entry(struct mps_softc *sc, + struct dev_mapping_table *mt_entry) + { + Mpi2DriverMap0Entry_t *dpm_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + + if (!sc->is_dpm_enable) + return 0; + + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = dpm_entry + mt_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF & + mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = htole16(mt_entry->id); + dpm_entry->MappingInformation = htole16(mt_entry->missing_count); + dpm_entry->PhysicalBitsMapping = 0; + dpm_entry->Reserved1 = 0; + dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + mt_entry->dpm_entry_num)) { + printf("%s: write of dpm entry %d for device failed\n", + __func__, mt_entry->dpm_entry_num); + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + return -1; + } + + dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + return 0; + } + + /** + * _mapping_get_ir_maprange - get start and end index for IR map range. + * @sc: per adapter object + * @start_idx: place holder for start index + * @end_idx: place holder for end index + * + * The IR volumes can be mapped either at start or end of the mapping table + * this function gets the detail of where IR volume mapping starts and ends + * in the device mapping table + * + * Returns nothing. + */ + static void + _mapping_get_ir_maprange(struct mps_softc *sc, u32 *start_idx, u32 *end_idx) + { + u16 volume_mapping_flags; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { + *start_idx = 0; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + *start_idx = 1; + } else + *start_idx = sc->max_devices - sc->max_volumes; + *end_idx = *start_idx + sc->max_volumes - 1; + } + + /** + * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID + * @sc: per adapter object + * @enc_id: enclosure logical identifier + * + * Returns the index of enclosure entry on success or bad index. + */ + static u8 + _mapping_get_enc_idx_from_id(struct mps_softc *sc, u64 enc_id, + u64 phy_bits) + { + struct enc_mapping_table *et_entry; + u8 enc_idx = 0; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if ((et_entry->enclosure_id == le64toh(enc_id)) && + (!et_entry->phy_bits || (et_entry->phy_bits & + le32toh(phy_bits)))) + return enc_idx; + } + return MPS_ENCTABLE_BAD_IDX; + } + + /** + * _mapping_get_enc_idx_from_handle - get enclosure index from handle + * @sc: per adapter object + * @enc_id: enclosure handle + * + * Returns the index of enclosure entry on success or bad index. + */ + static u8 + _mapping_get_enc_idx_from_handle(struct mps_softc *sc, u16 handle) + { + struct enc_mapping_table *et_entry; + u8 enc_idx = 0; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->missing_count) + continue; + if (et_entry->enc_handle == handle) + return enc_idx; + } + return MPS_ENCTABLE_BAD_IDX; + } + + /** + * _mapping_get_high_missing_et_idx - get missing enclosure index + * @sc: per adapter object + * + * Search through the enclosure table and identifies the enclosure entry + * with high missing count and returns it's index + * + * Returns the index of enclosure entry on success or bad index. + */ + static u8 + _mapping_get_high_missing_et_idx(struct mps_softc *sc) + { + struct enc_mapping_table *et_entry; + u8 high_missing_count = 0; + u8 enc_idx, high_idx = MPS_ENCTABLE_BAD_IDX; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if ((et_entry->missing_count > high_missing_count) && + !et_entry->skip_search) { + high_missing_count = et_entry->missing_count; + high_idx = enc_idx; + } + } + return high_idx; + } + + /** + * _mapping_get_high_missing_mt_idx - get missing map table index + * @sc: per adapter object + * + * Search through the map table and identifies the device entry + * with high missing count and returns it's index + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_high_missing_mt_idx(struct mps_softc *sc) + { + u32 map_idx, high_idx = MPS_ENCTABLE_BAD_IDX; + u8 high_missing_count = 0; + u32 start_idx, end_idx, start_idx_ir, end_idx_ir; + struct dev_mapping_table *mt_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + start_idx = 0; + end_idx = sc->max_devices; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + start_idx = 1; + if (sc->ir_firmware) + _mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir); + if (start_idx == start_idx_ir) + start_idx = end_idx_ir + 1; + else + end_idx = start_idx_ir; + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) { + if (mt_entry->missing_count > high_missing_count) { + high_missing_count = mt_entry->missing_count; + high_idx = map_idx; + } + } + return high_idx; + } + + /** + * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID + * @sc: per adapter object + * @wwid: world wide unique ID of the volume + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_ir_mt_idx_from_wwid(struct mps_softc *sc, u64 wwid) + { + u32 start_idx, end_idx, map_idx; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (mt_entry->physical_id == wwid) + return map_idx; + + return MPS_MAPTABLE_BAD_IDX; + } + + /** + * _mapping_get_mt_idx_from_id - get map table index from a device ID + * @sc: per adapter object + * @dev_id: device identifer (SAS Address) + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_mt_idx_from_id(struct mps_softc *sc, u64 dev_id) + { + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->physical_id == dev_id) + return map_idx; + } + return MPS_MAPTABLE_BAD_IDX; + } + + /** + * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle + * @sc: per adapter object + * @wwid: volume device handle + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_ir_mt_idx_from_handle(struct mps_softc *sc, u16 volHandle) + { + u32 start_idx, end_idx, map_idx; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (mt_entry->dev_handle == volHandle) + return map_idx; + + return MPS_MAPTABLE_BAD_IDX; + } + + /** + * _mapping_get_mt_idx_from_handle - get map table index from handle + * @sc: per adapter object + * @dev_id: device handle + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_mt_idx_from_handle(struct mps_softc *sc, u16 handle) + { + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle) + return map_idx; + } + return MPS_MAPTABLE_BAD_IDX; + } + + /** + * _mapping_get_free_ir_mt_idx - get first free index for a volume + * @sc: per adapter object + * + * Search through mapping table for free index for a volume and if no free + * index then looks for a volume with high mapping index + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_free_ir_mt_idx(struct mps_softc *sc) + { + u8 high_missing_count = 0; + u32 start_idx, end_idx, map_idx; + u32 high_idx = MPS_MAPTABLE_BAD_IDX; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (!(mt_entry->device_info & MPS_MAP_IN_USE)) + return map_idx; + + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) { + if (mt_entry->missing_count > high_missing_count) { + high_missing_count = mt_entry->missing_count; + high_idx = map_idx; + } + } + return high_idx; + } + + /** + * _mapping_get_free_mt_idx - get first free index for a device + * @sc: per adapter object + * @start_idx: offset in the table to start search + * + * Returns the index of map table entry on success or bad index. + */ + static u32 + _mapping_get_free_mt_idx(struct mps_softc *sc, u32 start_idx) + { + u32 map_idx, max_idx = sc->max_devices; + struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx]; + u16 volume_mapping_flags; + + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (sc->ir_firmware && (volume_mapping_flags == + MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) + max_idx -= sc->max_volumes; + for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++) + if (!(mt_entry->device_info & (MPS_MAP_IN_USE | + MPS_DEV_RESERVED))) + return map_idx; + + return MPS_MAPTABLE_BAD_IDX; + } + + /** + * _mapping_get_dpm_idx_from_id - get DPM index from ID + * @sc: per adapter object + * @id: volume WWID or enclosure ID or device ID + * + * Returns the index of DPM entry on success or bad index. + */ + static u16 + _mapping_get_dpm_idx_from_id(struct mps_softc *sc, u64 id, u32 phy_bits) + { + u16 entry_num; + uint64_t PhysicalIdentifier; + Mpi2DriverMap0Entry_t *dpm_entry; + + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High; + PhysicalIdentifier = (PhysicalIdentifier << 32) | + dpm_entry->PhysicalIdentifier.Low; + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, + dpm_entry++) + if ((id == PhysicalIdentifier) && + (!phy_bits || !dpm_entry->PhysicalBitsMapping || + (phy_bits & dpm_entry->PhysicalBitsMapping))) + return entry_num; + + return MPS_DPM_BAD_IDX; + } + + + /** + * _mapping_get_free_dpm_idx - get first available DPM index + * @sc: per adapter object + * + * Returns the index of DPM entry on success or bad index. + */ + static u32 + _mapping_get_free_dpm_idx(struct mps_softc *sc) + { + u16 entry_num; + + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { + if (!sc->dpm_entry_used[entry_num]) + return entry_num; + } + return MPS_DPM_BAD_IDX; + } + + /** + * _mapping_update_ir_missing_cnt - Updates missing count for a volume + * @sc: per adapter object + * @map_idx: map table index of the volume + * @element: IR configuration change element + * @wwid: IR volume ID. + * + * Updates the missing count in the map table and in the DPM entry for a volume + * + * Returns nothing. + */ + static void + _mapping_update_ir_missing_cnt(struct mps_softc *sc, u32 map_idx, + Mpi2EventIrConfigElement_t *element, u64 wwid) + { + struct dev_mapping_table *mt_entry; + u8 missing_cnt, reason = element->ReasonCode; + u16 dpm_idx; + Mpi2DriverMap0Entry_t *dpm_entry; + + if (!sc->is_dpm_enable) + return; + mt_entry = &sc->mapping_table[map_idx]; + if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) { + mt_entry->missing_count = 0; + } else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + mt_entry->missing_count = 0; + mt_entry->init_complete = 0; + } else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) || + (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT) + mt_entry->missing_count++; + else + mt_entry->init_complete = 1; + } + if (!mt_entry->missing_count) + mt_entry->missing_count++; + mt_entry->dev_handle = 0; + } + + dpm_idx = mt_entry->dpm_entry_num; + if (dpm_idx == MPS_DPM_BAD_IDX) { + if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) || + (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED)) + dpm_idx = _mapping_get_dpm_idx_from_id(sc, + mt_entry->physical_id, 0); + else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) + return; + } + if (dpm_idx != MPS_DPM_BAD_IDX) { + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += dpm_idx; + missing_cnt = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + if ((mt_entry->physical_id == + le64toh((u64)dpm_entry->PhysicalIdentifier.High | + dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt == + mt_entry->missing_count)) + mt_entry->init_complete = 1; + } else { + dpm_idx = _mapping_get_free_dpm_idx(sc); + mt_entry->init_complete = 0; + } + + if ((dpm_idx != MPS_DPM_BAD_IDX) && !mt_entry->init_complete) { + mt_entry->init_complete = 1; + mt_entry->dpm_entry_num = dpm_idx; + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += dpm_idx; + dpm_entry->PhysicalIdentifier.Low = + (0xFFFFFFFF & mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = + (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = map_idx; + dpm_entry->MappingInformation = mt_entry->missing_count; + dpm_entry->PhysicalBitsMapping = 0; + dpm_entry->Reserved1 = 0; + sc->dpm_flush_entry[dpm_idx] = 1; + sc->dpm_entry_used[dpm_idx] = 1; + } else if (dpm_idx == MPS_DPM_BAD_IDX) { + printf("%s: no space to add entry in DPM table\n", __func__); + mt_entry->init_complete = 1; + } + } + + /** + * _mapping_add_to_removal_table - mark an entry for removal + * @sc: per adapter object + * @handle: Handle of enclosures/device/volume + * + * Adds the handle or DPM entry number in removal table. + * + * Returns nothing. + */ + static void + _mapping_add_to_removal_table(struct mps_softc *sc, u16 handle, + u16 dpm_idx) + { + struct map_removal_table *remove_entry; + u32 i; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + remove_entry = sc->removal_table; + + for (i = 0; i < sc->max_devices; i++, remove_entry++) { + if (remove_entry->dev_handle || remove_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) + continue; + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + if (dpm_idx) + remove_entry->dpm_entry_num = dpm_idx; + if (remove_entry->dpm_entry_num == MPS_DPM_BAD_IDX) + remove_entry->dev_handle = handle; + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) + remove_entry->dev_handle = handle; + break; + } + + } + + /** + * _mapping_update_missing_count - Update missing count for a device + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change list and if any device is found not + * responding it's associated map table entry and DPM entry is updated + * + * Returns nothing. + */ + static void + _mapping_update_missing_count(struct mps_softc *sc, + struct _map_topology_change *topo_change) + { + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u8 entry; + struct _map_phy_change *phy_change; + u32 map_idx; + struct dev_mapping_table *mt_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (!phy_change->dev_handle || (phy_change->reason != + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) + continue; + map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change-> + dev_handle); + phy_change->is_processed = 1; + if (map_idx == MPS_MAPTABLE_BAD_IDX) { + printf("%s: device is already removed from mapping " + "table\n", __func__); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT) + mt_entry->missing_count++; + else + mt_entry->init_complete = 1; + } + if (!mt_entry->missing_count) + mt_entry->missing_count++; + _mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0); + mt_entry->dev_handle = 0; + + if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) && + sc->is_dpm_enable && !mt_entry->init_complete && + mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) { + dpm_entry = + (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += mt_entry->dpm_entry_num; + dpm_entry->MappingInformation = mt_entry->missing_count; + sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1; + } + mt_entry->init_complete = 1; + } + } + + /** + * _mapping_find_enc_map_space -find map table entries for enclosure + * @sc: per adapter object + * @et_entry: enclosure entry + * + * Search through the mapping table defragment it and provide contiguous + * space in map table for a particular enclosure entry + * + * Returns start index in map table or bad index. + */ + static u32 + _mapping_find_enc_map_space(struct mps_softc *sc, + struct enc_mapping_table *et_entry) + { + u16 vol_mapping_flags; + u32 skip_count, end_of_table, map_idx, enc_idx; + u16 num_found; + u32 start_idx = MPS_MAPTABLE_BAD_IDX; + struct dev_mapping_table *mt_entry; + struct enc_mapping_table *enc_entry; + unsigned char done_flag = 0, found_space; + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + + skip_count = sc->num_rsvd_entries; + num_found = 0; + + vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + + if (!sc->ir_firmware) + end_of_table = sc->max_devices; + else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) + end_of_table = sc->max_devices; + else + end_of_table = sc->max_devices - sc->max_volumes; + + for (map_idx = (max_num_phy_ids + skip_count); + map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if ((et_entry->enclosure_id == mt_entry->physical_id) && + (!mt_entry->phy_bits || (mt_entry->phy_bits & + et_entry->phy_bits))) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + return start_idx; + } + } else + num_found = 0; + } + for (map_idx = (max_num_phy_ids + skip_count); + map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (!(mt_entry->device_info & MPS_DEV_RESERVED)) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + return start_idx; + } + } else + num_found = 0; + } + + while (!done_flag) { + enc_idx = _mapping_get_high_missing_et_idx(sc); + if (enc_idx == MPS_ENCTABLE_BAD_IDX) + return MPS_MAPTABLE_BAD_IDX; + enc_entry = &sc->enclosure_table[enc_idx]; + /*VSP FIXME*/ + enc_entry->skip_search = 1; + mt_entry = &sc->mapping_table[enc_entry->start_index]; + for (map_idx = enc_entry->start_index; map_idx < + (enc_entry->start_index + enc_entry->num_slots); map_idx++, + mt_entry++) + mt_entry->device_info &= ~MPS_DEV_RESERVED; + found_space = 0; + for (map_idx = (max_num_phy_ids + + skip_count); map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (!(mt_entry->device_info & MPS_DEV_RESERVED)) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + found_space = 1; + } + } else + num_found = 0; + } + + if (!found_space) + continue; + for (map_idx = start_idx; map_idx < (start_idx + num_found); + map_idx++) { + enc_entry = sc->enclosure_table; + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; + enc_idx++, enc_entry++) { + if (map_idx < enc_entry->start_index || + map_idx > (enc_entry->start_index + + enc_entry->num_slots)) + continue; + if (!enc_entry->removal_flag) { + enc_entry->removal_flag = 1; + _mapping_add_to_removal_table(sc, 0, + enc_entry->dpm_entry_num); + } + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->device_info & + MPS_MAP_IN_USE) { + _mapping_add_to_removal_table(sc, + mt_entry->dev_handle, 0); + _mapping_clear_map_entry(mt_entry); + } + if (map_idx == (enc_entry->start_index + + enc_entry->num_slots - 1)) + _mapping_clear_enc_entry(et_entry); + } + } + enc_entry = sc->enclosure_table; + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; + enc_idx++, enc_entry++) { + if (!enc_entry->removal_flag) { + mt_entry = &sc->mapping_table[enc_entry-> + start_index]; + for (map_idx = enc_entry->start_index; map_idx < + (enc_entry->start_index + + enc_entry->num_slots); map_idx++, + mt_entry++) + mt_entry->device_info |= + MPS_DEV_RESERVED; + et_entry->skip_search = 0; + } + } + done_flag = 1; + } + return start_idx; + } + + /** + * _mapping_get_dev_info -get information about newly added devices + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change event list and issues sas device pg0 + * requests for the newly added device and reserved entries in tables + * + * Returns nothing + */ + static void + _mapping_get_dev_info(struct mps_softc *sc, + struct _map_topology_change *topo_change) + { + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + u8 entry, enc_idx, phy_idx; + u32 map_idx, index, device_info; + struct _map_phy_change *phy_change, *tmp_phy_change; + uint64_t sas_address; + struct enc_mapping_table *et_entry; + struct dev_mapping_table *mt_entry; + u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + int rc; + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (phy_change->is_processed || !phy_change->dev_handle || + phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) + continue; + if (mps_config_get_sas_device_pg0(sc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + phy_change->dev_handle)) { + phy_change->is_processed = 1; + continue; + } + + device_info = le32toh(sas_device_pg0.DeviceInfo); + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && + (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { + rc = mpssas_get_sas_address_for_sata_disk(sc, + &sas_address, phy_change->dev_handle, + device_info); + if (rc) { + printf("%s: failed to compute the " + "hashed SAS Address for SATA " + "device with handle 0x%04x\n", + __func__, phy_change->dev_handle); + sas_address = + sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + mps_dprint(sc, MPS_INFO, "SAS Address for SATA " + "device = %jx\n", sas_address); + } else { + sas_address = + sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + } else { + sas_address = sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + phy_change->physical_id = sas_address; + phy_change->slot = le16toh(sas_device_pg0.Slot); + phy_change->device_info = + le32toh(sas_device_pg0.DeviceInfo); + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + enc_idx = _mapping_get_enc_idx_from_handle(sc, + topo_change->enc_handle); + if (enc_idx == MPS_ENCTABLE_BAD_IDX) { + phy_change->is_processed = 1; + printf("%s: failed to add the device with " + "handle 0x%04x because the enclosure is " + "not in the mapping table\n", __func__, + phy_change->dev_handle); + continue; + } + if (!((phy_change->device_info & + MPI2_SAS_DEVICE_INFO_END_DEVICE) && + (phy_change->device_info & + (MPI2_SAS_DEVICE_INFO_SSP_TARGET | + MPI2_SAS_DEVICE_INFO_STP_TARGET | + MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) { + phy_change->is_processed = 1; + continue; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->start_index != MPS_MAPTABLE_BAD_IDX) + continue; + if (!topo_change->exp_handle) { + map_idx = sc->num_rsvd_entries; + et_entry->start_index = map_idx; + } else { + map_idx = _mapping_find_enc_map_space(sc, + et_entry); + et_entry->start_index = map_idx; + if (et_entry->start_index == + MPS_MAPTABLE_BAD_IDX) { + phy_change->is_processed = 1; + for (phy_idx = 0; phy_idx < + topo_change->num_entries; + phy_idx++) { + tmp_phy_change = + &topo_change->phy_details + [phy_idx]; + if (tmp_phy_change->reason == + add_code) + tmp_phy_change-> + is_processed = 1; + } + break; + } + } + mt_entry = &sc->mapping_table[map_idx]; + for (index = map_idx; index < (et_entry->num_slots + + map_idx); index++, mt_entry++) { + mt_entry->device_info = MPS_DEV_RESERVED; + mt_entry->physical_id = et_entry->enclosure_id; + mt_entry->phy_bits = et_entry->phy_bits; + } + } + } + } + + /** + * _mapping_set_mid_to_eid -set map table data from enclosure table + * @sc: per adapter object + * @et_entry: enclosure entry + * + * Returns nothing + */ + static inline void + _mapping_set_mid_to_eid(struct mps_softc *sc, + struct enc_mapping_table *et_entry) + { + struct dev_mapping_table *mt_entry; + u16 slots = et_entry->num_slots, map_idx; + u32 start_idx = et_entry->start_index; + if (start_idx != MPS_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++) + mt_entry->physical_id = et_entry->enclosure_id; + } + } + + /** + * _mapping_clear_removed_entries - mark the entries to be cleared + * @sc: per adapter object + * + * Search through the removal table and mark the entries which needs to be + * flushed to DPM and also updates the map table and enclosure table by + * clearing the corresponding entries. + * + * Returns nothing + */ + static void + _mapping_clear_removed_entries(struct mps_softc *sc) + { + u32 remove_idx; + struct map_removal_table *remove_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u8 done_flag = 0, num_entries, m, i; + struct enc_mapping_table *et_entry, *from, *to; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + if (sc->is_dpm_enable) { + remove_entry = sc->removal_table; + for (remove_idx = 0; remove_idx < sc->max_devices; + remove_idx++, remove_entry++) { + if (remove_entry->dpm_entry_num != MPS_DPM_BAD_IDX) { + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += remove_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = 0; + dpm_entry->PhysicalIdentifier.High = 0; + dpm_entry->DeviceIndex = 0; + dpm_entry->MappingInformation = 0; + dpm_entry->PhysicalBitsMapping = 0; + sc->dpm_flush_entry[remove_entry-> + dpm_entry_num] = 1; + sc->dpm_entry_used[remove_entry->dpm_entry_num] + = 0; + remove_entry->dpm_entry_num = MPS_DPM_BAD_IDX; + } + } + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + num_entries = sc->num_enc_table_entries; + while (!done_flag) { + done_flag = 1; + et_entry = sc->enclosure_table; + for (i = 0; i < num_entries; i++, et_entry++) { + if (!et_entry->enc_handle && et_entry-> + init_complete) { + done_flag = 0; + if (i != (num_entries - 1)) { + from = &sc->enclosure_table + [i+1]; + to = &sc->enclosure_table[i]; + for (m = i; m < (num_entries - + 1); m++, from++, to++) { + _mapping_set_mid_to_eid + (sc, to); + *to = *from; + } + _mapping_clear_enc_entry(to); + sc->num_enc_table_entries--; + num_entries = + sc->num_enc_table_entries; + } else { + _mapping_clear_enc_entry + (et_entry); + sc->num_enc_table_entries--; + num_entries = + sc->num_enc_table_entries; + } + } + } + } + } + } + + /** + * _mapping_add_new_device -Add the new device into mapping table + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change event list and updates map table, + * enclosure table and DPM pages for for the newly added devices. + * + * Returns nothing + */ + static void + _mapping_add_new_device(struct mps_softc *sc, + struct _map_topology_change *topo_change) + { + u8 enc_idx, missing_cnt, is_removed = 0; + u16 dpm_idx; + u32 search_idx, map_idx; + u32 entry; + struct dev_mapping_table *mt_entry; + struct enc_mapping_table *et_entry; + struct _map_phy_change *phy_change; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + Mpi2DriverMap0Entry_t *dpm_entry; + uint64_t temp64_var; + u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER); + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (phy_change->is_processed) + continue; + if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED || + !phy_change->dev_handle) { + phy_change->is_processed = 1; + continue; + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + enc_idx = _mapping_get_enc_idx_from_handle + (sc, topo_change->enc_handle); + if (enc_idx == MPS_ENCTABLE_BAD_IDX) { + phy_change->is_processed = 1; + printf("%s: failed to add the device with " + "handle 0x%04x because the enclosure is " + "not in the mapping table\n", __func__, + phy_change->dev_handle); + continue; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->start_index == MPS_MAPTABLE_BAD_IDX) { + phy_change->is_processed = 1; + if (!sc->mt_full_retry) { + sc->mt_add_device_failed = 1; + continue; + } + printf("%s: failed to add the device with " + "handle 0x%04x because there is no free " + "space available in the mapping table\n", + __func__, phy_change->dev_handle); + continue; + } + map_idx = et_entry->start_index + phy_change->slot - + et_entry->start_slot; + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = phy_change->physical_id; + mt_entry->channel = 0; + mt_entry->id = map_idx; + mt_entry->dev_handle = phy_change->dev_handle; + mt_entry->missing_count = 0; + mt_entry->dpm_entry_num = et_entry->dpm_entry_num; + mt_entry->device_info = phy_change->device_info | + (MPS_DEV_RESERVED | MPS_MAP_IN_USE); + if (sc->is_dpm_enable) { + dpm_idx = et_entry->dpm_entry_num; + if (dpm_idx == MPS_DPM_BAD_IDX) + dpm_idx = _mapping_get_dpm_idx_from_id + (sc, et_entry->enclosure_id, + et_entry->phy_bits); + if (dpm_idx == MPS_DPM_BAD_IDX) { + dpm_idx = _mapping_get_free_dpm_idx(sc); + if (dpm_idx != MPS_DPM_BAD_IDX) { + dpm_entry = + (Mpi2DriverMap0Entry_t *) + ((u8 *) sc->dpm_pg0 + + hdr_sz); + dpm_entry += dpm_idx; + dpm_entry-> + PhysicalIdentifier.Low = + (0xFFFFFFFF & + et_entry->enclosure_id); + dpm_entry-> + PhysicalIdentifier.High = + ( et_entry->enclosure_id + >> 32); + dpm_entry->DeviceIndex = + (U16)et_entry->start_index; + dpm_entry->MappingInformation = + et_entry->num_slots; + dpm_entry->MappingInformation + <<= map_shift; + dpm_entry->PhysicalBitsMapping + = et_entry->phy_bits; + et_entry->dpm_entry_num = + dpm_idx; + /* FIXME Do I need to set the dpm_idxin mt_entry too */ + sc->dpm_entry_used[dpm_idx] = 1; + sc->dpm_flush_entry[dpm_idx] = + 1; + phy_change->is_processed = 1; + } else { + phy_change->is_processed = 1; + printf("%s: failed to add the " + "device with handle 0x%04x " + "to persistent table " + "because there is no free " + "space available\n", + __func__, + phy_change->dev_handle); + } + } else { + et_entry->dpm_entry_num = dpm_idx; + mt_entry->dpm_entry_num = dpm_idx; + } + } + /* FIXME Why not mt_entry too? */ + et_entry->init_complete = 1; + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + map_idx = _mapping_get_mt_idx_from_id + (sc, phy_change->physical_id); + if (map_idx == MPS_MAPTABLE_BAD_IDX) { + search_idx = sc->num_rsvd_entries; + if (topo_change->exp_handle) + search_idx += max_num_phy_ids; + map_idx = _mapping_get_free_mt_idx(sc, + search_idx); + } + if (map_idx == MPS_MAPTABLE_BAD_IDX) { + map_idx = _mapping_get_high_missing_mt_idx(sc); + if (map_idx != MPS_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle) { + _mapping_add_to_removal_table + (sc, mt_entry->dev_handle, + 0); + is_removed = 1; + } + mt_entry->init_complete = 0; + } + } + if (map_idx != MPS_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = phy_change->physical_id; + mt_entry->channel = 0; + mt_entry->id = map_idx; + mt_entry->dev_handle = phy_change->dev_handle; + mt_entry->missing_count = 0; + mt_entry->device_info = phy_change->device_info + | (MPS_DEV_RESERVED | MPS_MAP_IN_USE); + } else { + phy_change->is_processed = 1; + if (!sc->mt_full_retry) { + sc->mt_add_device_failed = 1; + continue; + } + printf("%s: failed to add the device with " + "handle 0x%04x because there is no free " + "space available in the mapping table\n", + __func__, phy_change->dev_handle); + continue; + } + if (sc->is_dpm_enable) { + if (mt_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) { + dpm_idx = mt_entry->dpm_entry_num; + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *)sc->dpm_pg0 + hdr_sz); + dpm_entry += dpm_idx; + missing_cnt = dpm_entry-> + MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + temp64_var = dpm_entry-> + PhysicalIdentifier.High; + temp64_var = (temp64_var << 32) | + dpm_entry->PhysicalIdentifier.Low; + if ((mt_entry->physical_id == + temp64_var) && !missing_cnt) + mt_entry->init_complete = 1; + } else { + dpm_idx = _mapping_get_free_dpm_idx(sc); + mt_entry->init_complete = 0; + } + if (dpm_idx != MPS_DPM_BAD_IDX && + !mt_entry->init_complete) { + mt_entry->init_complete = 1; + mt_entry->dpm_entry_num = dpm_idx; + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *)sc->dpm_pg0 + hdr_sz); + dpm_entry += dpm_idx; + dpm_entry->PhysicalIdentifier.Low = + (0xFFFFFFFF & + mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = + (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = (U16) map_idx; + dpm_entry->MappingInformation = 0; + dpm_entry->PhysicalBitsMapping = 0; + sc->dpm_entry_used[dpm_idx] = 1; + sc->dpm_flush_entry[dpm_idx] = 1; + phy_change->is_processed = 1; + } else if (dpm_idx == MPS_DPM_BAD_IDX) { + phy_change->is_processed = 1; + printf("%s: failed to add the " + "device with handle 0x%04x " + "to persistent table " + "because there is no free " + "space available\n", + __func__, + phy_change->dev_handle); + } + } + mt_entry->init_complete = 1; + } + + phy_change->is_processed = 1; + } + if (is_removed) + _mapping_clear_removed_entries(sc); + } + + /** + * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM + * @sc: per adapter object + * + * Returns nothing + */ + static void + _mapping_flush_dpm_pages(struct mps_softc *sc) + { + Mpi2DriverMap0Entry_t *dpm_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + u16 entry_num; + + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { + if (!sc->dpm_flush_entry[entry_num]) + continue; + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += entry_num; + dpm_entry->MappingInformation = htole16(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = htole32(dpm_entry-> + PhysicalBitsMapping); + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + /* TODO-How to handle failed writes? */ + if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + entry_num)) { + printf("%s: write of dpm entry %d for device failed\n", + __func__, entry_num); + } else + sc->dpm_flush_entry[entry_num] = 0; + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry-> + PhysicalBitsMapping); + } + } + + /** + * _mapping_allocate_memory- allocates the memory required for mapping tables + * @sc: per adapter object + * + * Allocates the memory for all the tables required for host mapping + * + * Return 0 on success or non-zero on failure. + */ + int + mps_mapping_allocate_memory(struct mps_softc *sc) + { + uint32_t dpm_pg0_sz; + + sc->mapping_table = malloc((sizeof(struct dev_mapping_table) * + sc->max_devices), M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->mapping_table) + goto free_resources; + + sc->removal_table = malloc((sizeof(struct map_removal_table) * + sc->max_devices), M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->removal_table) + goto free_resources; + + sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) * + sc->max_enclosures), M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->enclosure_table) + goto free_resources; + + sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries), + M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->dpm_entry_used) + goto free_resources; + + sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries), + M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->dpm_flush_entry) + goto free_resources; + + dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + + (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); + + sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPT2, M_ZERO|M_NOWAIT); + if (!sc->dpm_pg0) { + printf("%s: memory alloc failed for dpm page; disabling dpm\n", + __func__); + sc->is_dpm_enable = 0; + } + + return 0; + + free_resources: + free(sc->mapping_table, M_MPT2); + free(sc->removal_table, M_MPT2); + free(sc->enclosure_table, M_MPT2); + free(sc->dpm_entry_used, M_MPT2); + free(sc->dpm_flush_entry, M_MPT2); + free(sc->dpm_pg0, M_MPT2); + printf("%s: device initialization failed due to failure in mapping " + "table memory allocation\n", __func__); + return -1; + } + + /** + * mps_mapping_free_memory- frees the memory allocated for mapping tables + * @sc: per adapter object + * + * Returns nothing. + */ + void + mps_mapping_free_memory(struct mps_softc *sc) + { + free(sc->mapping_table, M_MPT2); + free(sc->removal_table, M_MPT2); + free(sc->enclosure_table, M_MPT2); + free(sc->dpm_entry_used, M_MPT2); + free(sc->dpm_flush_entry, M_MPT2); + free(sc->dpm_pg0, M_MPT2); + } + + + static void + _mapping_process_dpm_pg0(struct mps_softc *sc) + { + u8 missing_cnt, enc_idx; + u16 slot_id, entry_num, num_slots; + u32 map_idx, dev_idx, start_idx, end_idx; + struct dev_mapping_table *mt_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + struct enc_mapping_table *et_entry; + u64 physical_id; + u32 phy_bits = 0; + + if (sc->ir_firmware) + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + + dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, + dpm_entry++) { + physical_id = dpm_entry->PhysicalIdentifier.High; + physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + if (!physical_id) { + sc->dpm_entry_used[entry_num] = 0; + continue; + } + sc->dpm_entry_used[entry_num] = 1; + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + missing_cnt = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + dev_idx = le16toh(dpm_entry->DeviceIndex); + phy_bits = le32toh(dpm_entry->PhysicalBitsMapping); + if (sc->ir_firmware && (dev_idx >= start_idx) && + (dev_idx <= end_idx)) { + mt_entry = &sc->mapping_table[dev_idx]; + mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (mt_entry->physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->channel = MPS_RAID_CHANNEL; + mt_entry->id = dev_idx; + mt_entry->missing_count = missing_cnt; + mt_entry->dpm_entry_num = entry_num; + mt_entry->device_info = MPS_DEV_RESERVED; + continue; + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + if (dev_idx < (sc->num_rsvd_entries + + max_num_phy_ids)) { + slot_id = 0; + if (ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1) + slot_id = 1; + num_slots = max_num_phy_ids; + } else { + slot_id = 0; + num_slots = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_SLOT_MASK; + num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + } + enc_idx = sc->num_enc_table_entries; + if (enc_idx >= sc->max_enclosures) { + printf("%s: enclosure entries exceed max " + "enclosures of %d\n", __func__, + sc->max_enclosures); + break; + } + sc->num_enc_table_entries++; + et_entry = &sc->enclosure_table[enc_idx]; + physical_id = dpm_entry->PhysicalIdentifier.High; + et_entry->enclosure_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + et_entry->start_index = dev_idx; + et_entry->dpm_entry_num = entry_num; + et_entry->num_slots = num_slots; + et_entry->start_slot = slot_id; + et_entry->missing_count = missing_cnt; + et_entry->phy_bits = phy_bits; + + mt_entry = &sc->mapping_table[dev_idx]; + for (map_idx = dev_idx; map_idx < (dev_idx + num_slots); + map_idx++, mt_entry++) { + if (mt_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) { + printf("%s: conflict in mapping table " + "for enclosure %d\n", __func__, + enc_idx); + break; + } + physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->phy_bits = phy_bits; + mt_entry->channel = 0; + mt_entry->id = dev_idx; + mt_entry->dpm_entry_num = entry_num; + mt_entry->missing_count = missing_cnt; + mt_entry->device_info = MPS_DEV_RESERVED; + } + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + map_idx = dev_idx; + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) { + printf("%s: conflict in mapping table for " + "device %d\n", __func__, map_idx); + break; + } + physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->phy_bits = phy_bits; + mt_entry->channel = 0; + mt_entry->id = dev_idx; + mt_entry->missing_count = missing_cnt; + mt_entry->dpm_entry_num = entry_num; + mt_entry->device_info = MPS_DEV_RESERVED; + } + } /*close the loop for DPM table */ + } + + /* + * mps_mapping_check_devices - start of the day check for device availabilty + * @sc: per adapter object + * @sleep_flag: Flag indicating whether this function can sleep or not + * + * Returns nothing. + */ + void + mps_mapping_check_devices(struct mps_softc *sc, int sleep_flag) + { + u32 i; + /* u32 cntdn, i; + u32 timeout = 60;*/ + struct dev_mapping_table *mt_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + struct enc_mapping_table *et_entry; + u32 start_idx, end_idx; + + /* We need to ucomment this when this function is called + * from the port enable complete */ + #if 0 + sc->track_mapping_events = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + if (!sc->pending_map_events) + break; + if (sleep_flag == CAN_SLEEP) + pause("mps_pause", (hz/1000));/* 1msec sleep */ + else + DELAY(500); /* 500 useconds delay */ + } while (--cntdn); + + + if (!cntdn) + printf("%s: there are %d" + " pending events after %d seconds of delay\n", + __func__, sc->pending_map_events, timeout); + #endif + sc->pending_map_events = 0; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + et_entry = sc->enclosure_table; + for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) { + if (!et_entry->init_complete) { + if (et_entry->missing_count < + MPS_MAX_MISSING_COUNT) { + et_entry->missing_count++; + if (et_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) + _mapping_commit_enc_entry(sc, + et_entry); + } + et_entry->init_complete = 1; + } + } + if (!sc->ir_firmware) + return; + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) { + if (mt_entry->device_info & MPS_DEV_RESERVED + && !mt_entry->physical_id) + mt_entry->init_complete = 1; + else if (mt_entry->device_info & MPS_DEV_RESERVED) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < + MPS_MAX_MISSING_COUNT) { + mt_entry->missing_count++; + if (mt_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) + _mapping_commit_map_entry(sc, + mt_entry); + } + mt_entry->init_complete = 1; + } + } + } + } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + mt_entry = sc->mapping_table; + for (i = 0; i < sc->max_devices; i++, mt_entry++) { + if (mt_entry->device_info & MPS_DEV_RESERVED + && !mt_entry->physical_id) + mt_entry->init_complete = 1; + else if (mt_entry->device_info & MPS_DEV_RESERVED) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < + MPS_MAX_MISSING_COUNT) { + mt_entry->missing_count++; + if (mt_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) + _mapping_commit_map_entry(sc, + mt_entry); + } + mt_entry->init_complete = 1; + } + } + } + } + } + + + /** + * mps_mapping_is_reinit_required - check whether event replay required + * @sc: per adapter object + * + * Checks the per ioc flags and decide whether reinit of events required + * + * Returns 1 for reinit of ioc 0 for not. + */ + int mps_mapping_is_reinit_required(struct mps_softc *sc) + { + if (!sc->mt_full_retry && sc->mt_add_device_failed) { + sc->mt_full_retry = 1; + sc->mt_add_device_failed = 0; + _mapping_flush_dpm_pages(sc); + return 1; + } + sc->mt_full_retry = 1; + return 0; + } + + /** + * mps_mapping_initialize - initialize mapping tables + * @sc: per adapter object + * + * Read controller persitant mapping tables into internal data area. + * + * Return 0 for success or non-zero for failure. + */ + int + mps_mapping_initialize(struct mps_softc *sc) + { + uint16_t volume_mapping_flags, dpm_pg0_sz; + uint32_t i; + Mpi2ConfigReply_t mpi_reply; + int error; + uint8_t retry_count; + uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + /* The additional 1 accounts for the virtual enclosure + * created for the controller + */ + sc->max_enclosures = sc->facts->MaxEnclosures + 1; + sc->max_expanders = sc->facts->MaxSasExpanders; + sc->max_volumes = sc->facts->MaxVolumes; + sc->max_devices = sc->facts->MaxTargets + sc->max_volumes; + sc->pending_map_events = 0; + sc->num_enc_table_entries = 0; + sc->num_rsvd_entries = 0; + sc->num_channels = 1; + sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries; + sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0; + sc->track_mapping_events = 0; + + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING) + sc->is_dpm_enable = 0; + + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + sc->num_rsvd_entries = 1; + + volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (sc->ir_firmware && (volume_mapping_flags == + MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)) + sc->num_rsvd_entries += sc->max_volumes; + + error = mps_mapping_allocate_memory(sc); + if (error) + return (error); + + for (i = 0; i < sc->max_devices; i++) + _mapping_clear_map_entry(sc->mapping_table + i); + + for (i = 0; i < sc->max_enclosures; i++) + _mapping_clear_enc_entry(sc->enclosure_table + i); + + for (i = 0; i < sc->max_devices; i++) { + sc->removal_table[i].dev_handle = 0; + sc->removal_table[i].dpm_entry_num = MPS_DPM_BAD_IDX; + } + + memset(sc->dpm_entry_used, 0, sc->max_dpm_entries); + memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries); + + if (sc->is_dpm_enable) { + dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + + (sc->max_dpm_entries * + sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); + retry_count = 0; + + retry_read_dpm: + if (mps_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0, + dpm_pg0_sz)) { + printf("%s: dpm page read failed; disabling dpm\n", + __func__); + if (retry_count < 3) { + retry_count++; + goto retry_read_dpm; + } + sc->is_dpm_enable = 0; + } + } + + if (sc->is_dpm_enable) + _mapping_process_dpm_pg0(sc); + + sc->track_mapping_events = 1; + return 0; + } + + /** + * mps_mapping_exit - clear mapping table and associated memory + * @sc: per adapter object + * + * Returns nothing. + */ + void + mps_mapping_exit(struct mps_softc *sc) + { + _mapping_flush_dpm_pages(sc); + mps_mapping_free_memory(sc); + } + + /** + * mps_mapping_get_sas_id - assign a target id for sas device + * @sc: per adapter object + * @sas_address: sas address of the device + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ + unsigned int + mps_mapping_get_sas_id(struct mps_softc *sc, uint64_t sas_address, u16 handle) + { + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle && mt_entry->physical_id == + sas_address) + return mt_entry->id; + } + + return MPS_MAP_BAD_ID; + } + + /** + * mps_mapping_get_sas_id_from_handle - find a target id in mapping table using + * only the dev handle. This is just a wrapper function for the local function + * _mapping_get_mt_idx_from_handle. + * @sc: per adapter object + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ + unsigned int + mps_mapping_get_sas_id_from_handle(struct mps_softc *sc, u16 handle) + { + return (_mapping_get_mt_idx_from_handle(sc, handle)); + } + + /** + * mps_mapping_get_raid_id - assign a target id for raid device + * @sc: per adapter object + * @wwid: world wide identifier for raid volume + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ + unsigned int + mps_mapping_get_raid_id(struct mps_softc *sc, u64 wwid, u16 handle) + { + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle && mt_entry->physical_id == + wwid) + return mt_entry->id; + } + + return MPS_MAP_BAD_ID; + } + + /** + * mps_mapping_get_raid_id_from_handle - find raid device in mapping table + * using only the volume dev handle. This is just a wrapper function for the + * local function _mapping_get_ir_mt_idx_from_handle. + * @sc: per adapter object + * @volHandle: volume device handle + * + * Returns valid ID on success or BAD_ID. + */ + unsigned int + mps_mapping_get_raid_id_from_handle(struct mps_softc *sc, u16 volHandle) + { + return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle)); + } + + /** + * mps_mapping_enclosure_dev_status_change_event - handle enclosure events + * @sc: per adapter object + * @event_data: event data payload + * + * Return nothing. + */ + void + mps_mapping_enclosure_dev_status_change_event(struct mps_softc *sc, + Mpi2EventDataSasEnclDevStatusChange_t *event_data) + { + u8 enc_idx, missing_count; + struct enc_mapping_table *et_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + u8 update_phy_bits = 0; + u32 saved_phy_bits; + uint64_t temp64_var; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) != + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) + goto out; + + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + + if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) { + if (!event_data->NumSlots) { + printf("%s: enclosure with handle = 0x%x reported 0 " + "slots\n", __func__, + le16toh(event_data->EnclosureHandle)); + goto out; + } + temp64_var = event_data->EnclosureLogicalID.High; + temp64_var = (temp64_var << 32) | + event_data->EnclosureLogicalID.Low; + enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var, + event_data->PhyBits); + if (enc_idx != MPS_ENCTABLE_BAD_IDX) { + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->init_complete && + !et_entry->missing_count) { + printf("%s: enclosure %d is already present " + "with handle = 0x%x\n",__func__, enc_idx, + et_entry->enc_handle); + goto out; + } + et_entry->enc_handle = le16toh(event_data-> + EnclosureHandle); + et_entry->start_slot = le16toh(event_data->StartSlot); + saved_phy_bits = et_entry->phy_bits; + et_entry->phy_bits |= le32toh(event_data->PhyBits); + if (saved_phy_bits != et_entry->phy_bits) + update_phy_bits = 1; + if (et_entry->missing_count || update_phy_bits) { + et_entry->missing_count = 0; + if (sc->is_dpm_enable && + et_entry->dpm_entry_num != + MPS_DPM_BAD_IDX) { + dpm_entry += et_entry->dpm_entry_num; + missing_count = + (u8)(dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK); + if (!et_entry->init_complete && ( + missing_count || update_phy_bits)) { + dpm_entry->MappingInformation + = et_entry->num_slots; + dpm_entry->MappingInformation + <<= map_shift; + dpm_entry->PhysicalBitsMapping + = et_entry->phy_bits; + sc->dpm_flush_entry[et_entry-> + dpm_entry_num] = 1; + } + } + } + } else { + enc_idx = sc->num_enc_table_entries; + if (enc_idx >= sc->max_enclosures) { + printf("%s: enclosure can not be added; " + "mapping table is full\n", __func__); + goto out; + } + sc->num_enc_table_entries++; + et_entry = &sc->enclosure_table[enc_idx]; + et_entry->enc_handle = le16toh(event_data-> + EnclosureHandle); + et_entry->enclosure_id = event_data-> + EnclosureLogicalID.High; + et_entry->enclosure_id = ( et_entry->enclosure_id << + 32) | event_data->EnclosureLogicalID.Low; + et_entry->start_index = MPS_MAPTABLE_BAD_IDX; + et_entry->dpm_entry_num = MPS_DPM_BAD_IDX; + et_entry->num_slots = le16toh(event_data->NumSlots); + et_entry->start_slot = le16toh(event_data->StartSlot); + et_entry->phy_bits = le32toh(event_data->PhyBits); + } + et_entry->init_complete = 1; + } else if (event_data->ReasonCode == + MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) { + enc_idx = _mapping_get_enc_idx_from_handle(sc, + le16toh(event_data->EnclosureHandle)); + if (enc_idx == MPS_ENCTABLE_BAD_IDX) { + printf("%s: cannot unmap enclosure %d because it has " + "already been deleted", __func__, enc_idx); + goto out; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (!et_entry->init_complete) { + if (et_entry->missing_count < MPS_MAX_MISSING_COUNT) + et_entry->missing_count++; + else + et_entry->init_complete = 1; + } + if (!et_entry->missing_count) + et_entry->missing_count++; + if (sc->is_dpm_enable && !et_entry->init_complete && + et_entry->dpm_entry_num != MPS_DPM_BAD_IDX) { + dpm_entry += et_entry->dpm_entry_num; + dpm_entry->MappingInformation = et_entry->num_slots; + dpm_entry->MappingInformation <<= map_shift; + dpm_entry->MappingInformation |= + et_entry->missing_count; + sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1; + } + et_entry->init_complete = 1; + } + + out: + _mapping_flush_dpm_pages(sc); + if (sc->pending_map_events) + sc->pending_map_events--; + } + + /** + * mps_mapping_topology_change_event - handle topology change events + * @sc: per adapter object + * @event_data: event data payload + * + * Returns nothing. + */ + void + mps_mapping_topology_change_event(struct mps_softc *sc, + Mpi2EventDataSasTopologyChangeList_t *event_data) + { + struct _map_topology_change topo_change; + struct _map_phy_change *phy_change; + Mpi2EventSasTopoPhyEntry_t *event_phy_change; + u8 i, num_entries; + + topo_change.enc_handle = le16toh(event_data->EnclosureHandle); + topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle); + num_entries = event_data->NumEntries; + topo_change.num_entries = num_entries; + topo_change.start_phy_num = event_data->StartPhyNum; + topo_change.num_phys = event_data->NumPhys; + topo_change.exp_status = event_data->ExpStatus; + event_phy_change = event_data->PHY; + topo_change.phy_details = NULL; + + if (!num_entries) + goto out; + phy_change = malloc(sizeof(struct _map_phy_change) * num_entries, + M_MPT2, M_NOWAIT|M_ZERO); + topo_change.phy_details = phy_change; + if (!phy_change) + goto out; + for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) { + phy_change->dev_handle = le16toh(event_phy_change-> + AttachedDevHandle); + phy_change->reason = event_phy_change->PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + } + _mapping_update_missing_count(sc, &topo_change); + _mapping_get_dev_info(sc, &topo_change); + _mapping_clear_removed_entries(sc); + _mapping_add_new_device(sc, &topo_change); + + out: + free(topo_change.phy_details, M_MPT2); + _mapping_flush_dpm_pages(sc); + if (sc->pending_map_events) + sc->pending_map_events--; + } + + /** + * _mapping_check_update_ir_mt_idx - Check and update IR map table index + * @sc: per adapter object + * @event_data: event data payload + * @evt_idx: current event index + * @map_idx: current index and the place holder for new map table index + * @wwid_table: world wide name for volumes in the element table + * + * pass through IR events and find whether any events matches and if so + * tries to find new index if not returns failure + * + * Returns 0 on success and 1 on failure + */ + static int + _mapping_check_update_ir_mt_idx(struct mps_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx, + u64 *wwid_table) + { + struct dev_mapping_table *mt_entry; + u32 st_idx, end_idx, mt_idx = *map_idx; + u8 match = 0; + Mpi2EventIrConfigElement_t *element; + u16 element_flags; + int i; + + mt_entry = &sc->mapping_table[mt_idx]; + _mapping_get_ir_maprange(sc, &st_idx, &end_idx); + search_again: + match = 0; + for (i = evt_idx + 1; i < event_data->NumElements; i++) { + element = (Mpi2EventIrConfigElement_t *) + &event_data->ConfigElement[i]; + element_flags = le16toh(element->ElementFlags); + if ((element_flags & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) != + MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) + continue; + if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + if (mt_entry->physical_id == wwid_table[i]) { + match = 1; + break; + } + } + } + + if (match) { + do { + mt_idx++; + if (mt_idx > end_idx) + return 1; + mt_entry = &sc->mapping_table[mt_idx]; + } while (mt_entry->device_info & MPS_MAP_IN_USE); + goto search_again; + } + *map_idx = mt_idx; + return 0; + } + + /** + * mps_mapping_ir_config_change_event - handle IR config change list events + * @sc: per adapter object + * @event_data: event data payload + * + * Returns nothing. + */ + void + mps_mapping_ir_config_change_event(struct mps_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data) + { + Mpi2EventIrConfigElement_t *element; + int i; + u64 *wwid_table; + u32 map_idx, flags; + struct dev_mapping_table *mt_entry; + u16 element_flags; + u8 log_full_error = 0; + + wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPT2, + M_NOWAIT | M_ZERO); + if (!wwid_table) + goto out; + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + flags = le32toh(event_data->Flags); + for (i = 0; i < event_data->NumElements; i++, element++) { + element_flags = le16toh(element->ElementFlags); + if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) && + (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) && + (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE) + && (element->ReasonCode != + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) + continue; + if ((element_flags & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) == + MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) { + mps_config_get_volume_wwid(sc, + le16toh(element->VolDevHandle), &wwid_table[i]); + map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, + wwid_table[i]); + if (map_idx != MPS_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->device_info |= MPS_MAP_IN_USE; + } + } + } + if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + goto out; + else { + element = (Mpi2EventIrConfigElement_t *)&event_data-> + ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_ADDED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + map_idx = _mapping_get_ir_mt_idx_from_wwid + (sc, wwid_table[i]); + if (map_idx != MPS_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->channel = MPS_RAID_CHANNEL; + mt_entry->id = map_idx; + mt_entry->dev_handle = le16toh + (element->VolDevHandle); + mt_entry->device_info = + MPS_DEV_RESERVED | MPS_MAP_IN_USE; + _mapping_update_ir_missing_cnt(sc, + map_idx, element, wwid_table[i]); + continue; + } + map_idx = _mapping_get_free_ir_mt_idx(sc); + if (map_idx == MPS_MAPTABLE_BAD_IDX) + log_full_error = 1; + else if (i < (event_data->NumElements - 1)) { + log_full_error = + _mapping_check_update_ir_mt_idx + (sc, event_data, i, &map_idx, + wwid_table); + } + if (log_full_error) { + printf("%s: no space to add the RAID " + "volume with handle 0x%04x in " + "mapping table\n", __func__, le16toh + (element->VolDevHandle)); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = wwid_table[i]; + mt_entry->channel = MPS_RAID_CHANNEL; + mt_entry->id = map_idx; + mt_entry->dev_handle = le16toh(element-> + VolDevHandle); + mt_entry->device_info = MPS_DEV_RESERVED | + MPS_MAP_IN_USE; + mt_entry->init_complete = 0; + _mapping_update_ir_missing_cnt(sc, map_idx, + element, wwid_table[i]); + } else if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_REMOVED) { + map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, + wwid_table[i]); + if (map_idx == MPS_MAPTABLE_BAD_IDX) { + printf("%s: failed to remove a volume " + "because it has already been " + "removed\n", __func__); + continue; + } + _mapping_update_ir_missing_cnt(sc, map_idx, + element, wwid_table[i]); + } else if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) { + map_idx = _mapping_get_mt_idx_from_handle(sc, + le16toh(element->VolDevHandle)); + if (map_idx == MPS_MAPTABLE_BAD_IDX) { + printf("%s: failed to remove volume " + "with handle 0x%04x because it has " + "already been removed\n", __func__, + le16toh(element->VolDevHandle)); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + _mapping_update_ir_missing_cnt(sc, map_idx, + element, mt_entry->physical_id); + } + } + } + + out: + _mapping_flush_dpm_pages(sc); + free(wwid_table, M_MPT2); + if (sc->pending_map_events) + sc->pending_map_events--; + } ==== - //depot/users/kenm/FreeBSD-test/sys/dev/mps/mps_mapping.c#1 ==== *** /dev/null Fri Jan 20 13:16:35 2012 --- src/sys/dev/mps/mps_mapping.h Fri Jan 20 13:16:35 2012 *************** *** 0 **** --- 1,71 ---- + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + + #ifndef _MPS_MAPPING_H + #define _MPS_MAPPING_H + + /** + * struct _map_phy_change - PHY entries recieved in Topology change list + * @physical_id: SAS address of the device attached with the associate PHY + * @device_info: bitfield provides detailed info about the device + * @dev_handle: device handle for the device pointed by this entry + * @slot: slot ID + * @is_processed: Flag to indicate whether this entry is processed or not + */ + struct _map_phy_change { + uint64_t physical_id; + uint32_t device_info; + uint16_t dev_handle; + uint16_t slot; + uint8_t reason; + uint8_t is_processed; + }; + + /** + * struct _map_topology_change - entries to be removed from mapping table + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + */ + struct _map_topology_change { + uint16_t enc_handle; + uint16_t exp_handle; + uint8_t num_entries; + uint8_t start_phy_num; + uint8_t num_phys; + uint8_t exp_status; + struct _map_phy_change *phy_details; + }; + + + extern int + mpssas_get_sas_address_for_sata_disk(struct mps_softc *ioc, + u64 *sas_address, u16 handle, u32 device_info); + + #endif ==== - //depot/users/kenm/FreeBSD-test/sys/dev/mps/mps_mapping.h#1 ==== *** src/sys/dev/mps/mps_pci.c.orig --- src/sys/dev/mps/mps_pci.c *************** *** 29,34 **** --- 29,35 ---- /* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */ + /* TODO Move headers to mpsvar */ #include #include #include *************** *** 46,57 **** --- 47,63 ---- #include #include + #include #include #include #include #include + #include + #include + #include + #include #include static int mps_pci_probe(device_t); *************** *** 63,77 **** static int mps_alloc_msix(struct mps_softc *sc, int msgs); static int mps_alloc_msi(struct mps_softc *sc, int msgs); - int mps_disable_msix = 0; - TUNABLE_INT("hw.mps.disable_msix", &mps_disable_msix); - SYSCTL_INT(_hw_mps, OID_AUTO, disable_msix, CTLFLAG_RD, &mps_disable_msix, 0, - "Disable MSIX interrupts\n"); - int mps_disable_msi = 0; - TUNABLE_INT("hw.mps.disable_msi", &mps_disable_msi); - SYSCTL_INT(_hw_mps, OID_AUTO, disable_msi, CTLFLAG_RD, &mps_disable_msi, 0, - "Disable MSI interrupts\n"); - static device_method_t mps_methods[] = { DEVMETHOD(device_probe, mps_pci_probe), DEVMETHOD(device_attach, mps_pci_attach), --- 69,74 ---- *************** *** 125,134 **** 0xffff, 0xffff, 0, "LSI SAS2208" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, 0xffff, 0xffff, 0, "LSI SAS2208" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, ! 0xffff, 0xffff, 0, "LSI SAS2208" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, ! 0xffff, 0xffff, 0, "LSI SAS2208" }, { 0, 0, 0, 0, 0, NULL } }; --- 122,145 ---- 0xffff, 0xffff, 0, "LSI SAS2208" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, 0xffff, 0xffff, 0, "LSI SAS2208" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, ! 0xffff, 0xffff, 0, "LSI SAS2308" }, ! // Add Customer specific vender/subdevice id before generic ! // (0xffff) vender/subdevice id. ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, ! 0x8086, 0x3516, 0, "Intel(R) Integrated RAID Module RMS25JB080" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, ! 0x8086, 0x3517, 0, "Intel(R) Integrated RAID Module RMS25JB040" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, ! 0x8086, 0x3518, 0, "Intel(R) Integrated RAID Module RMS25KB080" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, ! 0x8086, 0x3519, 0, "Intel(R) Integrated RAID Module RMS25KB040" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, ! 0xffff, 0xffff, 0, "LSI SAS2308" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, ! 0xffff, 0xffff, 0, "LSI SAS2308" }, ! { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, ! 0xffff, 0xffff, MPS_FLAGS_WD_AVAILABLE, "LSI SSS6200" }, { 0, 0, 0, 0, 0, NULL } }; *************** *** 161,167 **** if ((id = mps_find_ident(dev)) != NULL) { device_set_desc(dev, id->desc); ! return (BUS_PROBE_DEFAULT); } return (ENXIO); } --- 172,178 ---- if ((id = mps_find_ident(dev)) != NULL) { device_set_desc(dev, id->desc); ! return (BUS_PROBE_VENDOR); } return (ENXIO); } *************** *** 205,211 **** sc->mps_bhandle = rman_get_bushandle(sc->mps_regs_resource); /* Allocate the parent DMA tag */ ! if (bus_dma_tag_create( NULL, /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ --- 216,222 ---- sc->mps_bhandle = rman_get_bushandle(sc->mps_regs_resource); /* Allocate the parent DMA tag */ ! if (bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ *************** *** 235,244 **** dev = sc->mps_dev; error = ENXIO; ! if ((mps_disable_msix == 0) && ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT)) error = mps_alloc_msix(sc, MPS_MSI_COUNT); ! if ((error != 0) && (mps_disable_msi == 0) && ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT)) error = mps_alloc_msi(sc, MPS_MSI_COUNT); --- 246,255 ---- dev = sc->mps_dev; error = ENXIO; ! if ((sc->disable_msix == 0) && ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT)) error = mps_alloc_msix(sc, MPS_MSI_COUNT); ! if ((error != 0) && (sc->disable_msi == 0) && ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT)) error = mps_alloc_msi(sc, MPS_MSI_COUNT); *************** *** 362,364 **** --- 373,392 ---- return (error); } + int + mps_pci_restore(struct mps_softc *sc) + { + struct pci_devinfo *dinfo; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + dinfo = device_get_ivars(sc->mps_dev); + if (dinfo == NULL) { + mps_dprint(sc, MPS_FAULT, "%s: NULL dinfo\n", __func__); + return (EINVAL); + } + + pci_cfg_restore(sc->mps_dev, dinfo); + return (0); + } + *** src/sys/dev/mps/mps_sas.c.orig --- src/sys/dev/mps/mps_sas.c *************** *** 23,34 **** * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include ! __FBSDID("$FreeBSD: head/sys/dev/mps/mps_sas.c 228939 2011-12-28 22:49:28Z mav $"); /* Communications core for LSI MPT2 */ #include #include #include --- 23,64 ---- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ #include ! __FBSDID("$FreeBSD$"); /* Communications core for LSI MPT2 */ + /* TODO Move headers to mpsvar */ #include #include #include *************** *** 41,55 **** #include #include #include - #include #include #include #include #include #include #include #include #include #include --- 71,91 ---- #include #include #include #include + #include + #include + #include + #include #include #include #include + #include + #include #include + #include #include #include #include *************** *** 67,492 **** #include #include #include #include #include ! struct mpssas_target { ! uint16_t handle; ! uint8_t linkrate; ! uint64_t devname; ! uint64_t sasaddr; ! uint32_t devinfo; ! uint16_t encl_handle; ! uint16_t encl_slot; ! uint16_t parent_handle; ! int flags; ! #define MPSSAS_TARGET_INABORT (1 << 0) ! #define MPSSAS_TARGET_INRESET (1 << 1) ! #define MPSSAS_TARGET_INCHIPRESET (1 << 2) ! #define MPSSAS_TARGET_INRECOVERY 0x7 ! uint16_t tid; ! }; ! struct mpssas_softc { ! struct mps_softc *sc; ! u_int flags; ! #define MPSSAS_IN_DISCOVERY (1 << 0) ! #define MPSSAS_IN_STARTUP (1 << 1) ! #define MPSSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) ! #define MPSSAS_QUEUE_FROZEN (1 << 3) ! struct mpssas_target *targets; ! struct cam_devq *devq; ! struct cam_sim *sim; ! struct cam_path *path; ! struct intr_config_hook sas_ich; ! struct callout discovery_callout; ! u_int discovery_timeouts; ! struct mps_event_handle *mpssas_eh; }; ! struct mpssas_devprobe { ! struct mps_config_params params; ! u_int state; ! #define MPSSAS_PROBE_DEV1 0x01 ! #define MPSSAS_PROBE_DEV2 0x02 ! #define MPSSAS_PROBE_PHY 0x03 ! #define MPSSAS_PROBE_EXP 0x04 ! #define MPSSAS_PROBE_PHY2 0x05 ! #define MPSSAS_PROBE_EXP2 0x06 ! struct mpssas_target target; ! }; ! #define MPSSAS_DISCOVERY_TIMEOUT 20 ! #define MPSSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ ! ! static MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory"); ! ! static __inline int mpssas_set_lun(uint8_t *lun, u_int ccblun); ! static struct mpssas_target * mpssas_alloc_target(struct mpssas_softc *, ! struct mpssas_target *); ! static struct mpssas_target * mpssas_find_target(struct mpssas_softc *, int, ! uint16_t); ! static void mpssas_announce_device(struct mpssas_softc *, ! struct mpssas_target *); ! static void mpssas_startup(void *data); ! static void mpssas_discovery_end(struct mpssas_softc *sassc); static void mpssas_discovery_timeout(void *data); - static void mpssas_prepare_remove(struct mpssas_softc *, - MPI2_EVENT_SAS_TOPO_PHY_ENTRY *); static void mpssas_remove_device(struct mps_softc *, struct mps_command *); static void mpssas_remove_complete(struct mps_softc *, struct mps_command *); static void mpssas_action(struct cam_sim *sim, union ccb *ccb); static void mpssas_poll(struct cam_sim *sim); - static void mpssas_probe_device(struct mps_softc *sc, uint16_t handle); - static void mpssas_probe_device_complete(struct mps_softc *sc, - struct mps_config_params *params); static void mpssas_scsiio_timeout(void *data); static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm); ! static void mpssas_recovery(struct mps_softc *, struct mps_command *); ! static int mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm); ! static void mpssas_issue_tm_request(struct mps_softc *sc, ! struct mps_command *cm); ! static void mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, ! int error); ! static int mpssas_complete_tm_request(struct mps_softc *sc, ! struct mps_command *cm, int free_cm); static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *); static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *); #if __FreeBSD_version >= 900026 static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm); static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr); static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb); ! #endif /* __FreeBSD_version >= 900026 */ ! static void mpssas_resetdev(struct mpssas_softc *, struct mps_command *); ! static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *); static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *); ! static void mpssas_freeze_device(struct mpssas_softc *, struct mpssas_target *); ! static void mpssas_unfreeze_device(struct mpssas_softc *, struct mpssas_target *) __unused; ! /* ! * Abstracted so that the driver can be backwards and forwards compatible ! * with future versions of CAM that will provide this functionality. ! */ ! #define MPS_SET_LUN(lun, ccblun) \ ! mpssas_set_lun(lun, ccblun) ! ! static __inline int ! mpssas_set_lun(uint8_t *lun, u_int ccblun) { ! uint64_t *newlun; ! newlun = (uint64_t *)lun; ! *newlun = 0; ! if (ccblun <= 0xff) { ! /* Peripheral device address method, LUN is 0 to 255 */ ! lun[1] = ccblun; ! } else if (ccblun <= 0x3fff) { ! /* Flat space address method, LUN is <= 16383 */ ! scsi_ulto2b(ccblun, lun); ! lun[0] |= 0x40; ! } else if (ccblun <= 0xffffff) { ! /* Extended flat space address method, LUN is <= 16777215 */ ! scsi_ulto3b(ccblun, &lun[1]); ! /* Extended Flat space address method */ ! lun[0] = 0xc0; ! /* Length = 1, i.e. LUN is 3 bytes long */ ! lun[0] |= 0x10; ! /* Extended Address Method */ ! lun[0] |= 0x02; ! } else { ! return (EINVAL); } ! return (0); } ! static struct mpssas_target * ! mpssas_alloc_target(struct mpssas_softc *sassc, struct mpssas_target *probe) { ! struct mpssas_target *target; ! int start; ! mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); ! ! /* ! * If it's not a sata or sas target, CAM won't be able to see it. Put ! * it into a high-numbered slot so that it's accessible but not ! * interrupting the target numbering sequence of real drives. ! */ ! if ((probe->devinfo & (MPI2_SAS_DEVICE_INFO_SSP_TARGET | ! MPI2_SAS_DEVICE_INFO_STP_TARGET | MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) ! == 0) { ! start = 200; ! } else { ! /* ! * Use the enclosure number and slot number as a hint for target ! * numbering. If that doesn't produce a sane result, search the ! * entire space. ! */ ! #if 0 ! start = probe->encl_handle * 16 + probe->encl_slot; ! #else ! start = probe->encl_slot; ! #endif ! if (start >= sassc->sc->facts->MaxTargets) ! start = 0; } ! target = mpssas_find_target(sassc, start, 0); ! /* ! * Nothing found on the first pass, try a second pass that searches the ! * entire space. ! */ ! if (target == NULL) ! target = mpssas_find_target(sassc, 0, 0); ! ! return (target); } ! static struct mpssas_target * ! mpssas_find_target(struct mpssas_softc *sassc, int start, uint16_t handle) { ! struct mpssas_target *target; ! int i; ! for (i = start; i < sassc->sc->facts->MaxTargets; i++) { ! target = &sassc->targets[i]; ! if (target->handle == handle) ! return (target); } ! return (NULL); } ! /* ! * Start the probe sequence for a given device handle. This will not ! * block. ! */ ! static void ! mpssas_probe_device(struct mps_softc *sc, uint16_t handle) { ! struct mpssas_devprobe *probe; ! struct mps_config_params *params; ! MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; ! int error; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! probe = malloc(sizeof(*probe), M_MPSSAS, M_NOWAIT | M_ZERO); ! if (probe == NULL) { ! mps_dprint(sc, MPS_FAULT, "Out of memory starting probe\n"); return; } - params = &probe->params; - hdr = ¶ms->hdr.Ext; ! params->action = MPI2_CONFIG_ACTION_PAGE_HEADER; ! params->page_address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE | handle; ! hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; ! hdr->ExtPageLength = 0; ! hdr->PageNumber = 0; ! hdr->PageVersion = 0; ! params->buffer = NULL; ! params->length = 0; ! params->callback = mpssas_probe_device_complete; ! params->cbdata = probe; ! probe->target.handle = handle; ! probe->state = MPSSAS_PROBE_DEV1; ! ! if ((error = mps_read_config_page(sc, params)) != 0) { ! free(probe, M_MPSSAS); ! mps_dprint(sc, MPS_FAULT, "Failure starting device probe\n"); return; } } static void ! mpssas_probe_device_complete(struct mps_softc *sc, ! struct mps_config_params *params) { ! MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; ! struct mpssas_devprobe *probe; ! int error; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! hdr = ¶ms->hdr.Ext; ! probe = params->cbdata; ! switch (probe->state) { ! case MPSSAS_PROBE_DEV1: ! case MPSSAS_PROBE_PHY: ! case MPSSAS_PROBE_EXP: ! if (params->status != MPI2_IOCSTATUS_SUCCESS) { ! mps_dprint(sc, MPS_FAULT, ! "Probe Failure 0x%x state %d\n", params->status, ! probe->state); ! free(probe, M_MPSSAS); ! return; ! } ! params->action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; ! params->length = hdr->ExtPageLength * 4; ! params->buffer = malloc(params->length, M_MPSSAS, ! M_ZERO|M_NOWAIT); ! if (params->buffer == NULL) { ! mps_dprint(sc, MPS_FAULT, "Out of memory at state " ! "0x%x, size 0x%x\n", probe->state, params->length); ! free(probe, M_MPSSAS); ! return; ! } ! if (probe->state == MPSSAS_PROBE_DEV1) ! probe->state = MPSSAS_PROBE_DEV2; ! else if (probe->state == MPSSAS_PROBE_PHY) ! probe->state = MPSSAS_PROBE_PHY2; ! else if (probe->state == MPSSAS_PROBE_EXP) ! probe->state = MPSSAS_PROBE_EXP2; ! error = mps_read_config_page(sc, params); ! break; ! case MPSSAS_PROBE_DEV2: ! { ! MPI2_CONFIG_PAGE_SAS_DEV_0 *buf; ! if (params->status != MPI2_IOCSTATUS_SUCCESS) { ! mps_dprint(sc, MPS_FAULT, ! "Probe Failure 0x%x state %d\n", params->status, ! probe->state); ! free(params->buffer, M_MPSSAS); ! free(probe, M_MPSSAS); ! return; } ! buf = params->buffer; ! mps_print_sasdev0(sc, buf); ! ! probe->target.devname = mps_to_u64(&buf->DeviceName); ! probe->target.devinfo = buf->DeviceInfo; ! probe->target.encl_handle = buf->EnclosureHandle; ! probe->target.encl_slot = buf->Slot; ! probe->target.sasaddr = mps_to_u64(&buf->SASAddress); ! probe->target.parent_handle = buf->ParentDevHandle; ! ! if (buf->DeviceInfo & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) { ! params->page_address = ! MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | buf->PhyNum; ! hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; ! hdr->PageNumber = 0; ! probe->state = MPSSAS_PROBE_PHY; ! } else { ! params->page_address = ! MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | ! buf->ParentDevHandle | (buf->PhyNum << 16); ! hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; ! hdr->PageNumber = 1; ! probe->state = MPSSAS_PROBE_EXP; ! } ! params->action = MPI2_CONFIG_ACTION_PAGE_HEADER; ! hdr->ExtPageLength = 0; ! hdr->PageVersion = 0; ! params->buffer = NULL; ! params->length = 0; ! free(buf, M_MPSSAS); ! error = mps_read_config_page(sc, params); ! break; } - case MPSSAS_PROBE_PHY2: - case MPSSAS_PROBE_EXP2: - { - MPI2_CONFIG_PAGE_SAS_PHY_0 *phy; - MPI2_CONFIG_PAGE_EXPANDER_1 *exp; - struct mpssas_softc *sassc; - struct mpssas_target *targ; - char devstring[80]; - uint16_t handle; ! if (params->status != MPI2_IOCSTATUS_SUCCESS) { ! mps_dprint(sc, MPS_FAULT, ! "Probe Failure 0x%x state %d\n", params->status, ! probe->state); ! free(params->buffer, M_MPSSAS); ! free(probe, M_MPSSAS); ! return; ! } ! if (probe->state == MPSSAS_PROBE_PHY2) { ! phy = params->buffer; ! mps_print_sasphy0(sc, phy); ! probe->target.linkrate = phy->NegotiatedLinkRate & 0xf; ! } else { ! exp = params->buffer; ! mps_print_expander1(sc, exp); ! probe->target.linkrate = exp->NegotiatedLinkRate & 0xf; ! } ! free(params->buffer, M_MPSSAS); ! sassc = sc->sassc; ! handle = probe->target.handle; ! if ((targ = mpssas_find_target(sassc, 0, handle)) != NULL) { ! mps_printf(sc, "Ignoring dup device handle 0x%04x\n", ! handle); ! free(probe, M_MPSSAS); ! return; ! } ! if ((targ = mpssas_alloc_target(sassc, &probe->target)) == NULL) { ! mps_printf(sc, "Target table overflow, handle 0x%04x\n", ! handle); ! free(probe, M_MPSSAS); ! return; ! } ! *targ = probe->target; /* Copy the attributes */ ! targ->tid = targ - sassc->targets; ! mps_describe_devinfo(targ->devinfo, devstring, 80); ! if (bootverbose) ! mps_printf(sc, "Found device <%s> <%s> <0x%04x> " ! "<%d/%d>\n", devstring, ! mps_describe_table(mps_linkrate_names, ! targ->linkrate), targ->handle, targ->encl_handle, ! targ->encl_slot); ! free(probe, M_MPSSAS); ! mpssas_announce_device(sassc, targ); ! break; ! } ! default: ! printf("what?\n"); ! } } /* ! * The MPT2 firmware performs debounce on the link to avoid transient link errors ! * and false removals. When it does decide that link has been lost and a device ! * need to go away, it expects that the host will perform a target reset and then ! * an op remove. The reset has the side-effect of aborting any outstanding ! * requests for the device, which is required for the op-remove to succeed. It's ! * not clear if the host should check for the device coming back alive after the ! * reset. */ ! static void ! mpssas_prepare_remove(struct mpssas_softc *sassc, MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; struct mps_softc *sc; struct mps_command *cm; struct mpssas_target *targ = NULL; - uint16_t handle; mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); ! handle = phy->AttachedDevHandle; ! targ = mpssas_find_target(sassc, 0, handle); ! if (targ == NULL) /* We don't know about this device? */ return; ! sc = sassc->sc; ! cm = mps_alloc_command(sc); if (cm == NULL) { ! mps_printf(sc, "comand alloc failure in mpssas_prepare_remove\n"); return; } ! mps_dprint(sc, MPS_INFO, "Preparing to remove target %d\n", targ->tid); req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; memset(req, 0, sizeof(*req)); --- 103,421 ---- #include #include #include + #include + #include #include #include + #include ! #define MPSSAS_DISCOVERY_TIMEOUT 20 ! #define MPSSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ ! /* ! * static array to check SCSI OpCode for EEDP protection bits ! */ ! #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP ! #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP ! #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP ! static uint8_t op_code_prot[256] = { ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, ! 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ! MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory"); ! static struct mpssas_target * mpssas_find_target_by_handle(struct mpssas_softc *, int, uint16_t); static void mpssas_discovery_timeout(void *data); static void mpssas_remove_device(struct mps_softc *, struct mps_command *); static void mpssas_remove_complete(struct mps_softc *, struct mps_command *); static void mpssas_action(struct cam_sim *sim, union ccb *ccb); static void mpssas_poll(struct cam_sim *sim); static void mpssas_scsiio_timeout(void *data); static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm); ! static void mpssas_direct_drive_io(struct mpssas_softc *sassc, ! struct mps_command *cm, union ccb *ccb); static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *); static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *); + static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *); #if __FreeBSD_version >= 900026 static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm); static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr); static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb); ! #endif //FreeBSD_version >= 900026 static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *); ! static int mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm); ! static int mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type); ! static void mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb); ! static void mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb); ! static void mpssas_scanner_thread(void *arg); ! #if __FreeBSD_version >= 1000006 ! static void mpssas_async(void *callback_arg, uint32_t code, ! struct cam_path *path, void *arg); ! #else ! static void mpssas_check_eedp(struct mpssas_softc *sassc); ! static void mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb); ! #endif ! static int mpssas_send_portenable(struct mps_softc *sc); ! static void mpssas_portenable_complete(struct mps_softc *sc, ! struct mps_command *cm); ! static struct mpssas_target * ! mpssas_find_target_by_handle(struct mpssas_softc *sassc, int start, uint16_t handle) { ! struct mpssas_target *target; ! int i; ! for (i = start; i < sassc->sc->facts->MaxTargets; i++) { ! target = &sassc->targets[i]; ! if (target->handle == handle) ! return (target); } ! return (NULL); } ! /* we need to freeze the simq during attach and diag reset, to avoid failing ! * commands before device handles have been found by discovery. Since ! * discovery involves reading config pages and possibly sending commands, ! * discovery actions may continue even after we receive the end of discovery ! * event, so refcount discovery actions instead of assuming we can unfreeze ! * the simq when we get the event. ! */ ! void ! mpssas_startup_increment(struct mpssas_softc *sassc) { ! if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { ! if (sassc->startup_refcount++ == 0) { ! /* just starting, freeze the simq */ ! mps_dprint(sassc->sc, MPS_INFO, ! "%s freezing simq\n", __func__); ! xpt_freeze_simq(sassc->sim, 1); ! } ! mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__, ! sassc->startup_refcount); ! } ! } ! void ! mpssas_startup_decrement(struct mpssas_softc *sassc) ! { ! if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { ! if (--sassc->startup_refcount == 0) { ! /* finished all discovery-related actions, release ! * the simq and rescan for the latest topology. ! */ ! mps_dprint(sassc->sc, MPS_INFO, ! "%s releasing simq\n", __func__); ! sassc->flags &= ~MPSSAS_IN_STARTUP; ! xpt_release_simq(sassc->sim, 1); ! mpssas_rescan_target(sassc->sc, NULL); ! } ! mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__, ! sassc->startup_refcount); } + } ! /* LSI's firmware requires us to stop sending commands when we're doing task ! * management, so refcount the TMs and keep the simq frozen when any are in ! * use. ! */ ! struct mps_command * ! mpssas_alloc_tm(struct mps_softc *sc) ! { ! struct mps_command *tm; ! tm = mps_alloc_high_priority_command(sc); ! if (tm != NULL) { ! if (sc->sassc->tm_count++ == 0) { ! mps_printf(sc, "%s freezing simq\n", __func__); ! xpt_freeze_simq(sc->sassc->sim, 1); ! } ! mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__, ! sc->sassc->tm_count); ! } ! return tm; } ! void ! mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm) { ! if (tm == NULL) ! return; ! /* if there are no TMs in use, we can release the simq. We use our ! * own refcount so that it's easier for a diag reset to cleanup and ! * release the simq. ! */ ! if (--sc->sassc->tm_count == 0) { ! mps_printf(sc, "%s releasing simq\n", __func__); ! xpt_release_simq(sc->sassc->sim, 1); } + mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__, + sc->sassc->tm_count); ! mps_free_high_priority_command(sc, tm); } ! ! void ! mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ) { ! struct mpssas_softc *sassc = sc->sassc; ! path_id_t pathid; ! target_id_t targetid; ! union ccb *ccb; ! pathid = cam_sim_path(sassc->sim); ! if (targ == NULL) ! targetid = CAM_TARGET_WILDCARD; ! else ! targetid = targ - sassc->targets; ! /* ! * Allocate a CCB and schedule a rescan. ! */ ! ccb = xpt_alloc_ccb_nowait(); ! if (ccb == NULL) { ! mps_dprint(sc, MPS_FAULT, "unable to alloc CCB for rescan\n"); return; } ! if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, pathid, ! targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { ! mps_dprint(sc, MPS_FAULT, "unable to create path for rescan\n"); ! xpt_free_ccb(ccb); return; } + + /* XXX Hardwired to scan the bus for now */ + ccb->ccb_h.func_code = XPT_SCAN_BUS; + mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid); + mpssas_rescan(sassc, ccb); } static void ! mpssas_log_command(struct mps_command *cm, const char *fmt, ...) { ! struct sbuf sb; ! va_list ap; ! char str[192]; ! char path_str[64]; ! if (cm == NULL) ! return; ! sbuf_new(&sb, str, sizeof(str), 0); ! va_start(ap, fmt); ! if (cm->cm_ccb != NULL) { ! xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, ! sizeof(path_str)); ! sbuf_cat(&sb, path_str); ! if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { ! scsi_command_string(&cm->cm_ccb->csio, &sb); ! sbuf_printf(&sb, "length %d ", ! cm->cm_ccb->csio.dxfer_len); } ! } ! else { ! sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", ! cam_sim_name(cm->cm_sc->sassc->sim), ! cam_sim_unit(cm->cm_sc->sassc->sim), ! cam_sim_bus(cm->cm_sc->sassc->sim), ! cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, ! cm->cm_lun); } ! sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); ! sbuf_vprintf(&sb, fmt, ap); ! sbuf_finish(&sb); ! printf("%s", sbuf_data(&sb)); ! va_end(ap); ! } ! static void ! mpssas_lost_target(struct mps_softc *sc, struct mpssas_target *targ) ! { ! struct mpssas_softc *sassc = sc->sassc; ! path_id_t pathid = cam_sim_path(sassc->sim); ! struct cam_path *path; ! mps_printf(sc, "%s targetid %u\n", __func__, targ->tid); ! if (xpt_create_path(&path, NULL, pathid, targ->tid, 0) != CAM_REQ_CMP) { ! mps_printf(sc, "unable to create path for lost target %d\n", ! targ->tid); ! return; ! } ! xpt_async(AC_LOST_DEVICE, path, NULL); ! xpt_free_path(path); } /* ! * The MPT2 firmware performs debounce on the link to avoid transient link ! * errors and false removals. When it does decide that link has been lost ! * and a device need to go away, it expects that the host will perform a ! * target reset and then an op remove. The reset has the side-effect of ! * aborting any outstanding requests for the device, which is required for ! * the op-remove to succeed. It's not clear if the host should check for ! * the device coming back alive after the reset. */ ! void ! mpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; struct mps_softc *sc; struct mps_command *cm; struct mpssas_target *targ = NULL; mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); ! /* ! * If this is a WD controller, determine if the disk should be exposed ! * to the OS or not. If disk should be exposed, return from this ! * function without doing anything. ! */ ! sc = sassc->sc; ! if ((sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) && (sc->WD_hide_expose == ! MPS_WD_EXPOSE_ALWAYS)) { ! return; ! } ! ! targ = mpssas_find_target_by_handle(sassc, 0, handle); ! if (targ == NULL) { ! /* FIXME: what is the action? */ /* We don't know about this device? */ + printf("%s: invalid handle 0x%x \n", __func__, handle); return; + } + + targ->flags |= MPSSAS_TARGET_INREMOVAL; ! cm = mpssas_alloc_tm(sc); if (cm == NULL) { ! mps_printf(sc, "%s: command alloc failure\n", __func__); return; } ! mpssas_lost_target(sc, targ); req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; memset(req, 0, sizeof(*req)); *************** *** 497,511 **** /* SAS Hard Link Reset / SATA Link Reset */ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; cm->cm_data = NULL; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_complete = mpssas_remove_device; ! cm->cm_targ = targ; ! mpssas_issue_tm_request(sc, cm); } static void ! mpssas_remove_device(struct mps_softc *sc, struct mps_command *cm) { MPI2_SCSI_TASK_MANAGE_REPLY *reply; MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; --- 426,441 ---- /* SAS Hard Link Reset / SATA Link Reset */ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + cm->cm_targ = targ; cm->cm_data = NULL; ! cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; cm->cm_complete = mpssas_remove_device; ! cm->cm_complete_data = (void *)(uintptr_t)handle; ! mps_map_command(sc, cm); } static void ! mpssas_remove_device(struct mps_softc *sc, struct mps_command *tm) { MPI2_SCSI_TASK_MANAGE_REPLY *reply; MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; *************** *** 515,664 **** mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; ! handle = cm->cm_targ->handle; ! ! mpssas_complete_tm_request(sc, cm, /*free_cm*/ 0); /* * Currently there should be no way we can hit this case. It only * happens when we have a failure to allocate chain frames, and * task management commands don't have S/G lists. */ ! if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! " ! "This should not happen!\n", __func__, cm->cm_flags, handle); return; } if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { ! mps_printf(sc, "Failure 0x%x reseting device 0x%04x\n", reply->IOCStatus, handle); ! mps_free_command(sc, cm); return; } mps_dprint(sc, MPS_INFO, "Reset aborted %u commands\n", reply->TerminationCount); ! mps_free_reply(sc, cm->cm_reply_data); /* Reuse the existing command */ ! req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)cm->cm_req; memset(req, 0, sizeof(*req)); req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; req->DevHandle = handle; ! cm->cm_data = NULL; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! cm->cm_flags &= ~MPS_CM_FLAGS_COMPLETE; ! cm->cm_complete = mpssas_remove_complete; ! mps_map_command(sc, cm); ! mps_dprint(sc, MPS_INFO, "clearing target handle 0x%04x\n", handle); ! TAILQ_FOREACH_SAFE(cm, &sc->io_list, cm_link, next_cm) { union ccb *ccb; ! if (cm->cm_targ->handle != handle) ! continue; ! ! mps_dprint(sc, MPS_INFO, "Completing missed command %p\n", cm); ! ccb = cm->cm_complete_data; ccb->ccb_h.status = CAM_DEV_NOT_THERE; ! mpssas_scsiio_complete(sc, cm); ! } ! targ = mpssas_find_target(sc->sassc, 0, handle); ! if (targ != NULL) { ! targ->handle = 0x0; ! mpssas_announce_device(sc->sassc, targ); } } static void ! mpssas_remove_complete(struct mps_softc *sc, struct mps_command *cm) { MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)cm->cm_reply; ! mps_printf(sc, "mpssas_remove_complete on target 0x%04x," ! " IOCStatus= 0x%x\n", cm->cm_targ->tid, reply->IOCStatus); ! mps_free_command(sc, cm); ! } ! ! static void ! mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, ! MPI2_EVENT_NOTIFICATION_REPLY *event) ! { ! struct mpssas_softc *sassc; ! ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! ! sassc = sc->sassc; ! mps_print_evt_sas(sc, event); ! ! switch (event->Event) { ! case MPI2_EVENT_SAS_DISCOVERY: ! { ! MPI2_EVENT_DATA_SAS_DISCOVERY *data; ! ! data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData; ! ! if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) ! mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n"); ! if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { ! mps_dprint(sc, MPS_TRACE, "SAS discovery end event\n"); ! sassc->flags &= ~MPSSAS_IN_DISCOVERY; ! mpssas_discovery_end(sassc); ! } ! break; } - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - { - MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; - MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; - int i; ! data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) ! &event->EventData; ! if (data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) { ! if (bootverbose) ! printf("Expander found at enclosure %d\n", ! data->EnclosureHandle); ! mpssas_probe_device(sc, data->ExpanderDevHandle); ! } ! ! for (i = 0; i < data->NumEntries; i++) { ! phy = &data->PHY[i]; ! switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { ! case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: ! mpssas_probe_device(sc, phy->AttachedDevHandle); ! break; ! case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: ! mpssas_prepare_remove(sassc, phy); ! break; ! case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: ! case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: ! case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: ! default: ! break; ! } ! } ! ! break; } - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - break; - default: - break; - } ! mps_free_reply(sc, data); } static int --- 445,566 ---- mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; ! handle = (uint16_t)(uintptr_t)tm->cm_complete_data; ! targ = tm->cm_targ; /* * Currently there should be no way we can hit this case. It only * happens when we have a failure to allocate chain frames, and * task management commands don't have S/G lists. */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! " ! "This should not happen!\n", __func__, tm->cm_flags, handle); + mpssas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + /* XXX retry the remove after the diag reset completes? */ + mps_printf(sc, "%s NULL reply reseting device 0x%04x\n", + __func__, handle); + mpssas_free_tm(sc, tm); return; } if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { ! mps_printf(sc, "IOCStatus = 0x%x while resetting device 0x%x\n", reply->IOCStatus, handle); ! mpssas_free_tm(sc, tm); return; } mps_dprint(sc, MPS_INFO, "Reset aborted %u commands\n", reply->TerminationCount); ! mps_free_reply(sc, tm->cm_reply_data); ! tm->cm_reply = NULL; /* Ensures the the reply won't get re-freed */ /* Reuse the existing command */ ! req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; memset(req, 0, sizeof(*req)); req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; req->DevHandle = handle; ! tm->cm_data = NULL; ! tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! tm->cm_complete = mpssas_remove_complete; ! tm->cm_complete_data = (void *)(uintptr_t)handle; ! mps_map_command(sc, tm); ! mps_dprint(sc, MPS_INFO, "clearing target %u handle 0x%04x\n", ! targ->tid, handle); ! TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { union ccb *ccb; ! mps_dprint(sc, MPS_INFO, "Completing missed command %p\n", tm); ! ccb = tm->cm_complete_data; ccb->ccb_h.status = CAM_DEV_NOT_THERE; ! mpssas_scsiio_complete(sc, tm); } } static void ! mpssas_remove_complete(struct mps_softc *sc, struct mps_command *tm) { MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; + uint16_t handle; + struct mpssas_target *targ; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; ! handle = (uint16_t)(uintptr_t)tm->cm_complete_data; ! /* ! * Currently there should be no way we can hit this case. It only ! * happens when we have a failure to allocate chain frames, and ! * task management commands don't have S/G lists. ! */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { ! mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! " ! "This should not happen!\n", __func__, tm->cm_flags, ! handle); ! mpssas_free_tm(sc, tm); ! return; ! } ! if (reply == NULL) { ! /* most likely a chip reset */ ! mps_printf(sc, "%s NULL reply removing device 0x%04x\n", ! __func__, handle); ! mpssas_free_tm(sc, tm); ! return; } ! mps_printf(sc, "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__, ! handle, reply->IOCStatus); ! /* ! * Don't clear target if remove fails because things will get confusing. ! * Leave the devname and sasaddr intact so that we know to avoid reusing ! * this target id if possible, and so we can assign the same target id ! * to this device if it comes back in the future. ! */ ! if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) { ! targ = tm->cm_targ; ! targ->handle = 0x0; ! targ->encl_handle = 0x0; ! targ->encl_slot = 0x0; ! targ->exp_dev_handle = 0x0; ! targ->phy_num = 0x0; ! targ->linkrate = 0x0; ! targ->devinfo = 0x0; } ! mpssas_free_tm(sc, tm); } static int *************** *** 674,679 **** --- 576,586 ---- setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); + setbit(events, MPI2_EVENT_IR_VOLUME); + setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); + setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); + setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); mps_register_events(sc, events, mpssas_evt_handler, NULL, &sc->sassc->mpssas_eh); *************** *** 685,692 **** mps_attach_sas(struct mps_softc *sc) { struct mpssas_softc *sassc; ! int error = 0; ! int num_sim_reqs; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); --- 592,601 ---- mps_attach_sas(struct mps_softc *sc) { struct mpssas_softc *sassc; ! #if __FreeBSD_version >= 1000006 ! cam_status status; ! #endif ! int unit, error = 0; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); *************** *** 696,737 **** sc->sassc = sassc; sassc->sc = sc; ! /* ! * Tell CAM that we can handle 5 fewer requests than we have ! * allocated. If we allow the full number of requests, all I/O ! * will halt when we run out of resources. Things work fine with ! * just 1 less request slot given to CAM than we have allocated. ! * We also need a couple of extra commands so that we can send down ! * abort, reset, etc. requests when commands time out. Otherwise ! * we could wind up in a situation with sc->num_reqs requests down ! * on the card and no way to send an abort. ! * ! * XXX KDM need to figure out why I/O locks up if all commands are ! * used. ! */ ! num_sim_reqs = sc->num_reqs - 5; ! ! if ((sassc->devq = cam_simq_alloc(num_sim_reqs)) == NULL) { mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n"); error = ENOMEM; goto out; } sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc, ! device_get_unit(sc->mps_dev), &sc->mps_mtx, num_sim_reqs, ! num_sim_reqs, sassc->devq); if (sassc->sim == NULL) { mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n"); error = EINVAL; goto out; } /* * XXX There should be a bus for every port on the adapter, but since * we're just going to fake the topology for now, we'll pretend that * everything is just a target on a single bus. */ - mps_lock(sc); if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) { mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n", error); --- 605,652 ---- sc->sassc = sassc; sassc->sc = sc; ! if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n"); error = ENOMEM; goto out; } + unit = device_get_unit(sc->mps_dev); sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc, ! unit, &sc->mps_mtx, sc->num_reqs, sc->num_reqs, sassc->devq); if (sassc->sim == NULL) { mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n"); error = EINVAL; goto out; } + TAILQ_INIT(&sassc->ev_queue); + + /* Initialize taskqueue for Event Handling */ + TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc); + sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &sassc->ev_tq); + + /* Run the task queue with lowest priority */ + taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq", + device_get_nameunit(sc->mps_dev)); + + TAILQ_INIT(&sassc->ccb_scanq); + error = mps_kproc_create(mpssas_scanner_thread, sassc, + &sassc->rescan_thread, 0, 0, "mps_scan%d", unit); + if (error) { + mps_printf(sc, "Error %d starting rescan thread\n", error); + goto out; + } + + mps_lock(sc); + sassc->flags |= MPSSAS_SCANTHREAD; + /* * XXX There should be a bus for every port on the adapter, but since * we're just going to fake the topology for now, we'll pretend that * everything is just a target on a single bus. */ if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) { mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n", error); *************** *** 744,757 **** * the simq will prevent the CAM boottime scanner from running * before discovery is complete. */ ! sassc->flags = MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY; xpt_freeze_simq(sassc->sim, 1); ! ! mps_unlock(sc); callout_init(&sassc->discovery_callout, 1 /*mpsafe*/); sassc->discovery_timeouts = 0; mpssas_register_events(sc); out: if (error) --- 659,683 ---- * the simq will prevent the CAM boottime scanner from running * before discovery is complete. */ ! sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY; xpt_freeze_simq(sassc->sim, 1); ! sc->sassc->startup_refcount = 0; callout_init(&sassc->discovery_callout, 1 /*mpsafe*/); sassc->discovery_timeouts = 0; + sassc->tm_count = 0; + + #if __FreeBSD_version >= 1000006 + status = xpt_register_async(AC_ADVINFO_CHANGED, mpssas_async, sc, NULL); + if (status != CAM_REQ_CMP) { + mps_printf(sc, "Error %#x registering async handler for " + "AC_ADVINFO_CHANGED events\n", status); + } + #endif + + mps_unlock(sc); + mpssas_register_events(sc); out: if (error) *************** *** 770,791 **** return (0); sassc = sc->sassc; /* Make sure CAM doesn't wedge if we had to bail out early. */ mps_lock(sc); if (sassc->flags & MPSSAS_IN_STARTUP) xpt_release_simq(sassc->sim, 1); - mps_unlock(sc); - if (sassc->mpssas_eh != NULL) - mps_deregister_events(sc, sassc->mpssas_eh); - - mps_lock(sc); - if (sassc->sim != NULL) { xpt_bus_deregister(cam_sim_path(sassc->sim)); cam_sim_free(sassc->sim, FALSE); } mps_unlock(sc); if (sassc->devq != NULL) --- 696,736 ---- return (0); sassc = sc->sassc; + mps_deregister_events(sc, sassc->mpssas_eh); + /* + * Drain and free the event handling taskqueue with the lock + * unheld so that any parallel processing tasks drain properly + * without deadlocking. + */ + if (sassc->ev_tq != NULL) + taskqueue_free(sassc->ev_tq); + /* Make sure CAM doesn't wedge if we had to bail out early. */ mps_lock(sc); + + /* Deregister our async handler */ + #if __FreeBSD_version >= 1000006 + xpt_register_async(0, mpssas_async, sc, NULL); + #endif + if (sassc->flags & MPSSAS_IN_STARTUP) xpt_release_simq(sassc->sim, 1); if (sassc->sim != NULL) { xpt_bus_deregister(cam_sim_path(sassc->sim)); cam_sim_free(sassc->sim, FALSE); } + + if (sassc->flags & MPSSAS_SCANTHREAD) { + sassc->flags |= MPSSAS_SHUTDOWN; + wakeup(&sassc->ccb_scanq); + + if (sassc->flags & MPSSAS_SCANTHREAD) { + msleep(&sassc->flags, &sc->mps_mtx, PRIBIO, + "mps_shutdown", 30 * hz); + } + } mps_unlock(sc); if (sassc->devq != NULL) *************** *** 798,804 **** return (0); } ! static void mpssas_discovery_end(struct mpssas_softc *sassc) { struct mps_softc *sc = sassc->sc; --- 743,749 ---- return (0); } ! void mpssas_discovery_end(struct mpssas_softc *sassc) { struct mps_softc *sc = sassc->sc; *************** *** 808,866 **** if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING) callout_stop(&sassc->discovery_callout); - if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { - mps_dprint(sc, MPS_INFO, - "mpssas_discovery_end: removing confighook\n"); - sassc->flags &= ~MPSSAS_IN_STARTUP; - xpt_release_simq(sassc->sim, 1); - } - #if 0 - mpssas_announce_device(sassc, NULL); - #endif - } static void ! mpssas_announce_device(struct mpssas_softc *sassc, struct mpssas_target *targ) { ! union ccb *ccb; ! int bus, tid, lun; ! /* ! * Force a rescan, a hackish way to announce devices. ! * XXX Doing a scan on an individual device is hackish in that it ! * won't scan the LUNs. ! * XXX Does it matter if any of this fails? ! */ ! bus = cam_sim_path(sassc->sim); ! if (targ != NULL) { ! tid = targ->tid; ! lun = 0; ! } else { ! tid = CAM_TARGET_WILDCARD; ! lun = CAM_LUN_WILDCARD; ! } ! ccb = xpt_alloc_ccb_nowait(); ! if (ccb == NULL) ! return; ! if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, bus, tid, ! CAM_LUN_WILDCARD) != CAM_REQ_CMP) { ! xpt_free_ccb(ccb); ! return; ! } ! mps_dprint(sassc->sc, MPS_INFO, "Triggering rescan of %d:%d:-1\n", ! bus, tid); ! xpt_rescan(ccb); ! } ! static void ! mpssas_startup(void *data) ! { ! struct mpssas_softc *sassc = data; ! mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); - mps_lock(sassc->sc); if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) { mpssas_discovery_end(sassc); } else { --- 753,780 ---- if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING) callout_stop(&sassc->discovery_callout); } static void ! mpssas_discovery_timeout(void *data) { ! struct mpssas_softc *sassc = data; ! struct mps_softc *sc; ! ! sc = sassc->sc; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! mps_lock(sc); ! mps_printf(sc, ! "Timeout waiting for discovery, interrupts may not be working!\n"); ! sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING; ! /* Poll the hardware for events in case interrupts aren't working */ ! mps_intr_locked(sc); ! mps_printf(sassc->sc, ! "Finished polling after discovery timeout at %d\n", ticks); if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) { mpssas_discovery_end(sassc); } else { *************** *** 877,907 **** mpssas_discovery_end(sassc); } } - mps_unlock(sassc->sc); - return; - } - - static void - mpssas_discovery_timeout(void *data) - { - struct mpssas_softc *sassc = data; - struct mps_softc *sc; - - sc = sassc->sc; - mps_dprint(sc, MPS_TRACE, "%s\n", __func__); - - mps_lock(sc); - mps_printf(sc, - "Timeout waiting for discovery, interrupts may not be working!\n"); - sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING; - - /* Poll the hardware for events in case interrupts aren't working */ - mps_intr_locked(sc); mps_unlock(sc); - - /* Check the status of discovery and re-arm the timeout if needed */ - mpssas_startup(sassc); } static void --- 791,798 ---- *************** *** 911,918 **** sassc = cam_sim_softc(sim); ! mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__, ccb->ccb_h.func_code); switch (ccb->ccb_h.func_code) { case XPT_PATH_INQ: --- 802,810 ---- sassc = cam_sim_softc(sim); ! mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__, ccb->ccb_h.func_code); + mtx_assert(&sassc->sc->mps_mtx, MA_OWNED); switch (ccb->ccb_h.func_code) { case XPT_PATH_INQ: *************** *** 925,931 **** cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; cpi->max_target = sassc->sc->facts->MaxTargets - 1; ! cpi->max_lun = 8; cpi->initiator_id = 255; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); --- 817,823 ---- cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; cpi->max_target = sassc->sc->facts->MaxTargets - 1; ! cpi->max_lun = 0; cpi->initiator_id = 255; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); *************** *** 937,943 **** cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC; ! cpi->maxio = MAXPHYS; cpi->ccb_h.status = CAM_REQ_CMP; break; } --- 829,840 ---- cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC; ! #if __FreeBSD_version >= 800001 ! /* ! * XXX KDM where does this number come from? ! */ ! cpi->maxio = 256 * 1024; ! #endif cpi->ccb_h.status = CAM_REQ_CMP; break; } *************** *** 989,999 **** --- 886,899 ---- ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_RESET_DEV: + mps_printf(sassc->sc, "mpssas_action XPT_RESET_DEV\n"); mpssas_action_resetdev(sassc, ccb); return; case XPT_RESET_BUS: case XPT_ABORT: case XPT_TERM_IO: + mps_printf(sassc->sc, "mpssas_action faking success for " + "abort or reset\n"); ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_SCSI_IO: *************** *** 1003,1009 **** case XPT_SMP_IO: mpssas_action_smpio(sassc, ccb); return; ! #endif /* __FreeBSD_version >= 900026 */ default: ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; break; --- 903,909 ---- case XPT_SMP_IO: mpssas_action_smpio(sassc, ccb); return; ! #endif default: ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; break; *************** *** 1012,1360 **** } - #if 0 static void ! mpssas_resettimeout_complete(struct mps_softc *sc, struct mps_command *cm) { ! MPI2_SCSI_TASK_MANAGE_REPLY *resp; ! uint16_t code; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; ! code = resp->ResponseCode; ! ! mps_free_command(sc, cm); ! mpssas_unfreeze_device(sassc, targ); ! ! if (code != MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { ! mps_reset_controller(sc); } ! return; } - #endif ! static void ! mpssas_scsiio_timeout(void *data) { - union ccb *ccb; - struct mps_softc *sc; struct mps_command *cm; ! struct mpssas_target *targ; ! #if 0 ! char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; ! #endif ! cm = (struct mps_command *)data; ! sc = cm->cm_sc; ! /* ! * Run the interrupt handler to make sure it's not pending. This ! * isn't perfect because the command could have already completed ! * and been re-used, though this is unlikely. */ ! mps_lock(sc); ! mps_intr_locked(sc); ! if (cm->cm_state == MPS_CM_STATE_FREE) { ! mps_unlock(sc); ! return; ! } ! ccb = cm->cm_complete_data; ! targ = cm->cm_targ; ! if (targ == 0x00) ! /* Driver bug */ ! targ = &sc->sassc->targets[ccb->ccb_h.target_id]; - xpt_print(ccb->ccb_h.path, "SCSI command timeout on device handle " - "0x%04x SMID %d\n", targ->handle, cm->cm_desc.Default.SMID); /* ! * XXX KDM this is useful for debugging purposes, but the existing ! * scsi_op_desc() implementation can't handle a NULL value for ! * inq_data. So this will remain commented out until I bring in ! * those changes as well. */ ! #if 0 ! xpt_print(ccb->ccb_h.path, "Timed out command: %s. CDB %s\n", ! scsi_op_desc((ccb->ccb_h.flags & CAM_CDB_POINTER) ? ! ccb->csio.cdb_io.cdb_ptr[0] : ! ccb->csio.cdb_io.cdb_bytes[0], NULL), ! scsi_cdb_string((ccb->ccb_h.flags & CAM_CDB_POINTER) ? ! ccb->csio.cdb_io.cdb_ptr : ! ccb->csio.cdb_io.cdb_bytes, cdb_str, ! sizeof(cdb_str))); ! #endif ! /* Inform CAM about the timeout and that recovery is starting. */ ! #if 0 ! if ((targ->flags & MPSSAS_TARGET_INRECOVERY) == 0) { ! mpssas_freeze_device(sc->sassc, targ); ! ccb->ccb_h.status = CAM_CMD_TIMEOUT; ! xpt_done(ccb); } ! #endif ! mpssas_freeze_device(sc->sassc, targ); ! ccb->ccb_h.status = CAM_CMD_TIMEOUT; ! /* ! * recycle the command into recovery so that there's no risk of ! * command allocation failure. ! */ ! cm->cm_state = MPS_CM_STATE_TIMEDOUT; ! mpssas_recovery(sc, cm); ! mps_unlock(sc); } static void ! mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; /* * Currently there should be no way we can hit this case. It only * happens when we have a failure to allocate chain frames, and * task management commands don't have S/G lists. */ ! if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { ! mps_printf(sc, "%s: cm_flags = %#x for abort on handle %#04x! " ! "This should not happen!\n", __func__, cm->cm_flags, ! req->DevHandle); } ! mps_printf(sc, "%s: abort request on handle %#04x SMID %d " ! "complete\n", __func__, req->DevHandle, req->TaskMID); ! mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1); } static void ! mpssas_recovery(struct mps_softc *sc, struct mps_command *abort_cm) { ! struct mps_command *cm; ! MPI2_SCSI_TASK_MANAGE_REQUEST *req, *orig_req; ! cm = mps_alloc_command(sc); ! if (cm == NULL) { ! mps_printf(sc, "%s: command allocation failure\n", __func__); return; } ! cm->cm_targ = abort_cm->cm_targ; ! cm->cm_complete = mpssas_abort_complete; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; ! orig_req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)abort_cm->cm_req; ! req->DevHandle = abort_cm->cm_targ->handle; ! req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; ! req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; ! memcpy(req->LUN, orig_req->LUN, sizeof(req->LUN)); ! req->TaskMID = abort_cm->cm_desc.Default.SMID; ! cm->cm_data = NULL; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! mpssas_issue_tm_request(sc, cm); } ! /* ! * Can return 0 or EINPROGRESS on success. Any other value means failure. ! */ static int ! mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm) { ! int error; ! error = 0; ! cm->cm_flags |= MPS_CM_FLAGS_ACTIVE; ! error = mps_map_command(sc, cm); ! if ((error == 0) ! || (error == EINPROGRESS)) ! sc->tm_cmds_active++; ! return (error); } static void ! mpssas_issue_tm_request(struct mps_softc *sc, struct mps_command *cm) { ! int freeze_queue, send_command, error; ! freeze_queue = 0; ! send_command = 0; ! error = 0; ! mtx_assert(&sc->mps_mtx, MA_OWNED); /* ! * If there are no other pending task management commands, go ! * ahead and send this one. There is a small amount of anecdotal ! * evidence that sending lots of task management commands at once ! * may cause the controller to lock up. Or, if the user has ! * configured the driver (via the allow_multiple_tm_cmds variable) to ! * not serialize task management commands, go ahead and send the ! * command if even other task management commands are pending. */ ! if (TAILQ_FIRST(&sc->tm_list) == NULL) { ! send_command = 1; ! freeze_queue = 1; ! } else if (sc->allow_multiple_tm_cmds != 0) ! send_command = 1; ! TAILQ_INSERT_TAIL(&sc->tm_list, cm, cm_link); ! if (send_command != 0) { ! /* ! * Freeze the SIM queue while we issue the task management ! * command. According to the Fusion-MPT 2.0 spec, task ! * management requests are serialized, and so the host ! * should not send any I/O requests while task management ! * requests are pending. */ ! if (freeze_queue != 0) ! xpt_freeze_simq(sc->sassc->sim, 1); ! error = mpssas_map_tm_request(sc, cm); ! /* ! * At present, there is no error path back from ! * mpssas_map_tm_request() (which calls mps_map_command()) ! * when cm->cm_data == NULL. But since there is a return ! * value, we check it just in case the implementation ! * changes later. ! */ ! if ((error != 0) ! && (error != EINPROGRESS)) ! mpssas_tm_complete(sc, cm, ! MPI2_SCSITASKMGMT_RSP_TM_FAILED); } } ! static void ! mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, int error) { ! MPI2_SCSI_TASK_MANAGE_REPLY *resp; ! resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; ! if (resp != NULL) ! resp->ResponseCode = error; ! /* ! * Call the callback for this command, it will be ! * removed from the list and freed via the callback. ! */ ! cm->cm_complete(sc, cm); } ! /* ! * Complete a task management request. The basic completion operation will ! * always succeed. Returns status for sending any further task management ! * commands that were queued. ! */ ! static int ! mpssas_complete_tm_request(struct mps_softc *sc, struct mps_command *cm, ! int free_cm) { ! int error; ! error = 0; mtx_assert(&sc->mps_mtx, MA_OWNED); ! TAILQ_REMOVE(&sc->tm_list, cm, cm_link); ! cm->cm_flags &= ~MPS_CM_FLAGS_ACTIVE; ! sc->tm_cmds_active--; ! if (free_cm != 0) ! mps_free_command(sc, cm); ! if (TAILQ_FIRST(&sc->tm_list) == NULL) { ! /* ! * Release the SIM queue, we froze it when we sent the first ! * task management request. ! */ ! xpt_release_simq(sc->sassc->sim, 1); ! } else if ((sc->tm_cmds_active == 0) ! || (sc->allow_multiple_tm_cmds != 0)) { ! int error; ! struct mps_command *cm2; ! restart_traversal: ! /* ! * We don't bother using TAILQ_FOREACH_SAFE here, but ! * rather use the standard version and just restart the ! * list traversal if we run into the error case. ! * TAILQ_FOREACH_SAFE allows safe removal of the current ! * list element, but if you have a queue of task management ! * commands, all of which have mapping errors, you'll end ! * up with recursive calls to this routine and so you could ! * wind up removing more than just the current list element. ! */ ! TAILQ_FOREACH(cm2, &sc->tm_list, cm_link) { ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! /* This command is active, no need to send it again */ ! if (cm2->cm_flags & MPS_CM_FLAGS_ACTIVE) ! continue; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm2->cm_req; ! mps_printf(sc, "%s: sending deferred task management " ! "request for handle %#04x SMID %d\n", __func__, ! req->DevHandle, req->TaskMID); ! error = mpssas_map_tm_request(sc, cm2); ! ! /* ! * Check for errors. If we had an error, complete ! * this command with an error, and keep going through ! * the list until we are able to send at least one ! * command or all of them are completed with errors. ! * ! * We don't want to wind up in a situation where ! * we're stalled out with no way for queued task ! * management commands to complete. ! * ! * Note that there is not currently an error path ! * back from mpssas_map_tm_request() (which calls ! * mps_map_command()) when cm->cm_data == NULL. ! * But we still want to check for errors here in ! * case the implementation changes, or in case ! * there is some reason for a data payload here. ! */ ! if ((error != 0) ! && (error != EINPROGRESS)) { ! mpssas_tm_complete(sc, cm, ! MPI2_SCSITASKMGMT_RSP_TM_FAILED); ! ! /* ! * If we don't currently have any commands ! * active, go back to the beginning and see ! * if there are any more that can be started. ! * Otherwise, we're done here. ! */ ! if (sc->tm_cmds_active == 0) ! goto restart_traversal; ! else ! break; ! } ! ! /* ! * If the user only wants one task management command ! * active at a time, we're done, since we've ! * already successfully sent a command at this point. ! */ ! if (sc->allow_multiple_tm_cmds == 0) ! break; ! } } - return (error); } static void --- 912,1465 ---- } static void ! mpssas_announce_reset(struct mps_softc *sc, uint32_t ac_code, ! target_id_t target_id, lun_id_t lun_id) { ! path_id_t path_id = cam_sim_path(sc->sassc->sim); ! struct cam_path *path; ! mps_printf(sc, "%s code %x target %d lun %d\n", __func__, ! ac_code, target_id, lun_id); ! if (xpt_create_path(&path, NULL, ! path_id, target_id, lun_id) != CAM_REQ_CMP) { ! mps_printf(sc, "unable to create path for reset " ! "notification\n"); ! return; } ! xpt_async(ac_code, path, NULL); ! xpt_free_path(path); } ! static void ! mpssas_complete_all_commands(struct mps_softc *sc) { struct mps_command *cm; ! int i; ! int completed; ! ! mps_printf(sc, "%s\n", __func__); ! mtx_assert(&sc->mps_mtx, MA_OWNED); ! ! /* complete all commands with a NULL reply */ ! for (i = 1; i < sc->num_reqs; i++) { ! cm = &sc->commands[i]; ! cm->cm_reply = NULL; ! completed = 0; ! ! if (cm->cm_flags & MPS_CM_FLAGS_POLLED) ! cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; ! ! if (cm->cm_complete != NULL) { ! mpssas_log_command(cm, ! "completing cm %p state %x ccb %p for diag reset\n", ! cm, cm->cm_state, cm->cm_ccb); ! ! cm->cm_complete(sc, cm); ! completed = 1; ! } ! ! if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) { ! mpssas_log_command(cm, ! "waking up cm %p state %x ccb %p for diag reset\n", ! cm, cm->cm_state, cm->cm_ccb); ! wakeup(cm); ! completed = 1; ! } ! ! if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) { ! /* this should never happen, but if it does, log */ ! mpssas_log_command(cm, ! "cm %p state %x flags 0x%x ccb %p during diag " ! "reset\n", cm, cm->cm_state, cm->cm_flags, ! cm->cm_ccb); ! } ! } ! } ! void ! mpssas_handle_reinit(struct mps_softc *sc) ! { ! int i; ! /* Go back into startup mode and freeze the simq, so that CAM ! * doesn't send any commands until after we've rediscovered all ! * targets and found the proper device handles for them. ! * ! * After the reset, portenable will trigger discovery, and after all ! * discovery-related activities have finished, the simq will be ! * released. */ ! mps_printf(sc, "%s startup\n", __func__); ! sc->sassc->flags |= MPSSAS_IN_STARTUP; ! sc->sassc->flags |= MPSSAS_IN_DISCOVERY; ! xpt_freeze_simq(sc->sassc->sim, 1); ! ! /* notify CAM of a bus reset */ ! mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, ! CAM_LUN_WILDCARD); ! ! /* complete and cleanup after all outstanding commands */ ! mpssas_complete_all_commands(sc); ! mps_printf(sc, "%s startup %u tm %u after command completion\n", ! __func__, sc->sassc->startup_refcount, sc->sassc->tm_count); /* ! * The simq was explicitly frozen above, so set the refcount to 0. ! * The simq will be explicitly released after port enable completes. */ ! sc->sassc->startup_refcount = 0; ! /* zero all the target handles, since they may change after the ! * reset, and we have to rediscover all the targets and use the new ! * handles. ! */ ! for (i = 0; i < sc->facts->MaxTargets; i++) { ! if (sc->sassc->targets[i].outstanding != 0) ! mps_printf(sc, "target %u outstanding %u\n", ! i, sc->sassc->targets[i].outstanding); ! sc->sassc->targets[i].handle = 0x0; ! sc->sassc->targets[i].exp_dev_handle = 0x0; ! sc->sassc->targets[i].outstanding = 0; ! sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET; } ! } ! static void ! mpssas_tm_timeout(void *data) ! { ! struct mps_command *tm = data; ! struct mps_softc *sc = tm->cm_sc; ! ! mtx_assert(&sc->mps_mtx, MA_OWNED); ! mpssas_log_command(tm, "task mgmt %p timed out\n", tm); ! mps_reinit(sc); } static void ! mpssas_logical_unit_reset_complete(struct mps_softc *sc, struct mps_command *tm) { + MPI2_SCSI_TASK_MANAGE_REPLY *reply; MPI2_SCSI_TASK_MANAGE_REQUEST *req; + unsigned int cm_count = 0; + struct mps_command *cm; + struct mpssas_target *targ; + + callout_stop(&tm->cm_callout); ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; ! targ = tm->cm_targ; /* * Currently there should be no way we can hit this case. It only * happens when we have a failure to allocate chain frames, and * task management commands don't have S/G lists. */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { ! mps_printf(sc, "%s: cm_flags = %#x for LUN reset! " ! "This should not happen!\n", __func__, tm->cm_flags); ! mpssas_free_tm(sc, tm); ! return; ! } ! ! if (reply == NULL) { ! mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm); ! if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { ! /* this completion was due to a reset, just cleanup */ ! targ->flags &= ~MPSSAS_TARGET_INRESET; ! targ->tm = NULL; ! mpssas_free_tm(sc, tm); ! } ! else { ! /* we should have gotten a reply. */ ! mps_reinit(sc); ! } ! return; ! } ! ! mpssas_log_command(tm, ! "logical unit reset status 0x%x code 0x%x count %u\n", ! reply->IOCStatus, reply->ResponseCode, ! reply->TerminationCount); ! ! /* See if there are any outstanding commands for this LUN. ! * This could be made more efficient by using a per-LU data ! * structure of some sort. ! */ ! TAILQ_FOREACH(cm, &targ->commands, cm_link) { ! if (cm->cm_lun == tm->cm_lun) ! cm_count++; } ! if (cm_count == 0) { ! mpssas_log_command(tm, ! "logical unit %u finished recovery after reset\n", ! tm->cm_lun, tm); ! ! mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, ! tm->cm_lun); ! /* we've finished recovery for this logical unit. check and ! * see if some other logical unit has a timedout command ! * that needs to be processed. ! */ ! cm = TAILQ_FIRST(&targ->timedout_commands); ! if (cm) { ! mpssas_send_abort(sc, tm, cm); ! } ! else { ! targ->tm = NULL; ! mpssas_free_tm(sc, tm); ! } ! } ! else { ! /* if we still have commands for this LUN, the reset ! * effectively failed, regardless of the status reported. ! * Escalate to a target reset. ! */ ! mpssas_log_command(tm, ! "logical unit reset complete for tm %p, but still have %u command(s)\n", ! tm, cm_count); ! mpssas_send_reset(sc, tm, ! MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); ! } } static void ! mpssas_target_reset_complete(struct mps_softc *sc, struct mps_command *tm) { ! MPI2_SCSI_TASK_MANAGE_REPLY *reply; ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! struct mpssas_target *targ; ! ! callout_stop(&tm->cm_callout); ! ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; ! targ = tm->cm_targ; ! ! /* ! * Currently there should be no way we can hit this case. It only ! * happens when we have a failure to allocate chain frames, and ! * task management commands don't have S/G lists. ! */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { ! mps_printf(sc, "%s: cm_flags = %#x for target reset! " ! "This should not happen!\n", __func__, tm->cm_flags); ! mpssas_free_tm(sc, tm); ! return; ! } ! if (reply == NULL) { ! mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm); ! if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { ! /* this completion was due to a reset, just cleanup */ ! targ->flags &= ~MPSSAS_TARGET_INRESET; ! targ->tm = NULL; ! mpssas_free_tm(sc, tm); ! } ! else { ! /* we should have gotten a reply. */ ! mps_reinit(sc); ! } return; } ! mpssas_log_command(tm, ! "target reset status 0x%x code 0x%x count %u\n", ! reply->IOCStatus, reply->ResponseCode, ! reply->TerminationCount); ! targ->flags &= ~MPSSAS_TARGET_INRESET; ! if (targ->outstanding == 0) { ! /* we've finished recovery for this target and all ! * of its logical units. ! */ ! mpssas_log_command(tm, ! "recovery finished after target reset\n"); ! mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, ! CAM_LUN_WILDCARD); + targ->tm = NULL; + mpssas_free_tm(sc, tm); + } + else { + /* after a target reset, if this target still has + * outstanding commands, the reset effectively failed, + * regardless of the status reported. escalate. + */ + mpssas_log_command(tm, + "target reset complete for tm %p, but still have %u command(s)\n", + tm, targ->outstanding); + mps_reinit(sc); + } } ! #define MPS_RESET_TIMEOUT 30 ! static int ! mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type) { ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! struct mpssas_target *target; ! int err; ! ! target = tm->cm_targ; ! if (target->handle == 0) { ! mps_printf(sc, "%s null devhandle for target_id %d\n", ! __func__, target->tid); ! return -1; ! } ! ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! req->DevHandle = target->handle; ! req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; ! req->TaskType = type; ! ! if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { ! /* XXX Need to handle invalid LUNs */ ! MPS_SET_LUN(req->LUN, tm->cm_lun); ! tm->cm_targ->logical_unit_resets++; ! mpssas_log_command(tm, "sending logical unit reset\n"); ! tm->cm_complete = mpssas_logical_unit_reset_complete; ! } ! else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { ! /* Target reset method = SAS Hard Link Reset / SATA Link Reset */ ! req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; ! tm->cm_targ->target_resets++; ! tm->cm_targ->flags |= MPSSAS_TARGET_INRESET; ! mpssas_log_command(tm, "sending target reset\n"); ! tm->cm_complete = mpssas_target_reset_complete; ! } ! else { ! mps_printf(sc, "unexpected reset type 0x%x\n", type); ! return -1; ! } ! ! tm->cm_data = NULL; ! tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; ! tm->cm_complete_data = (void *)tm; ! callout_reset(&tm->cm_callout, MPS_RESET_TIMEOUT * hz, ! mpssas_tm_timeout, tm); ! err = mps_map_command(sc, tm); ! if (err) ! mpssas_log_command(tm, ! "error %d sending reset type %u\n", ! err, type); ! return err; } + static void ! mpssas_abort_complete(struct mps_softc *sc, struct mps_command *tm) { ! struct mps_command *cm; ! MPI2_SCSI_TASK_MANAGE_REPLY *reply; ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! struct mpssas_target *targ; ! callout_stop(&tm->cm_callout); ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; ! targ = tm->cm_targ; /* ! * Currently there should be no way we can hit this case. It only ! * happens when we have a failure to allocate chain frames, and ! * task management commands don't have S/G lists. */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { ! mpssas_log_command(tm, ! "cm_flags = %#x for abort %p TaskMID %u!\n", ! tm->cm_flags, tm, req->TaskMID); ! mpssas_free_tm(sc, tm); ! return; ! } ! ! if (reply == NULL) { ! mpssas_log_command(tm, ! "NULL abort reply for tm %p TaskMID %u\n", ! tm, req->TaskMID); ! if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { ! /* this completion was due to a reset, just cleanup */ ! targ->tm = NULL; ! mpssas_free_tm(sc, tm); ! } ! else { ! /* we should have gotten a reply. */ ! mps_reinit(sc); ! } ! return; ! } ! ! mpssas_log_command(tm, ! "abort TaskMID %u status 0x%x code 0x%x count %u\n", ! req->TaskMID, ! reply->IOCStatus, reply->ResponseCode, ! reply->TerminationCount); ! cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); ! if (cm == NULL) { ! /* if there are no more timedout commands, we're done with ! * error recovery for this target. */ ! mpssas_log_command(tm, ! "finished recovery after aborting TaskMID %u\n", ! req->TaskMID); ! targ->tm = NULL; ! mpssas_free_tm(sc, tm); ! } ! else if (req->TaskMID != cm->cm_desc.Default.SMID) { ! /* abort success, but we have more timedout commands to abort */ ! mpssas_log_command(tm, ! "continuing recovery after aborting TaskMID %u\n", ! req->TaskMID); ! ! mpssas_send_abort(sc, tm, cm); ! } ! else { ! /* we didn't get a command completion, so the abort ! * failed as far as we're concerned. escalate. ! */ ! mpssas_log_command(tm, ! "abort failed for TaskMID %u tm %p\n", ! req->TaskMID, tm); ! mpssas_send_reset(sc, tm, ! MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); } } ! #define MPS_ABORT_TIMEOUT 5 ! ! static int ! mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm) { ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! struct mpssas_target *targ; ! int err; ! ! targ = cm->cm_targ; ! if (targ->handle == 0) { ! mps_printf(sc, "%s null devhandle for target_id %d\n", ! __func__, cm->cm_ccb->ccb_h.target_id); ! return -1; ! } ! ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! req->DevHandle = targ->handle; ! req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; ! req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; ! ! /* XXX Need to handle invalid LUNs */ ! MPS_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); ! ! req->TaskMID = cm->cm_desc.Default.SMID; ! ! tm->cm_data = NULL; ! tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; ! tm->cm_complete = mpssas_abort_complete; ! tm->cm_complete_data = (void *)tm; ! tm->cm_targ = cm->cm_targ; ! tm->cm_lun = cm->cm_lun; ! callout_reset(&tm->cm_callout, MPS_ABORT_TIMEOUT * hz, ! mpssas_tm_timeout, tm); ! targ->aborts++; ! err = mps_map_command(sc, tm); ! if (err) ! mpssas_log_command(tm, ! "error %d sending abort for cm %p SMID %u\n", ! err, cm, req->TaskMID); ! return err; } ! ! static void ! mpssas_scsiio_timeout(void *data) { ! struct mps_softc *sc; ! struct mps_command *cm; ! struct mpssas_target *targ; ! cm = (struct mps_command *)data; ! sc = cm->cm_sc; mtx_assert(&sc->mps_mtx, MA_OWNED); ! mps_printf(sc, "%s checking sc %p cm %p\n", __func__, sc, cm); ! /* ! * Run the interrupt handler to make sure it's not pending. This ! * isn't perfect because the command could have already completed ! * and been re-used, though this is unlikely. ! */ ! mps_intr_locked(sc); ! if (cm->cm_state == MPS_CM_STATE_FREE) { ! mps_printf(sc, "SCSI command %p sc %p almost timed out\n", cm, sc); ! return; ! } ! if (cm->cm_ccb == NULL) { ! mps_printf(sc, "command timeout with NULL ccb\n"); ! return; ! } ! mpssas_log_command(cm, "command timeout cm %p ccb %p\n", ! cm, cm->cm_ccb); ! targ = cm->cm_targ; ! targ->timeouts++; ! /* XXX first, check the firmware state, to see if it's still ! * operational. if not, do a diag reset. ! */ ! cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; ! cm->cm_state = MPS_CM_STATE_TIMEDOUT; ! TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); ! if (targ->tm != NULL) { ! /* target already in recovery, just queue up another ! * timedout command to be processed later. ! */ ! mps_printf(sc, "queued timedout cm %p for processing by tm %p\n", ! cm, targ->tm); ! } ! else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) { ! mps_printf(sc, "timedout cm %p allocated tm %p\n", ! cm, targ->tm); ! /* start recovery by aborting the first timedout command */ ! mpssas_send_abort(sc, targ->tm, cm); ! } ! else { ! /* XXX queue this target up for recovery once a TM becomes ! * available. The firmware only has a limited number of ! * HighPriority credits for the high priority requests used ! * for task management, and we ran out. ! * ! * Isilon: don't worry about this for now, since we have ! * more credits than disks in an enclosure, and limit ! * ourselves to one TM per target for recovery. ! */ ! mps_printf(sc, "timedout cm %p failed to allocate a tm\n", ! cm); } } static void *************** *** 1364,1379 **** struct ccb_scsiio *csio; struct mps_softc *sc; struct mpssas_target *targ; struct mps_command *cm; ! ! mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); sc = sassc->sc; csio = &ccb->csio; targ = &sassc->targets[csio->ccb_h.target_id]; if (targ->handle == 0x0) { ! csio->ccb_h.status = CAM_SEL_TIMEOUT; xpt_done(ccb); return; } --- 1469,1509 ---- struct ccb_scsiio *csio; struct mps_softc *sc; struct mpssas_target *targ; + struct mpssas_lun *lun; struct mps_command *cm; ! uint8_t i, lba_byte, *ref_tag_addr; ! uint16_t eedp_flags; sc = sassc->sc; + mps_dprint(sc, MPS_TRACE, "%s ccb %p\n", __func__, ccb); + mtx_assert(&sc->mps_mtx, MA_OWNED); csio = &ccb->csio; targ = &sassc->targets[csio->ccb_h.target_id]; if (targ->handle == 0x0) { ! mps_dprint(sc, MPS_TRACE, "%s NULL handle for target %u\n", ! __func__, csio->ccb_h.target_id); ! csio->ccb_h.status = CAM_TID_INVALID; ! xpt_done(ccb); ! return; ! } ! /* ! * If devinfo is 0 this will be a volume. In that case don't tell CAM ! * that the volume has timed out. We want volumes to be enumerated ! * until they are deleted/removed, not just failed. ! */ ! if (targ->flags & MPSSAS_TARGET_INREMOVAL) { ! if (targ->devinfo == 0) ! csio->ccb_h.status = CAM_REQ_CMP; ! else ! csio->ccb_h.status = CAM_SEL_TIMEOUT; ! xpt_done(ccb); ! return; ! } ! ! if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) { ! mps_dprint(sc, MPS_TRACE, "%s shutting down\n", __func__); ! csio->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } *************** *** 1446,1451 **** --- 1576,1582 ---- req->Control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; break; } + req->Control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { mps_free_command(sc, cm); *************** *** 1461,1468 **** req->IoFlags = csio->cdb_len; /* ! * XXX need to handle S/G lists and physical addresses here. */ cm->cm_data = csio->data_ptr; cm->cm_length = csio->dxfer_len; cm->cm_sge = &req->SGL; --- 1592,1648 ---- req->IoFlags = csio->cdb_len; /* ! * Check if EEDP is supported and enabled. If it is then check if the ! * SCSI opcode could be using EEDP. If so, make sure the LUN exists and ! * is formatted for EEDP support. If all of this is true, set CDB up ! * for EEDP transfer. */ + eedp_flags = op_code_prot[req->CDB.CDB32[0]]; + if (sc->eedp_enabled && eedp_flags) { + SLIST_FOREACH(lun, &targ->luns, lun_link) { + if (lun->lun_id == csio->ccb_h.target_lun) { + break; + } + } + + if ((lun != NULL) && (lun->eedp_formatted)) { + req->EEDPBlockSize = lun->eedp_block_size; + eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); + req->EEDPFlags = eedp_flags; + + /* + * If CDB less than 32, fill in Primary Ref Tag with + * low 4 bytes of LBA. If CDB is 32, tag stuff is + * already there. Also, set protection bit. FreeBSD + * currently does not support CDBs bigger than 16, but + * the code doesn't hurt, and will be here for the + * future. + */ + if (csio->cdb_len != 32) { + lba_byte = (csio->cdb_len == 16) ? 6 : 2; + ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. + PrimaryReferenceTag; + for (i = 0; i < 4; i++) { + *ref_tag_addr = + req->CDB.CDB32[lba_byte + i]; + ref_tag_addr++; + } + req->CDB.EEDP32.PrimaryApplicationTagMask = + 0xFFFF; + req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | + 0x20; + } else { + eedp_flags |= + MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; + req->EEDPFlags = eedp_flags; + req->CDB.CDB32[10] = (req->CDB.CDB32[10] & + 0x1F) | 0x20; + } + } + } + cm->cm_data = csio->data_ptr; cm->cm_length = csio->dxfer_len; cm->cm_sge = &req->SGL; *************** *** 1472,1486 **** cm->cm_complete = mpssas_scsiio_complete; cm->cm_complete_data = ccb; cm->cm_targ = targ; ! sc->io_cmds_active++; ! if (sc->io_cmds_active > sc->io_cmds_highwater) ! sc->io_cmds_highwater = sc->io_cmds_active; - TAILQ_INSERT_TAIL(&sc->io_list, cm, cm_link); callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, mpssas_scsiio_timeout, cm); mps_map_command(sc, cm); return; } --- 1652,1684 ---- cm->cm_complete = mpssas_scsiio_complete; cm->cm_complete_data = ccb; cm->cm_targ = targ; + cm->cm_lun = csio->ccb_h.target_lun; + cm->cm_ccb = ccb; ! /* ! * If HBA is a WD and the command is not for a retry, try to build a ! * direct I/O message. If failed, or the command is for a retry, send ! * the I/O to the IR volume itself. ! */ ! if (sc->WD_valid_config) { ! if (ccb->ccb_h.status != MPS_WD_RETRY) { ! mpssas_direct_drive_io(sassc, cm, ccb); ! } else { ! ccb->ccb_h.status = CAM_REQ_INPROG; ! } ! } callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, mpssas_scsiio_timeout, cm); + targ->issued++; + targ->outstanding++; + TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); + + if ((sc->mps_debug & MPS_TRACE) != 0) + mpssas_log_command(cm, "%s cm %p ccb %p outstanding %u\n", + __func__, cm, ccb, targ->outstanding); + mps_map_command(sc, cm); return; } *************** *** 1490,1508 **** { MPI2_SCSI_IO_REPLY *rep; union ccb *ccb; struct mpssas_softc *sassc; ! int dir = 0; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); callout_stop(&cm->cm_callout); ! TAILQ_REMOVE(&sc->io_list, cm, cm_link); ! sc->io_cmds_active--; sassc = sc->sassc; ccb = cm->cm_complete_data; rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; - /* * XXX KDM if the chain allocation fails, does it matter if we do * the sync and unload here? It is simpler to do it in every case, --- 1688,1712 ---- { MPI2_SCSI_IO_REPLY *rep; union ccb *ccb; + struct ccb_scsiio *csio; struct mpssas_softc *sassc; ! struct scsi_vpd_supported_page_list *vpd_list = NULL; ! u8 *TLR_bits, TLR_on; ! int dir = 0, i; ! u16 alloc_len; ! mps_dprint(sc, MPS_TRACE, ! "%s cm %p SMID %u ccb %p reply %p outstanding %u\n", ! __func__, cm, cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, ! cm->cm_targ->outstanding); callout_stop(&cm->cm_callout); ! mtx_assert(&sc->mps_mtx, MA_OWNED); sassc = sc->sassc; ccb = cm->cm_complete_data; + csio = &ccb->csio; rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; /* * XXX KDM if the chain allocation fails, does it matter if we do * the sync and unload here? It is simpler to do it in every case, *************** *** 1517,1522 **** --- 1721,1761 ---- bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); } + cm->cm_targ->completed++; + cm->cm_targ->outstanding--; + TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); + + if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) { + TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); + if (cm->cm_reply != NULL) + mpssas_log_command(cm, + "completed timedout cm %p ccb %p during recovery " + "ioc %x scsi %x state %x xfer %u\n", + cm, cm->cm_ccb, + rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, + rep->TransferCount); + else + mpssas_log_command(cm, + "completed timedout cm %p ccb %p during recovery\n", + cm, cm->cm_ccb); + } else if (cm->cm_targ->tm != NULL) { + if (cm->cm_reply != NULL) + mpssas_log_command(cm, + "completed cm %p ccb %p during recovery " + "ioc %x scsi %x state %x xfer %u\n", + cm, cm->cm_ccb, + rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, + rep->TransferCount); + else + mpssas_log_command(cm, + "completed cm %p ccb %p during recovery\n", + cm, cm->cm_ccb); + } else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { + mpssas_log_command(cm, + "reset completed cm %p ccb %p\n", + cm, cm->cm_ccb); + } + if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { /* * We ran into an error after we tried to map the command, *************** *** 1550,1565 **** /* Take the fast path to completion */ if (cm->cm_reply == NULL) { if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { ! ccb->ccb_h.status = CAM_REQ_CMP; ! ccb->csio.scsi_status = SCSI_STATUS_OK; ! if (sassc->flags & MPSSAS_QUEUE_FROZEN) { ccb->ccb_h.status |= CAM_RELEASE_SIMQ; sassc->flags &= ~MPSSAS_QUEUE_FROZEN; mps_dprint(sc, MPS_INFO, "Unfreezing SIM queue\n"); } ! } else { ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); } --- 1789,1819 ---- /* Take the fast path to completion */ if (cm->cm_reply == NULL) { if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { ! if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) ! ccb->ccb_h.status = CAM_SCSI_BUS_RESET; ! else { ! ccb->ccb_h.status = CAM_REQ_CMP; ! ccb->csio.scsi_status = SCSI_STATUS_OK; ! } if (sassc->flags & MPSSAS_QUEUE_FROZEN) { ccb->ccb_h.status |= CAM_RELEASE_SIMQ; sassc->flags &= ~MPSSAS_QUEUE_FROZEN; mps_dprint(sc, MPS_INFO, "Unfreezing SIM queue\n"); } ! } ! ! /* ! * There are two scenarios where the status won't be ! * CAM_REQ_CMP. The first is if MPS_CM_FLAGS_ERROR_MASK is ! * set, the second is in the MPS_FLAGS_DIAGRESET above. ! */ ! if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { ! /* ! * Freeze the dev queue so that commands are ! * executed in the correct order with after error ! * recovery. ! */ ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); } *************** *** 1568,1604 **** return; } ! mps_dprint(sc, MPS_INFO, "(%d:%d:%d) IOCStatus= 0x%x, " ! "ScsiStatus= 0x%x, SCSIState= 0x%x TransferCount= 0x%x\n", ! xpt_path_path_id(ccb->ccb_h.path), ! xpt_path_target_id(ccb->ccb_h.path), ! xpt_path_lun_id(ccb->ccb_h.path), rep->IOCStatus, ! rep->SCSIStatus, rep->SCSIState, rep->TransferCount); switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) { - case MPI2_IOCSTATUS_BUSY: - case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: - /* - * The controller is overloaded, try waiting a bit for it - * to free up. - */ - ccb->ccb_h.status = CAM_BUSY; - break; case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: ! ccb->csio.resid = cm->cm_length - rep->TransferCount; /* FALLTHROUGH */ case MPI2_IOCSTATUS_SUCCESS: case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: ! ccb->ccb_h.status = CAM_REQ_CMP; break; - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - /* resid is ignored for this condition */ - ccb->csio.resid = 0; - ccb->ccb_h.status = CAM_DATA_RUN_ERR; - break; case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: ! ccb->ccb_h.status = CAM_DEV_NOT_THERE; break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: /* --- 1822,1970 ---- return; } ! if (sc->mps_debug & MPS_TRACE) ! mpssas_log_command(cm, ! "ioc %x scsi %x state %x xfer %u\n", ! rep->IOCStatus, rep->SCSIStatus, ! rep->SCSIState, rep->TransferCount); ! ! /* ! * If this is a Direct Drive I/O, reissue the I/O to the original IR ! * Volume if an error occurred (normal I/O retry). Use the original ! * CCB, but set a flag that this will be a retry so that it's sent to ! * the original volume. Free the command but reuse the CCB. ! */ ! if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) { ! mps_free_command(sc, cm); ! ccb->ccb_h.status = MPS_WD_RETRY; ! mpssas_action_scsiio(sassc, ccb); ! return; ! } switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) { case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: ! csio->resid = cm->cm_length - rep->TransferCount; /* FALLTHROUGH */ case MPI2_IOCSTATUS_SUCCESS: case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: ! ! if ((rep->IOCStatus & MPI2_IOCSTATUS_MASK) == ! MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) ! mpssas_log_command(cm, "recovered error\n"); ! ! /* Completion failed at the transport level. */ ! if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | ! MPI2_SCSI_STATE_TERMINATED)) { ! ccb->ccb_h.status = CAM_REQ_CMP_ERR; ! break; ! } ! ! /* In a modern packetized environment, an autosense failure ! * implies that there's not much else that can be done to ! * recover the command. ! */ ! if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { ! ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; ! break; ! } ! ! /* ! * CAM doesn't care about SAS Response Info data, but if this is ! * the state check if TLR should be done. If not, clear the ! * TLR_bits for the target. ! */ ! if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && ! ((rep->ResponseInfo & MPI2_SCSI_RI_MASK_REASONCODE) == ! MPS_SCSI_RI_INVALID_FRAME)) { ! sc->mapping_table[csio->ccb_h.target_id].TLR_bits = ! (u8)MPI2_SCSIIO_CONTROL_NO_TLR; ! } ! ! /* ! * Intentionally override the normal SCSI status reporting ! * for these two cases. These are likely to happen in a ! * multi-initiator environment, and we want to make sure that ! * CAM retries these commands rather than fail them. ! */ ! if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || ! (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { ! ccb->ccb_h.status = CAM_REQ_ABORTED; ! break; ! } ! ! /* Handle normal status and sense */ ! csio->scsi_status = rep->SCSIStatus; ! if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) ! ccb->ccb_h.status = CAM_REQ_CMP; ! else ! ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; ! ! if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { ! int sense_len, returned_sense_len; ! ! returned_sense_len = min(rep->SenseCount, ! sizeof(struct scsi_sense_data)); ! if (returned_sense_len < ccb->csio.sense_len) ! ccb->csio.sense_resid = ccb->csio.sense_len - ! returned_sense_len; ! else ! ccb->csio.sense_resid = 0; ! ! sense_len = min(returned_sense_len, ! ccb->csio.sense_len - ccb->csio.sense_resid); ! bzero(&ccb->csio.sense_data, ! sizeof(&ccb->csio.sense_data)); ! bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len); ! ccb->ccb_h.status |= CAM_AUTOSNS_VALID; ! } ! ! /* ! * Check if this is an INQUIRY command. If it's a VPD inquiry, ! * and it's page code 0 (Supported Page List), and there is ! * inquiry data, and this is for a sequential access device, and ! * the device is an SSP target, and TLR is supported by the ! * controller, turn the TLR_bits value ON if page 0x90 is ! * supported. ! */ ! if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && ! (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && ! (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && ! (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] == ! T_SEQUENTIAL) && (sc->control_TLR) && ! (sc->mapping_table[csio->ccb_h.target_id].device_info & ! MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { ! vpd_list = (struct scsi_vpd_supported_page_list *) ! csio->data_ptr; ! TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. ! TLR_bits; ! *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; ! TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; ! alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + ! csio->cdb_io.cdb_bytes[4]; ! for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { ! if (vpd_list->list[i] == 0x90) { ! *TLR_bits = TLR_on; ! break; ! } ! } ! } break; case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: ! /* ! * If devinfo is 0 this will be a volume. In that case don't ! * tell CAM that the volume is not there. We want volumes to ! * be enumerated until they are deleted/removed, not just ! * failed. ! */ ! if (cm->cm_targ->devinfo == 0) ! ccb->ccb_h.status = CAM_REQ_CMP; ! else ! ccb->ccb_h.status = CAM_DEV_NOT_THERE; ! break; ! case MPI2_IOCSTATUS_INVALID_SGL: ! mps_print_scsiio_cmd(sc, cm); ! ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: /* *************** *** 1615,1637 **** else ccb->ccb_h.status = CAM_REQ_ABORTED; break; case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: ! #if 0 ! ccb->ccb_h.status = CAM_REQ_ABORTED; ! #endif ! mps_printf(sc, "(%d:%d:%d) terminated ioc %x scsi %x state %x " ! "xfer %u\n", xpt_path_path_id(ccb->ccb_h.path), ! xpt_path_target_id(ccb->ccb_h.path), ! xpt_path_lun_id(ccb->ccb_h.path), ! rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, ! rep->TransferCount); ccb->ccb_h.status = CAM_REQUEUE_REQ; break; - case MPI2_IOCSTATUS_INVALID_SGL: - mps_print_scsiio_cmd(sc, cm); - ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; - break; case MPI2_IOCSTATUS_INVALID_FUNCTION: case MPI2_IOCSTATUS_INTERNAL_ERROR: case MPI2_IOCSTATUS_INVALID_VPID: --- 1981,2004 ---- else ccb->ccb_h.status = CAM_REQ_ABORTED; break; + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + /* resid is ignored for this condition */ + csio->resid = 0; + ccb->ccb_h.status = CAM_DATA_RUN_ERR; + break; case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: ! /* ! * Since these are generally external (i.e. hopefully ! * transient transport-related) errors, retry these without ! * decrementing the retry count. ! */ ccb->ccb_h.status = CAM_REQUEUE_REQ; + mpssas_log_command(cm, + "terminated ioc %x scsi %x state %x xfer %u\n", + rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, + rep->TransferCount); break; case MPI2_IOCSTATUS_INVALID_FUNCTION: case MPI2_IOCSTATUS_INTERNAL_ERROR: case MPI2_IOCSTATUS_INVALID_VPID: *************** *** 1643,1703 **** case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: default: ccb->ccb_h.status = CAM_REQ_CMP_ERR; } ! if ((rep->SCSIState & MPI2_SCSI_STATE_NO_SCSI_STATUS) == 0) { ! ccb->csio.scsi_status = rep->SCSIStatus; ! switch (rep->SCSIStatus) { ! case MPI2_SCSI_STATUS_TASK_SET_FULL: ! case MPI2_SCSI_STATUS_CHECK_CONDITION: ! ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; ! break; ! case MPI2_SCSI_STATUS_COMMAND_TERMINATED: ! case MPI2_SCSI_STATUS_TASK_ABORTED: ! ccb->ccb_h.status = CAM_REQ_ABORTED; ! break; ! case MPI2_SCSI_STATUS_GOOD: ! default: ! break; } } ! if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { ! int sense_len; ! if (rep->SenseCount < ccb->csio.sense_len) ! ccb->csio.sense_resid = ccb->csio.sense_len - ! rep->SenseCount; ! else ! ccb->csio.sense_resid = 0; ! sense_len = min(rep->SenseCount, ccb->csio.sense_len - ! ccb->csio.sense_resid); ! bzero(&ccb->csio.sense_data, sizeof(&ccb->csio.sense_data)); ! bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len); ! ccb->ccb_h.status |= CAM_AUTOSNS_VALID; ! } ! if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) ! ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; ! if (rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) ! ccb->ccb_h.status = CAM_REQ_CMP_ERR; ! if (sassc->flags & MPSSAS_QUEUE_FROZEN) { ! ccb->ccb_h.status |= CAM_RELEASE_SIMQ; ! sassc->flags &= ~MPSSAS_QUEUE_FROZEN; ! mps_printf(sc, "Command completed, unfreezing SIM queue\n"); } - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - ccb->ccb_h.status |= CAM_DEV_QFRZN; - xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); - } - mps_free_command(sc, cm); - xpt_done(ccb); } #if __FreeBSD_version >= 900026 --- 2010,2298 ---- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: default: + mpssas_log_command(cm, + "completed ioc %x scsi %x state %x xfer %u\n", + rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, + rep->TransferCount); + csio->resid = cm->cm_length; ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; } + if (sassc->flags & MPSSAS_QUEUE_FROZEN) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + sassc->flags &= ~MPSSAS_QUEUE_FROZEN; + mps_dprint(sc, MPS_INFO, "Command completed, " + "unfreezing SIM queue\n"); + } + + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + ccb->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); + } + + mps_free_command(sc, cm); + xpt_done(ccb); + } + + static void + mpssas_direct_drive_io(struct mpssas_softc *sassc, struct mps_command *cm, + union ccb *ccb) { + pMpi2SCSIIORequest_t pIO_req; + struct mps_softc *sc = sassc->sc; + uint64_t virtLBA; + uint32_t physLBA, stripe_offset, stripe_unit; + uint32_t io_size, column; + uint8_t *ptrLBA, lba_idx, physLBA_byte, *CDB; + + /* + * If this is a valid SCSI command (Read6, Read10, Read16, Write6, + * Write10, or Write16), build a direct I/O message. Otherwise, the I/O + * will be sent to the IR volume itself. Since Read6 and Write6 are a + * bit different than the 10/16 CDBs, handle them separately. + */ + pIO_req = (pMpi2SCSIIORequest_t)cm->cm_req; + CDB = pIO_req->CDB.CDB32; + + /* + * Handle 6 byte CDBs. + */ + if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_6) || + (CDB[0] == WRITE_6))) { + /* + * Get the transfer size in blocks. + */ + io_size = (cm->cm_length >> sc->DD_block_exponent); + + /* + * Get virtual LBA given in the CDB. + */ + virtLBA = ((uint64_t)(CDB[1] & 0x1F) << 16) | + ((uint64_t)CDB[2] << 8) | (uint64_t)CDB[3]; + + /* + * Check that LBA range for I/O does not exceed volume's + * MaxLBA. + */ + if ((virtLBA + (uint64_t)io_size - 1) <= + sc->DD_max_lba) { + /* + * Check if the I/O crosses a stripe boundary. If not, + * translate the virtual LBA to a physical LBA and set + * the DevHandle for the PhysDisk to be used. If it + * does cross a boundry, do normal I/O. To get the + * right DevHandle to use, get the map number for the + * column, then use that map number to look up the + * DevHandle of the PhysDisk. + */ + stripe_offset = (uint32_t)virtLBA & + (sc->DD_stripe_size - 1); + if ((stripe_offset + io_size) <= sc->DD_stripe_size) { + physLBA = (uint32_t)virtLBA >> + sc->DD_stripe_exponent; + stripe_unit = physLBA / sc->DD_num_phys_disks; + column = physLBA % sc->DD_num_phys_disks; + pIO_req->DevHandle = + sc->DD_column_map[column].dev_handle; + cm->cm_desc.SCSIIO.DevHandle = + pIO_req->DevHandle; ! physLBA = (stripe_unit << ! sc->DD_stripe_exponent) + stripe_offset; ! ptrLBA = &pIO_req->CDB.CDB32[1]; ! physLBA_byte = (uint8_t)(physLBA >> 16); ! *ptrLBA = physLBA_byte; ! ptrLBA = &pIO_req->CDB.CDB32[2]; ! physLBA_byte = (uint8_t)(physLBA >> 8); ! *ptrLBA = physLBA_byte; ! ptrLBA = &pIO_req->CDB.CDB32[3]; ! physLBA_byte = (uint8_t)physLBA; ! *ptrLBA = physLBA_byte; ! /* ! * Set flag that Direct Drive I/O is ! * being done. ! */ ! cm->cm_flags |= MPS_CM_FLAGS_DD_IO; ! } } + return; } ! /* ! * Handle 10 or 16 byte CDBs. ! */ ! if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_10) || ! (CDB[0] == WRITE_10) || (CDB[0] == READ_16) || ! (CDB[0] == WRITE_16))) { ! /* ! * For 16-byte CDB's, verify that the upper 4 bytes of the CDB ! * are 0. If not, this is accessing beyond 2TB so handle it in ! * the else section. 10-byte CDB's are OK. ! */ ! if ((CDB[0] < READ_16) || ! !(CDB[2] | CDB[3] | CDB[4] | CDB[5])) { ! /* ! * Get the transfer size in blocks. ! */ ! io_size = (cm->cm_length >> sc->DD_block_exponent); ! ! /* ! * Get virtual LBA. Point to correct lower 4 bytes of ! * LBA in the CDB depending on command. ! */ ! lba_idx = (CDB[0] < READ_16) ? 2 : 6; ! virtLBA = ((uint64_t)CDB[lba_idx] << 24) | ! ((uint64_t)CDB[lba_idx + 1] << 16) | ! ((uint64_t)CDB[lba_idx + 2] << 8) | ! (uint64_t)CDB[lba_idx + 3]; ! ! /* ! * Check that LBA range for I/O does not exceed volume's ! * MaxLBA. ! */ ! if ((virtLBA + (uint64_t)io_size - 1) <= ! sc->DD_max_lba) { ! /* ! * Check if the I/O crosses a stripe boundary. ! * If not, translate the virtual LBA to a ! * physical LBA and set the DevHandle for the ! * PhysDisk to be used. If it does cross a ! * boundry, do normal I/O. To get the right ! * DevHandle to use, get the map number for the ! * column, then use that map number to look up ! * the DevHandle of the PhysDisk. ! */ ! stripe_offset = (uint32_t)virtLBA & ! (sc->DD_stripe_size - 1); ! if ((stripe_offset + io_size) <= ! sc->DD_stripe_size) { ! physLBA = (uint32_t)virtLBA >> ! sc->DD_stripe_exponent; ! stripe_unit = physLBA / ! sc->DD_num_phys_disks; ! column = physLBA % ! sc->DD_num_phys_disks; ! pIO_req->DevHandle = ! sc->DD_column_map[column]. ! dev_handle; ! cm->cm_desc.SCSIIO.DevHandle = ! pIO_req->DevHandle; ! ! physLBA = (stripe_unit << ! sc->DD_stripe_exponent) + ! stripe_offset; ! ptrLBA = ! &pIO_req->CDB.CDB32[lba_idx]; ! physLBA_byte = (uint8_t)(physLBA >> 24); ! *ptrLBA = physLBA_byte; ! ptrLBA = ! &pIO_req->CDB.CDB32[lba_idx + 1]; ! physLBA_byte = (uint8_t)(physLBA >> 16); ! *ptrLBA = physLBA_byte; ! ptrLBA = ! &pIO_req->CDB.CDB32[lba_idx + 2]; ! physLBA_byte = (uint8_t)(physLBA >> 8); ! *ptrLBA = physLBA_byte; ! ptrLBA = ! &pIO_req->CDB.CDB32[lba_idx + 3]; ! physLBA_byte = (uint8_t)physLBA; ! *ptrLBA = physLBA_byte; ! ! /* ! * Set flag that Direct Drive I/O is ! * being done. ! */ ! cm->cm_flags |= MPS_CM_FLAGS_DD_IO; ! } ! } ! } else { ! /* ! * 16-byte CDB and the upper 4 bytes of the CDB are not ! * 0. Get the transfer size in blocks. ! */ ! io_size = (cm->cm_length >> sc->DD_block_exponent); ! /* ! * Get virtual LBA. ! */ ! virtLBA = ((uint64_t)CDB[2] << 54) | ! ((uint64_t)CDB[3] << 48) | ! ((uint64_t)CDB[4] << 40) | ! ((uint64_t)CDB[5] << 32) | ! ((uint64_t)CDB[6] << 24) | ! ((uint64_t)CDB[7] << 16) | ! ((uint64_t)CDB[8] << 8) | ! (uint64_t)CDB[9]; ! /* ! * Check that LBA range for I/O does not exceed volume's ! * MaxLBA. ! */ ! if ((virtLBA + (uint64_t)io_size - 1) <= ! sc->DD_max_lba) { ! /* ! * Check if the I/O crosses a stripe boundary. ! * If not, translate the virtual LBA to a ! * physical LBA and set the DevHandle for the ! * PhysDisk to be used. If it does cross a ! * boundry, do normal I/O. To get the right ! * DevHandle to use, get the map number for the ! * column, then use that map number to look up ! * the DevHandle of the PhysDisk. ! */ ! stripe_offset = (uint32_t)virtLBA & ! (sc->DD_stripe_size - 1); ! if ((stripe_offset + io_size) <= ! sc->DD_stripe_size) { ! physLBA = (uint32_t)(virtLBA >> ! sc->DD_stripe_exponent); ! stripe_unit = physLBA / ! sc->DD_num_phys_disks; ! column = physLBA % ! sc->DD_num_phys_disks; ! pIO_req->DevHandle = ! sc->DD_column_map[column]. ! dev_handle; ! cm->cm_desc.SCSIIO.DevHandle = ! pIO_req->DevHandle; ! physLBA = (stripe_unit << ! sc->DD_stripe_exponent) + ! stripe_offset; ! /* ! * Set upper 4 bytes of LBA to 0. We ! * assume that the phys disks are less ! * than 2 TB's in size. Then, set the ! * lower 4 bytes. ! */ ! pIO_req->CDB.CDB32[2] = 0; ! pIO_req->CDB.CDB32[3] = 0; ! pIO_req->CDB.CDB32[4] = 0; ! pIO_req->CDB.CDB32[5] = 0; ! ptrLBA = &pIO_req->CDB.CDB32[6]; ! physLBA_byte = (uint8_t)(physLBA >> 24); ! *ptrLBA = physLBA_byte; ! ptrLBA = &pIO_req->CDB.CDB32[7]; ! physLBA_byte = (uint8_t)(physLBA >> 16); ! *ptrLBA = physLBA_byte; ! ptrLBA = &pIO_req->CDB.CDB32[8]; ! physLBA_byte = (uint8_t)(physLBA >> 8); ! *ptrLBA = physLBA_byte; ! ptrLBA = &pIO_req->CDB.CDB32[9]; ! physLBA_byte = (uint8_t)physLBA; ! *ptrLBA = physLBA_byte; ! /* ! * Set flag that Direct Drive I/O is ! * being done. ! */ ! cm->cm_flags |= MPS_CM_FLAGS_DD_IO; ! } ! } ! } } } #if __FreeBSD_version >= 900026 *************** *** 1722,1728 **** __func__, cm->cm_flags); ccb->ccb_h.status = CAM_REQ_CMP_ERR; goto bailout; ! } rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; if (rpl == NULL) { --- 2317,2323 ---- __func__, cm->cm_flags); ccb->ccb_h.status = CAM_REQ_CMP_ERR; goto bailout; ! } rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; if (rpl == NULL) { *************** *** 1989,1995 **** --- 2584,2592 ---- * the parent device of this device, which is probably the expander. */ if (sasaddr == 0) { + #ifdef OLD_MPS_PROBE struct mpssas_target *parent_target; + #endif if (targ->parent_handle == 0x0) { mps_printf(sc, "%s: handle %d does not have a valid " *************** *** 1997,2004 **** ccb->ccb_h.status = CAM_REQ_INVALID; goto bailout; } ! parent_target = mpssas_find_target(sassc, 0, ! targ->parent_handle); if (parent_target == NULL) { mps_printf(sc, "%s: handle %d does not have a valid " --- 2594,2602 ---- ccb->ccb_h.status = CAM_REQ_INVALID; goto bailout; } ! #ifdef OLD_MPS_PROBE ! parent_target = mpssas_find_target_by_handle(sassc, 0, ! targ->parent_handle); if (parent_target == NULL) { mps_printf(sc, "%s: handle %d does not have a valid " *************** *** 2018,2023 **** --- 2616,2642 ---- } sasaddr = parent_target->sasaddr; + #else /* OLD_MPS_PROBE */ + if ((targ->parent_devinfo & + MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { + mps_printf(sc, "%s: handle %d parent %d does not " + "have an SMP target!\n", __func__, + targ->handle, targ->parent_handle); + ccb->ccb_h.status = CAM_REQ_INVALID; + goto bailout; + + } + if (targ->parent_sasaddr == 0x0) { + mps_printf(sc, "%s: handle %d parent handle %d does " + "not have a valid SAS address!\n", + __func__, targ->handle, targ->parent_handle); + ccb->ccb_h.status = CAM_REQ_INVALID; + goto bailout; + } + + sasaddr = targ->parent_sasaddr; + #endif /* OLD_MPS_PROBE */ + } if (sasaddr == 0) { *************** *** 2034,2132 **** xpt_done(ccb); } ! ! #endif /* __FreeBSD_version >= 900026 */ static void mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb) { struct mps_softc *sc; ! struct mps_command *cm; struct mpssas_target *targ; sc = sassc->sc; ! targ = &sassc->targets[ccb->ccb_h.target_id]; ! ! if (targ->flags & MPSSAS_TARGET_INRECOVERY) { ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(ccb); return; } ! cm = mps_alloc_command(sc); ! if (cm == NULL) { ! mps_printf(sc, "%s: cannot alloc command\n", __func__); ! ccb->ccb_h.status = CAM_RESRC_UNAVAIL; ! xpt_done(ccb); ! return; ! } ! ! cm->cm_targ = targ; ! cm->cm_complete = mpssas_resetdev_complete; ! cm->cm_complete_data = ccb; ! ! mpssas_resetdev(sassc, cm); ! } ! ! static void ! mpssas_resetdev(struct mpssas_softc *sassc, struct mps_command *cm) ! { ! MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! struct mps_softc *sc; ! ! mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); ! ! sc = sassc->sc; ! ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; ! req->DevHandle = cm->cm_targ->handle; req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; /* SAS Hard Link Reset / SATA Link Reset */ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; ! cm->cm_data = NULL; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! ! mpssas_issue_tm_request(sc, cm); } static void ! mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *cm) { MPI2_SCSI_TASK_MANAGE_REPLY *resp; union ccb *ccb; ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; ! ccb = cm->cm_complete_data; ! if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; mps_printf(sc, "%s: cm_flags = %#x for reset of handle %#04x! " ! "This should not happen!\n", __func__, cm->cm_flags, req->DevHandle); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; goto bailout; } ! printf("resetdev complete IOCStatus= 0x%x ResponseCode= 0x%x\n", resp->IOCStatus, resp->ResponseCode); ! if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) ccb->ccb_h.status = CAM_REQ_CMP; else ccb->ccb_h.status = CAM_REQ_CMP_ERR; bailout: - mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1); xpt_done(ccb); } --- 2653,2739 ---- xpt_done(ccb); } ! #endif //__FreeBSD_version >= 900026 static void mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb) { + MPI2_SCSI_TASK_MANAGE_REQUEST *req; struct mps_softc *sc; ! struct mps_command *tm; struct mpssas_target *targ; + mps_dprint(sassc->sc, MPS_TRACE, __func__); + mtx_assert(&sassc->sc->mps_mtx, MA_OWNED); + sc = sassc->sc; ! tm = mps_alloc_command(sc); ! if (tm == NULL) { ! mps_printf(sc, "comand alloc failure in mpssas_action_resetdev\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(ccb); return; } ! targ = &sassc->targets[ccb->ccb_h.target_id]; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; ! req->DevHandle = targ->handle; req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; /* SAS Hard Link Reset / SATA Link Reset */ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; ! tm->cm_data = NULL; ! tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; ! tm->cm_complete = mpssas_resetdev_complete; ! tm->cm_complete_data = ccb; ! mps_map_command(sc, tm); } static void ! mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *tm) { MPI2_SCSI_TASK_MANAGE_REPLY *resp; union ccb *ccb; ! mps_dprint(sc, MPS_TRACE, __func__); ! mtx_assert(&sc->mps_mtx, MA_OWNED); ! resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; ! ccb = tm->cm_complete_data; ! /* ! * Currently there should be no way we can hit this case. It only ! * happens when we have a failure to allocate chain frames, and ! * task management commands don't have S/G lists. ! */ ! if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; ! req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; mps_printf(sc, "%s: cm_flags = %#x for reset of handle %#04x! " ! "This should not happen!\n", __func__, tm->cm_flags, req->DevHandle); ccb->ccb_h.status = CAM_REQ_CMP_ERR; goto bailout; } ! printf("%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__, resp->IOCStatus, resp->ResponseCode); ! if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { ccb->ccb_h.status = CAM_REQ_CMP; + mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, + CAM_LUN_WILDCARD); + } else ccb->ccb_h.status = CAM_REQ_CMP_ERR; bailout: + mpssas_free_tm(sc, tm); xpt_done(ccb); } *************** *** 2136,2151 **** struct mpssas_softc *sassc; sassc = cam_sim_softc(sim); mps_intr_locked(sassc->sc); } static void ! mpssas_freeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ) { } static void ! mpssas_unfreeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ) { } --- 2743,3244 ---- struct mpssas_softc *sassc; sassc = cam_sim_softc(sim); + + if (sassc->sc->mps_debug & MPS_TRACE) { + /* frequent debug messages during a panic just slow + * everything down too much. + */ + mps_printf(sassc->sc, "%s clearing MPS_TRACE\n", __func__); + sassc->sc->mps_debug &= ~MPS_TRACE; + } + mps_intr_locked(sassc->sc); } static void ! mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb) ! { ! struct mpssas_softc *sassc; ! char path_str[64]; ! ! if (done_ccb == NULL) ! return; ! ! sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; ! ! mtx_assert(&sassc->sc->mps_mtx, MA_OWNED); ! ! xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); ! mps_dprint(sassc->sc, MPS_INFO, "Completing rescan for %s\n", path_str); ! ! xpt_free_path(done_ccb->ccb_h.path); ! xpt_free_ccb(done_ccb); ! ! #if __FreeBSD_version < 1000006 ! /* ! * Before completing scan, get EEDP stuff for all of the existing ! * targets. ! */ ! mpssas_check_eedp(sassc); ! #endif ! ! } ! ! /* thread to handle bus rescans */ ! static void ! mpssas_scanner_thread(void *arg) ! { ! struct mpssas_softc *sassc; ! struct mps_softc *sc; ! union ccb *ccb; ! ! sassc = (struct mpssas_softc *)arg; ! sc = sassc->sc; ! ! mps_dprint(sc, MPS_TRACE, "%s\n", __func__); ! ! mps_lock(sc); ! for (;;) { ! msleep(&sassc->ccb_scanq, &sc->mps_mtx, PRIBIO, ! "mps_scanq", 0); ! if (sassc->flags & MPSSAS_SHUTDOWN) { ! mps_dprint(sc, MPS_TRACE, "Scanner shutting down\n"); ! break; ! } ! ccb = (union ccb *)TAILQ_FIRST(&sassc->ccb_scanq); ! if (ccb == NULL) ! continue; ! TAILQ_REMOVE(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe); ! xpt_action(ccb); ! } ! ! sassc->flags &= ~MPSSAS_SCANTHREAD; ! wakeup(&sassc->flags); ! mps_unlock(sc); ! mps_dprint(sc, MPS_TRACE, "Scanner exiting\n"); ! mps_kproc_exit(0); ! } ! ! static void ! mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb) ! { ! char path_str[64]; ! ! mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); ! ! mtx_assert(&sassc->sc->mps_mtx, MA_OWNED); ! ! if (ccb == NULL) ! return; ! ! xpt_path_string(ccb->ccb_h.path, path_str, sizeof(path_str)); ! mps_dprint(sassc->sc, MPS_INFO, "Queueing rescan for %s\n", path_str); ! ! /* Prepare request */ ! ccb->ccb_h.ppriv_ptr1 = sassc; ! ccb->ccb_h.cbfcnp = mpssas_rescan_done; ! xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, MPS_PRIORITY_XPT); ! TAILQ_INSERT_TAIL(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe); ! wakeup(&sassc->ccb_scanq); ! } ! ! #if __FreeBSD_version >= 1000006 ! static void ! mpssas_async(void *callback_arg, uint32_t code, struct cam_path *path, ! void *arg) ! { ! struct mps_softc *sc; ! ! sc = (struct mps_softc *)callback_arg; ! ! switch (code) { ! case AC_ADVINFO_CHANGED: { ! struct mpssas_target *target; ! struct mpssas_softc *sassc; ! struct scsi_read_capacity_data_long rcap_buf; ! struct ccb_dev_advinfo cdai; ! struct mpssas_lun *lun; ! lun_id_t lunid; ! int found_lun; ! uintptr_t buftype; ! ! buftype = (uintptr_t)arg; ! ! found_lun = 0; ! sassc = sc->sassc; ! ! /* ! * We're only interested in read capacity data changes. ! */ ! if (buftype != CDAI_TYPE_RCAPLONG) ! break; ! ! /* ! * We're only interested in devices that are attached to ! * this controller. ! */ ! if (xpt_path_path_id(path) != sassc->sim->path_id) ! break; ! ! /* ! * We should have a handle for this, but check to make sure. ! */ ! target = &sassc->targets[xpt_path_target_id(path)]; ! if (target->handle == 0) ! break; ! ! lunid = xpt_path_lun_id(path); ! ! SLIST_FOREACH(lun, &target->luns, lun_link) { ! if (lun->lun_id == lunid) { ! found_lun = 1; ! break; ! } ! } ! ! if (found_lun == 0) { ! lun = malloc(sizeof(struct mpssas_lun), M_MPT2, ! M_NOWAIT | M_ZERO); ! if (lun == NULL) { ! mps_dprint(sc, MPS_FAULT, "Unable to alloc " ! "LUN for EEDP support.\n"); ! break; ! } ! lun->lun_id = lunid; ! SLIST_INSERT_HEAD(&target->luns, lun, lun_link); ! } ! ! bzero(&rcap_buf, sizeof(rcap_buf)); ! xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); ! cdai.ccb_h.func_code = XPT_DEV_ADVINFO; ! cdai.ccb_h.flags = CAM_DIR_IN; ! cdai.buftype = CDAI_TYPE_RCAPLONG; ! cdai.flags = 0; ! cdai.bufsiz = sizeof(rcap_buf); ! cdai.buf = (uint8_t *)&rcap_buf; ! xpt_action((union ccb *)&cdai); ! if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) ! cam_release_devq(cdai.ccb_h.path, ! 0, 0, 0, FALSE); ! ! if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) ! && (rcap_buf.prot & SRC16_PROT_EN)) { ! lun->eedp_formatted = TRUE; ! lun->eedp_block_size = scsi_4btoul(rcap_buf.length); ! } else { ! lun->eedp_formatted = FALSE; ! lun->eedp_block_size = 0; ! } ! break; ! } ! default: ! break; ! } ! } ! #else /* __FreeBSD_version >= 1000006 */ ! ! static void ! mpssas_check_eedp(struct mpssas_softc *sassc) ! { ! struct mps_softc *sc = sassc->sc; ! struct ccb_scsiio *csio; ! struct scsi_read_capacity_16 *scsi_cmd; ! struct scsi_read_capacity_eedp *rcap_buf; ! union ccb *ccb; ! path_id_t pathid = cam_sim_path(sassc->sim); ! target_id_t targetid; ! lun_id_t lunid; ! struct cam_periph *found_periph; ! struct mpssas_target *target; ! struct mpssas_lun *lun; ! uint8_t found_lun; ! ! /* ! * Issue a READ CAPACITY 16 command to each LUN of each target. This ! * info is used to determine if the LUN is formatted for EEDP support. ! */ ! for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { ! target = &sassc->targets[targetid]; ! if (target->handle == 0x0) { ! continue; ! } ! ! lunid = 0; ! do { ! rcap_buf = ! malloc(sizeof(struct scsi_read_capacity_eedp), ! M_MPT2, M_NOWAIT | M_ZERO); ! if (rcap_buf == NULL) { ! mps_dprint(sc, MPS_FAULT, "Unable to alloc read " ! "capacity buffer for EEDP support.\n"); ! return; ! } ! ccb = xpt_alloc_ccb_nowait(); ! if (ccb == NULL) { ! mps_dprint(sc, MPS_FAULT, "Unable to alloc CCB " ! "for EEDP support.\n"); ! free(rcap_buf, M_MPT2); ! return; ! } ! ! if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, ! pathid, targetid, lunid) != CAM_REQ_CMP) { ! mps_dprint(sc, MPS_FAULT, "Unable to create " ! "path for EEDP support\n"); ! free(rcap_buf, M_MPT2); ! xpt_free_ccb(ccb); ! return; ! } ! ! /* ! * If a periph is returned, the LUN exists. Create an ! * entry in the target's LUN list. ! */ ! if ((found_periph = cam_periph_find(ccb->ccb_h.path, ! NULL)) != NULL) { ! /* ! * If LUN is already in list, don't create a new ! * one. ! */ ! found_lun = FALSE; ! SLIST_FOREACH(lun, &target->luns, lun_link) { ! if (lun->lun_id == lunid) { ! found_lun = TRUE; ! break; ! } ! } ! if (!found_lun) { ! lun = malloc(sizeof(struct mpssas_lun), ! M_MPT2, M_WAITOK | M_ZERO); ! if (lun == NULL) { ! mps_dprint(sc, MPS_FAULT, ! "Unable to alloc LUN for " ! "EEDP support.\n"); ! free(rcap_buf, M_MPT2); ! xpt_free_path(ccb->ccb_h.path); ! xpt_free_ccb(ccb); ! return; ! } ! lun->lun_id = lunid; ! SLIST_INSERT_HEAD(&target->luns, lun, ! lun_link); ! } ! lunid++; ! ! /* ! * Issue a READ CAPACITY 16 command for the LUN. ! * The mpssas_read_cap_done function will load ! * the read cap info into the LUN struct. ! */ ! csio = &ccb->csio; ! csio->ccb_h.func_code = XPT_SCSI_IO; ! csio->ccb_h.flags = CAM_DIR_IN; ! csio->ccb_h.retry_count = 4; ! csio->ccb_h.cbfcnp = mpssas_read_cap_done; ! csio->ccb_h.timeout = 60000; ! csio->data_ptr = (uint8_t *)rcap_buf; ! csio->dxfer_len = sizeof(struct ! scsi_read_capacity_eedp); ! csio->sense_len = MPS_SENSE_LEN; ! csio->cdb_len = sizeof(*scsi_cmd); ! csio->tag_action = MSG_SIMPLE_Q_TAG; ! ! scsi_cmd = (struct scsi_read_capacity_16 *) ! &csio->cdb_io.cdb_bytes; ! bzero(scsi_cmd, sizeof(*scsi_cmd)); ! scsi_cmd->opcode = 0x9E; ! scsi_cmd->service_action = SRC16_SERVICE_ACTION; ! ((uint8_t *)scsi_cmd)[13] = sizeof(struct ! scsi_read_capacity_eedp); ! ! /* ! * Set the path, target and lun IDs for the READ ! * CAPACITY request. ! */ ! ccb->ccb_h.path_id = ! xpt_path_path_id(ccb->ccb_h.path); ! ccb->ccb_h.target_id = ! xpt_path_target_id(ccb->ccb_h.path); ! ccb->ccb_h.target_lun = ! xpt_path_lun_id(ccb->ccb_h.path); ! ! ccb->ccb_h.ppriv_ptr1 = sassc; ! xpt_action(ccb); ! } else { ! free(rcap_buf, M_MPT2); ! xpt_free_path(ccb->ccb_h.path); ! xpt_free_ccb(ccb); ! } ! } while (found_periph); ! } ! } ! ! ! static void ! mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) ! { ! struct mpssas_softc *sassc; ! struct mpssas_target *target; ! struct mpssas_lun *lun; ! struct scsi_read_capacity_eedp *rcap_buf; ! ! if (done_ccb == NULL) ! return; ! ! rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; ! ! /* ! * Get the LUN ID for the path and look it up in the LUN list for the ! * target. ! */ ! sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; ! target = &sassc->targets[done_ccb->ccb_h.target_id]; ! SLIST_FOREACH(lun, &target->luns, lun_link) { ! if (lun->lun_id != done_ccb->ccb_h.target_lun) ! continue; ! ! /* ! * Got the LUN in the target's LUN list. Fill it in ! * with EEDP info. If the READ CAP 16 command had some ! * SCSI error (common if command is not supported), mark ! * the lun as not supporting EEDP and set the block size ! * to 0. ! */ ! if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) ! || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { ! lun->eedp_formatted = FALSE; ! lun->eedp_block_size = 0; ! break; ! } ! ! if (rcap_buf->protect & 0x01) { ! lun->eedp_formatted = TRUE; ! lun->eedp_block_size = scsi_4btoul(rcap_buf->length); ! } ! break; ! } ! ! // Finished with this CCB and path. ! free(rcap_buf, M_MPT2); ! xpt_free_path(done_ccb->ccb_h.path); ! xpt_free_ccb(done_ccb); ! } ! #endif /* __FreeBSD_version >= 1000006 */ ! ! int ! mpssas_startup(struct mps_softc *sc) ! { ! struct mpssas_softc *sassc; ! ! /* ! * Send the port enable message and set the wait_for_port_enable flag. ! * This flag helps to keep the simq frozen until all discovery events ! * are processed. ! */ ! sassc = sc->sassc; ! mpssas_startup_increment(sassc); ! sc->wait_for_port_enable = 1; ! mpssas_send_portenable(sc); ! return (0); ! } ! ! static int ! mpssas_send_portenable(struct mps_softc *sc) { + MPI2_PORT_ENABLE_REQUEST *request; + struct mps_command *cm; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; + request->Function = MPI2_FUNCTION_PORT_ENABLE; + request->MsgFlags = 0; + request->VP_ID = 0; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete = mpssas_portenable_complete; + cm->cm_data = NULL; + cm->cm_sge = NULL; + + mps_map_command(sc, cm); + mps_dprint(sc, MPS_TRACE, + "mps_send_portenable finished cm %p req %p complete %p\n", + cm, cm->cm_req, cm->cm_complete); + return (0); } static void ! mpssas_portenable_complete(struct mps_softc *sc, struct mps_command *cm) { + MPI2_PORT_ENABLE_REPLY *reply; + struct mpssas_softc *sassc; + struct mpssas_target *target; + int i; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + sassc = sc->sassc; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * port enable commands don't have S/G lists. + */ + if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { + mps_printf(sc, "%s: cm_flags = %#x for port enable! " + "This should not happen!\n", __func__, cm->cm_flags); + } + + reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; + if (reply == NULL) + mps_dprint(sc, MPS_FAULT, "Portenable NULL reply\n"); + else if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS) + mps_dprint(sc, MPS_FAULT, "Portenable failed\n"); + + mps_free_command(sc, cm); + if (sc->mps_ich.ich_arg != NULL) { + mps_dprint(sc, MPS_INFO, "disestablish config intrhook\n"); + config_intrhook_disestablish(&sc->mps_ich); + sc->mps_ich.ich_arg = NULL; + } + + /* + * Get WarpDrive info after discovery is complete but before the scan + * starts. At this point, all devices are ready to be exposed to the + * OS. If devices should be hidden instead, take them out of the + * 'targets' array before the scan. The devinfo for a disk will have + * some info and a volume's will be 0. Use that to remove disks. + */ + mps_wd_config_pages(sc); + if (((sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) + && (sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) + || (sc->WD_valid_config && (sc->WD_hide_expose == + MPS_WD_HIDE_IF_VOLUME))) { + for (i = 0; i < sassc->sc->facts->MaxTargets; i++) { + target = &sassc->targets[i]; + if (target->devinfo) { + target->devinfo = 0x0; + target->encl_handle = 0x0; + target->encl_slot = 0x0; + target->handle = 0x0; + target->tid = 0x0; + target->linkrate = 0x0; + target->flags = 0x0; + } + } + } + + /* + * Done waiting for port enable to complete. Decrement the refcount. + * If refcount is 0, discovery is complete and a rescan of the bus can + * take place. Since the simq was explicitly frozen before port + * enable, it must be explicitly released here to keep the + * freeze/release count in sync. + */ + sc->wait_for_port_enable = 0; + sc->port_enable_complete = 1; + mpssas_startup_decrement(sassc); + xpt_release_simq(sassc->sim, 1); } *** /dev/null Fri Jan 20 13:16:35 2012 --- src/sys/dev/mps/mps_sas.h Fri Jan 20 13:16:35 2012 *************** *** 0 **** --- 1,161 ---- + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + + struct mps_fw_event_work; + + struct mpssas_lun { + SLIST_ENTRY(mpssas_lun) lun_link; + lun_id_t lun_id; + uint8_t eedp_formatted; + uint32_t eedp_block_size; + }; + + struct mpssas_target { + uint16_t handle; + uint8_t linkrate; + uint64_t devname; + uint32_t devinfo; + uint16_t encl_handle; + uint16_t encl_slot; + uint8_t flags; + #define MPSSAS_TARGET_INABORT (1 << 0) + #define MPSSAS_TARGET_INRESET (1 << 1) + #define MPSSAS_TARGET_INDIAGRESET (1 << 2) + #define MPSSAS_TARGET_INREMOVAL (1 << 3) + #define MPSSAS_TARGET_INRECOVERY (MPSSAS_TARGET_INABORT | \ + MPSSAS_TARGET_INRESET | MPSSAS_TARGET_INCHIPRESET) + #define MPSSAS_TARGET_ADD (1 << 29) + #define MPSSAS_TARGET_REMOVE (1 << 30) + uint16_t tid; + SLIST_HEAD(, mpssas_lun) luns; + TAILQ_HEAD(, mps_command) commands; + struct mps_command *tm; + TAILQ_HEAD(, mps_command) timedout_commands; + uint16_t exp_dev_handle; + uint16_t phy_num; + uint64_t sasaddr; + uint16_t parent_handle; + uint64_t parent_sasaddr; + uint32_t parent_devinfo; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + TAILQ_ENTRY(mpssas_target) sysctl_link; + uint64_t issued; + uint64_t completed; + unsigned int outstanding; + unsigned int timeouts; + unsigned int aborts; + unsigned int logical_unit_resets; + unsigned int target_resets; + }; + + struct mpssas_softc { + struct mps_softc *sc; + u_int flags; + #define MPSSAS_IN_DISCOVERY (1 << 0) + #define MPSSAS_IN_STARTUP (1 << 1) + #define MPSSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) + #define MPSSAS_QUEUE_FROZEN (1 << 3) + #define MPSSAS_SHUTDOWN (1 << 4) + #define MPSSAS_SCANTHREAD (1 << 5) + struct mpssas_target *targets; + struct cam_devq *devq; + struct cam_sim *sim; + struct cam_path *path; + struct intr_config_hook sas_ich; + struct callout discovery_callout; + u_int discovery_timeouts; + struct mps_event_handle *mpssas_eh; + + u_int startup_refcount; + u_int tm_count; + struct proc *sysctl_proc; + + TAILQ_HEAD(, ccb_hdr) ccb_scanq; + struct proc *rescan_thread; + + struct taskqueue *ev_tq; + struct task ev_task; + TAILQ_HEAD(, mps_fw_event_work) ev_queue; + }; + + MALLOC_DECLARE(M_MPSSAS); + + /* + * Abstracted so that the driver can be backwards and forwards compatible + * with future versions of CAM that will provide this functionality. + */ + #define MPS_SET_LUN(lun, ccblun) \ + mpssas_set_lun(lun, ccblun) + + static __inline int + mpssas_set_lun(uint8_t *lun, u_int ccblun) + { + uint64_t *newlun; + + newlun = (uint64_t *)lun; + *newlun = 0; + if (ccblun <= 0xff) { + /* Peripheral device address method, LUN is 0 to 255 */ + lun[1] = ccblun; + } else if (ccblun <= 0x3fff) { + /* Flat space address method, LUN is <= 16383 */ + scsi_ulto2b(ccblun, lun); + lun[0] |= 0x40; + } else if (ccblun <= 0xffffff) { + /* Extended flat space address method, LUN is <= 16777215 */ + scsi_ulto3b(ccblun, &lun[1]); + /* Extended Flat space address method */ + lun[0] = 0xc0; + /* Length = 1, i.e. LUN is 3 bytes long */ + lun[0] |= 0x10; + /* Extended Address Method */ + lun[0] |= 0x02; + } else { + return (EINVAL); + } + + return (0); + } + + #define MPS_SET_SINGLE_LUN(req, lun) \ + do { \ + bzero((req)->LUN, 8); \ + (req)->LUN[1] = lun; \ + } while(0) + + void mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ); + void mpssas_discovery_end(struct mpssas_softc *sassc); + void mpssas_startup_increment(struct mpssas_softc *sassc); + void mpssas_startup_decrement(struct mpssas_softc *sassc); + + struct mps_command * mpssas_alloc_tm(struct mps_softc *sc); + void mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm); + void mpssas_firmware_event_work(void *arg, int pending); ==== - //depot/users/kenm/FreeBSD-test/sys/dev/mps/mps_sas.h#1 ==== *** /dev/null Fri Jan 20 13:16:36 2012 --- src/sys/dev/mps/mps_sas_lsi.c Fri Jan 20 13:16:36 2012 *************** *** 0 **** --- 1,865 ---- + /*- + * Copyright (c) 2011 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + + #include + __FBSDID("$FreeBSD$"); + + /* Communications core for LSI MPT2 */ + + /* TODO Move headers to mpsvar */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + /* For Hashed SAS Address creation for SATA Drives */ + #define MPT2SAS_SN_LEN 20 + #define MPT2SAS_MN_LEN 40 + + struct mps_fw_event_work { + u16 event; + void *event_data; + TAILQ_ENTRY(mps_fw_event_work) ev_link; + }; + + union _sata_sas_address { + u8 wwid[8]; + struct { + u32 high; + u32 low; + } word; + }; + + /* + * define the IDENTIFY DEVICE structure + */ + struct _ata_identify_device_data { + u16 reserved1[10]; /* 0-9 */ + u16 serial_number[10]; /* 10-19 */ + u16 reserved2[7]; /* 20-26 */ + u16 model_number[20]; /* 27-46*/ + u16 reserved3[209]; /* 47-255*/ + }; + + static void mpssas_fw_work(struct mps_softc *sc, + struct mps_fw_event_work *fw_event); + static void mpssas_fw_event_free(struct mps_softc *, + struct mps_fw_event_work *); + static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate); + static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, + Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, + u32 devinfo); + int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc, + u64 *sas_address, u16 handle, u32 device_info); + static int mpssas_volume_add(struct mps_softc *sc, + Mpi2EventIrConfigElement_t *element); + + void + mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event) + { + struct mps_fw_event_work *fw_event; + u16 sz; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + mps_print_evt_sas(sc, event); + mpssas_record_event(sc, event); + + fw_event = malloc(sizeof(struct mps_fw_event_work), M_MPT2, + M_ZERO|M_NOWAIT); + if (!fw_event) { + printf("%s: allocate failed for fw_event\n", __func__); + return; + } + sz = le16toh(event->EventDataLength) * 4; + fw_event->event_data = malloc(sz, M_MPT2, M_ZERO|M_NOWAIT); + if (!fw_event->event_data) { + printf("%s: allocate failed for event_data\n", __func__); + free(fw_event, M_MPT2); + return; + } + + bcopy(event->EventData, fw_event->event_data, sz); + fw_event->event = event->Event; + if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE || + event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && + sc->track_mapping_events) + sc->pending_map_events++; + + /* + * When wait_for_port_enable flag is set, make sure that all the events + * are processed. Increment the startup_refcount and decrement it after + * events are processed. + */ + if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && + sc->wait_for_port_enable) + mpssas_startup_increment(sc->sassc); + + TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link); + taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task); + + } + + static void + mpssas_fw_event_free(struct mps_softc *sc, struct mps_fw_event_work *fw_event) + { + + free(fw_event->event_data, M_MPT2); + free(fw_event, M_MPT2); + } + + /** + * _mps_fw_work - delayed task for processing firmware events + * @sc: per adapter object + * @fw_event: The fw_event_work object + * Context: user. + * + * Return nothing. + */ + static void + mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event) + { + struct mpssas_softc *sassc; + sassc = sc->sassc; + + switch (fw_event->event) { + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; + int i; + + data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) + fw_event->event_data; + + mps_mapping_topology_change_event(sc, fw_event->event_data); + + for (i = 0; i < data->NumEntries; i++) { + phy = &data->PHY[i]; + switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { + case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + if (mpssas_add_device(sc, + phy->AttachedDevHandle, phy->LinkRate)){ + printf("%s: failed to add device with " + "handle 0x%x\n", __func__, + phy->AttachedDevHandle); + mpssas_prepare_remove(sassc, phy-> + AttachedDevHandle); + } + break; + case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: + mpssas_prepare_remove(sassc, phy-> + AttachedDevHandle); + break; + case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: + case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: + default: + break; + } + } + /* + * refcount was incremented for this event in + * mpssas_evt_handler. Decrement it here because the event has + * been processed. + */ + mpssas_startup_decrement(sassc); + break; + } + case MPI2_EVENT_SAS_DISCOVERY: + { + MPI2_EVENT_DATA_SAS_DISCOVERY *data; + + data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data; + + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) + mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n"); + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { + mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n"); + sassc->flags &= ~MPSSAS_IN_DISCOVERY; + mpssas_discovery_end(sassc); + } + break; + } + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + { + Mpi2EventDataSasEnclDevStatusChange_t *data; + data = (Mpi2EventDataSasEnclDevStatusChange_t *) + fw_event->event_data; + mps_mapping_enclosure_dev_status_change_event(sc, + fw_event->event_data); + break; + } + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + { + Mpi2EventIrConfigElement_t *element; + int i; + u8 foreign_config; + Mpi2EventDataIrConfigChangeList_t *event_data; + struct mpssas_target *targ; + unsigned int id; + + event_data = fw_event->event_data; + foreign_config = (le32toh(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; + + element = + (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + id = mps_mapping_get_raid_id_from_handle + (sc, element->VolDevHandle); + + mps_mapping_ir_config_change_event(sc, event_data); + + for (i = 0; i < event_data->NumElements; i++, element++) { + switch (element->ReasonCode) { + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: + case MPI2_EVENT_IR_CHANGE_RC_ADDED: + if (!foreign_config) { + if (mpssas_volume_add(sc, element)) { + printf("%s: failed to add RAID " + "volume with handle 0x%x\n", + __func__, le16toh(element-> + VolDevHandle)); + } + } + break; + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: + case MPI2_EVENT_IR_CHANGE_RC_REMOVED: + /* + * Rescan after volume is deleted or removed. + */ + if (!foreign_config) { + if (id == MPS_MAP_BAD_ID) { + printf("%s: could not get ID " + "for volume with handle " + "0x%04x\n", __func__, + element->VolDevHandle); + break; + } + + targ = &sassc->targets[id]; + targ->handle = 0x0; + targ->encl_slot = 0x0; + targ->encl_handle = 0x0; + targ->exp_dev_handle = 0x0; + targ->phy_num = 0x0; + targ->linkrate = 0x0; + mpssas_rescan_target(sc, targ); + printf("RAID target id 0x%x removed\n", + targ->tid); + } + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: + /* + * Phys Disk of a volume has been created. Hide + * it from the OS. + */ + mpssas_prepare_remove(sassc, element-> + PhysDiskDevHandle); + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: + /* + * Phys Disk of a volume has been deleted. + * Expose it to the OS. + */ + if (mpssas_add_device(sc, + element->PhysDiskDevHandle, 0)){ + printf("%s: failed to add device with " + "handle 0x%x\n", __func__, + element->PhysDiskDevHandle); + mpssas_prepare_remove(sassc, element-> + PhysDiskDevHandle); + } + break; + } + } + /* + * refcount was incremented for this event in + * mpssas_evt_handler. Decrement it here because the event has + * been processed. + */ + mpssas_startup_decrement(sassc); + break; + } + case MPI2_EVENT_IR_VOLUME: + { + Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; + + /* + * Informational only. + */ + mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n"); + switch (event_data->ReasonCode) { + case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED: + mps_dprint(sc, MPS_INFO, " Volume Settings " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", event_data->PreviousValue, + event_data->NewValue, + event_data->VolDevHandle); + break; + case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED: + mps_dprint(sc, MPS_INFO, " Volume Status " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", event_data->PreviousValue, + event_data->NewValue, + event_data->VolDevHandle); + break; + case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED: + mps_dprint(sc, MPS_INFO, " Volume State " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", event_data->PreviousValue, + event_data->NewValue, + event_data->VolDevHandle); + break; + default: + break; + } + break; + } + case MPI2_EVENT_IR_PHYSICAL_DISK: + { + Mpi2EventDataIrPhysicalDisk_t *event_data = + fw_event->event_data; + + /* + * Informational only. + */ + mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n"); + switch (event_data->ReasonCode) { + case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED: + mps_dprint(sc, MPS_INFO, " Phys Disk Settings " + "changed from 0x%x to 0x%x for Phys Disk Number " + "%d and handle 0x%x at Enclosure handle 0x%x, Slot " + "%d", event_data->PreviousValue, + event_data->NewValue, event_data->PhysDiskNum, + event_data->PhysDiskDevHandle, + event_data->EnclosureHandle, event_data->Slot); + break; + case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED: + mps_dprint(sc, MPS_INFO, " Phys Disk Status changed " + "from 0x%x to 0x%x for Phys Disk Number %d and " + "handle 0x%x at Enclosure handle 0x%x, Slot %d", + event_data->PreviousValue, event_data->NewValue, + event_data->PhysDiskNum, + event_data->PhysDiskDevHandle, + event_data->EnclosureHandle, event_data->Slot); + break; + case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED: + mps_dprint(sc, MPS_INFO, " Phys Disk State changed " + "from 0x%x to 0x%x for Phys Disk Number %d and " + "handle 0x%x at Enclosure handle 0x%x, Slot %d", + event_data->PreviousValue, event_data->NewValue, + event_data->PhysDiskNum, + event_data->PhysDiskDevHandle, + event_data->EnclosureHandle, event_data->Slot); + break; + default: + break; + } + break; + } + case MPI2_EVENT_IR_OPERATION_STATUS: + { + Mpi2EventDataIrOperationStatus_t *event_data = + fw_event->event_data; + + /* + * Informational only. + */ + mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n"); + mps_dprint(sc, MPS_INFO, " RAID Operation of %d is %d " + "percent complete for Volume with handle 0x%x", + event_data->RAIDOperation, event_data->PercentComplete, + event_data->VolDevHandle); + break; + } + case MPI2_EVENT_LOG_ENTRY_ADDED: + { + pMpi2EventDataLogEntryAdded_t logEntry; + uint16_t logQualifier; + uint8_t logCode; + + logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data; + logQualifier = logEntry->LogEntryQualifier; + + if (logQualifier == MPI2_WD_LOG_ENTRY) { + logCode = logEntry->LogData[0]; + + switch (logCode) { + case MPI2_WD_SSD_THROTTLING: + printf("WarpDrive Warning: IO Throttling has " + "occurred in the WarpDrive subsystem. " + "Check WarpDrive documentation for " + "additional details\n"); + break; + case MPI2_WD_DRIVE_LIFE_WARN: + printf("WarpDrive Warning: Program/Erase " + "Cycles for the WarpDrive subsystem in " + "degraded range. Check WarpDrive " + "documentation for additional details\n"); + break; + case MPI2_WD_DRIVE_LIFE_DEAD: + printf("WarpDrive Fatal Error: There are no " + "Program/Erase Cycles for the WarpDrive " + "subsystem. The storage device will be in " + "read-only mode. Check WarpDrive " + "documentation for additional details\n"); + break; + case MPI2_WD_RAIL_MON_FAIL: + printf("WarpDrive Fatal Error: The Backup Rail " + "Monitor has failed on the WarpDrive " + "subsystem. Check WarpDrive documentation " + "for additional details\n"); + break; + default: + break; + } + } + break; + } + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: + default: + mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n", + fw_event->event); + break; + + } + mpssas_fw_event_free(sc, fw_event); + } + + void + mpssas_firmware_event_work(void *arg, int pending) + { + struct mps_fw_event_work *fw_event; + struct mps_softc *sc; + + sc = (struct mps_softc *)arg; + mps_lock(sc); + while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) { + TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link); + mpssas_fw_work(sc, fw_event); + } + mps_unlock(sc); + } + + static int + mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){ + char devstring[80]; + struct mpssas_softc *sassc; + struct mpssas_target *targ; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t config_page; + uint64_t sas_address, sata_sas_address; + uint64_t parent_sas_address = 0; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u32 device_info, parent_devinfo = 0; + unsigned int id; + int ret; + int error = 0; + + sassc = sc->sassc; + mpssas_startup_increment(sassc); + if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { + printf("%s: error reading SAS device page0\n", __func__); + error = ENXIO; + goto out; + } + + device_info = le32toh(config_page.DeviceInfo); + + if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) + && (config_page.ParentDevHandle != 0)) { + Mpi2ConfigReply_t tmp_mpi_reply; + Mpi2SasDevicePage0_t parent_config_page; + + if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply, + &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + le16toh(config_page.ParentDevHandle)))) { + printf("%s: error reading SAS device %#x page0\n", + __func__, le16toh(config_page.ParentDevHandle)); + } else { + parent_sas_address = parent_config_page.SASAddress.High; + parent_sas_address = (parent_sas_address << 32) | + parent_config_page.SASAddress.Low; + parent_devinfo = le32toh(parent_config_page.DeviceInfo); + } + } + /* TODO Check proper endianess */ + sas_address = config_page.SASAddress.High; + sas_address = (sas_address << 32) | + config_page.SASAddress.Low; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) + == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { + ret = mpssas_get_sas_address_for_sata_disk(sc, + &sata_sas_address, handle, device_info); + if (!ret) + id = mps_mapping_get_sas_id(sc, + sata_sas_address, handle); + else + id = mps_mapping_get_sas_id(sc, + sas_address, handle); + } else + id = mps_mapping_get_sas_id(sc, sas_address, + handle); + } else + id = mps_mapping_get_sas_id(sc, sas_address, handle); + + if (id == MPS_MAP_BAD_ID) { + printf("failure at %s:%d/%s()! Could not get ID for device " + "with handle 0x%04x\n", __FILE__, __LINE__, __func__, + handle); + error = ENXIO; + goto out; + } + mps_vprintf(sc, "SAS Address from SAS device page0 = %jx\n", + sas_address); + targ = &sassc->targets[id]; + targ->devinfo = device_info; + targ->devname = le32toh(config_page.DeviceName.High); + targ->devname = (targ->devname << 32) | + le32toh(config_page.DeviceName.Low); + targ->encl_handle = le16toh(config_page.EnclosureHandle); + targ->encl_slot = le16toh(config_page.Slot); + targ->handle = handle; + targ->parent_handle = le16toh(config_page.ParentDevHandle); + targ->sasaddr = mps_to_u64(&config_page.SASAddress); + targ->parent_sasaddr = le64toh(parent_sas_address); + targ->parent_devinfo = parent_devinfo; + targ->tid = id; + targ->linkrate = (linkrate>>4); + targ->flags = 0; + TAILQ_INIT(&targ->commands); + TAILQ_INIT(&targ->timedout_commands); + SLIST_INIT(&targ->luns); + mps_describe_devinfo(targ->devinfo, devstring, 80); + mps_vprintf(sc, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring, + mps_describe_table(mps_linkrate_names, targ->linkrate), + targ->handle, targ->encl_handle, targ->encl_slot); + if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) + mpssas_rescan_target(sc, targ); + mps_vprintf(sc, "Target id 0x%x added\n", targ->tid); + out: + mpssas_startup_decrement(sassc); + return (error); + + } + + int + mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc, + u64 *sas_address, u16 handle, u32 device_info) + { + Mpi2SataPassthroughReply_t mpi_reply; + int i, rc, try_count; + u32 *bufferptr; + union _sata_sas_address hash_address; + struct _ata_identify_device_data ata_identify; + u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN]; + u32 ioc_status; + u8 sas_status; + + memset(&ata_identify, 0, sizeof(ata_identify)); + try_count = 0; + do { + rc = mpssas_get_sata_identify(sc, handle, &mpi_reply, + (char *)&ata_identify, sizeof(ata_identify), device_info); + try_count++; + ioc_status = le16toh(mpi_reply.IOCStatus) + & MPI2_IOCSTATUS_MASK; + sas_status = mpi_reply.SASStatus; + } while ((rc == -EAGAIN || ioc_status || sas_status) && + (try_count < 5)); + + if (rc == 0 && !ioc_status && !sas_status) { + mps_dprint(sc, MPS_INFO, "%s: got SATA identify successfully " + "for handle = 0x%x with try_count = %d\n", + __func__, handle, try_count); + } else { + mps_dprint(sc, MPS_INFO, "%s: handle = 0x%x failed\n", + __func__, handle); + return -1; + } + /* Copy & byteswap the 40 byte model number to a buffer */ + for (i = 0; i < MPT2SAS_MN_LEN; i += 2) { + buffer[i] = ((u8 *)ata_identify.model_number)[i + 1]; + buffer[i + 1] = ((u8 *)ata_identify.model_number)[i]; + } + /* Copy & byteswap the 20 byte serial number to a buffer */ + for (i = 0; i < MPT2SAS_SN_LEN; i += 2) { + buffer[MPT2SAS_MN_LEN + i] = + ((u8 *)ata_identify.serial_number)[i + 1]; + buffer[MPT2SAS_MN_LEN + i + 1] = + ((u8 *)ata_identify.serial_number)[i]; + } + bufferptr = (u32 *)buffer; + /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8, + * so loop through the first 56 bytes (7*8), + * and then add in the last dword. + */ + hash_address.word.low = 0; + hash_address.word.high = 0; + for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) { + hash_address.word.low += *bufferptr; + bufferptr++; + hash_address.word.high += *bufferptr; + bufferptr++; + } + /* Add the last dword */ + hash_address.word.low += *bufferptr; + /* Make sure the hash doesn't start with 5, because it could clash + * with a SAS address. Change 5 to a D. + */ + if ((hash_address.word.high & 0x000000F0) == (0x00000050)) + hash_address.word.high |= 0x00000080; + *sas_address = (u64)hash_address.wwid[0] << 56 | + (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 | + (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 | + (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 | + (u64)hash_address.wwid[7]; + return 0; + } + + static int + mpssas_get_sata_identify(struct mps_softc *sc, u16 handle, + Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo) + { + Mpi2SataPassthroughRequest_t *mpi_request; + Mpi2SataPassthroughReply_t *reply; + struct mps_command *cm; + char *buffer; + int error = 0; + + buffer = malloc( sz, M_MPT2, M_NOWAIT | M_ZERO); + if (!buffer) + return ENOMEM; + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req; + bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST)); + mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH; + mpi_request->VF_ID = 0; + mpi_request->DevHandle = htole16(handle); + mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO | + MPI2_SATA_PT_REQ_PT_FLAGS_READ); + mpi_request->DataLength = htole32(sz); + mpi_request->CommandFIS[0] = 0x27; + mpi_request->CommandFIS[1] = 0x80; + mpi_request->CommandFIS[2] = (devinfo & + MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC; + cm->cm_sge = &mpi_request->SGL; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = buffer; + cm->cm_length = htole32(sz); + error = mps_request_polled(sc, cm); + reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + bcopy(buffer, id_buffer, sz); + bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t)); + if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS) { + printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n", + __func__, reply->IOCStatus); + error = ENXIO; + goto out; + } + out: + mps_free_command(sc, cm); + free(buffer, M_MPT2); + return (error); + } + + static int + mpssas_volume_add(struct mps_softc *sc, Mpi2EventIrConfigElement_t *element) + { + struct mpssas_softc *sassc; + struct mpssas_target *targ; + u64 wwid; + u16 handle = le16toh(element->VolDevHandle); + unsigned int id; + int error = 0; + + sassc = sc->sassc; + mpssas_startup_increment(sassc); + mps_config_get_volume_wwid(sc, handle, &wwid); + if (!wwid) { + printf("%s: invalid WWID; cannot add volume to mapping table\n", + __func__); + error = ENXIO; + goto out; + } + + id = mps_mapping_get_raid_id(sc, wwid, handle); + if (id == MPS_MAP_BAD_ID) { + printf("%s: could not get ID for volume with handle 0x%04x and " + "WWID 0x%016llx\n", __func__, handle, + (unsigned long long)wwid); + error = ENXIO; + goto out; + } + + targ = &sassc->targets[id]; + targ->tid = id; + targ->handle = handle; + targ->devname = wwid; + TAILQ_INIT(&targ->commands); + TAILQ_INIT(&targ->timedout_commands); + SLIST_INIT(&targ->luns); + if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) + mpssas_rescan_target(sc, targ); + mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n", + targ->tid, wwid); + out: + mpssas_startup_decrement(sassc); + return (error); + } + + /** + * mpssas_ir_shutdown - IR shutdown notification + * @sc: per adapter object + * + * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that + * the host system is shutting down. + * + * Return nothing. + */ + void + mpssas_ir_shutdown(struct mps_softc *sc) + { + u16 volume_mapping_flags; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + struct dev_mapping_table *mt_entry; + u32 start_idx, end_idx; + unsigned int id, found_volume = 0; + struct mps_command *cm; + Mpi2RaidActionRequest_t *action; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + /* is IR firmware build loaded? */ + if (!sc->ir_firmware) + return; + + /* are there any volumes? Look at IR target IDs. */ + // TODO-later, this should be looked up in the RAID config structure + // when it is implemented. + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { + start_idx = 0; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + start_idx = 1; + } else + start_idx = sc->max_devices - sc->max_volumes; + end_idx = start_idx + sc->max_volumes - 1; + + for (id = start_idx; id < end_idx; id++) { + mt_entry = &sc->mapping_table[id]; + if ((mt_entry->physical_id != 0) && + (mt_entry->missing_count == 0)) { + found_volume = 1; + break; + } + } + + if (!found_volume) + return; + + if ((cm = mps_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed\n", __func__); + return; + } + + action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; + action->Function = MPI2_FUNCTION_RAID_ACTION; + action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + mps_request_polled(sc, cm); + + /* + * Don't check for reply, just leave. + */ + if (cm) + mps_free_command(sc, cm); + } ==== - //depot/users/kenm/FreeBSD-test/sys/dev/mps/mps_sas_lsi.c#1 ==== *** src/sys/dev/mps/mps_table.c.orig --- src/sys/dev/mps/mps_table.c *************** *** 25,34 **** */ #include ! __FBSDID("$FreeBSD: head/sys/dev/mps/mps_table.c 212420 2010-09-10 15:03:56Z ken $"); /* Debugging tables for MPT2 */ #include #include #include --- 25,35 ---- */ #include ! __FBSDID("$FreeBSD$"); /* Debugging tables for MPT2 */ + /* TODO Move headers to mpsvar */ #include #include #include *************** *** 41,46 **** --- 42,50 ---- #include #include #include + #include + #include + #include #include #include *************** *** 53,58 **** --- 57,64 ---- #include #include #include + #include + #include #include #include *** src/sys/dev/mps/mps_table.h.orig --- src/sys/dev/mps/mps_table.h *************** *** 22,29 **** * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD: head/sys/dev/mps/mps_table.h 212420 2010-09-10 15:03:56Z ken $ */ #ifndef _MPS_TABLE_H --- 22,27 ---- *** src/sys/dev/mps/mps_user.c.orig --- src/sys/dev/mps/mps_user.c *************** *** 27,40 **** * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ! * LSI MPS-Fusion Host Adapter FreeBSD userland interface */ #include ! __FBSDID("$FreeBSD: head/sys/dev/mps/mps_user.c 216088 2010-11-30 22:39:46Z ken $"); #include "opt_compat.h" #include #include #include --- 27,70 ---- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ! * LSI MPT-Fusion Host Adapter FreeBSD userland interface ! */ ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ */ #include ! __FBSDID("$FreeBSD$"); #include "opt_compat.h" + /* TODO Move headers to mpsvar */ #include #include #include *************** *** 49,54 **** --- 79,87 ---- #include #include #include + #include + #include + #include #include #include *************** *** 56,70 **** #include #include #include #include #include #include #include #include #include ! #include static d_open_t mps_open; static d_close_t mps_close; --- 89,109 ---- #include #include + #include #include #include #include #include #include + #include + #include + #include #include #include ! #include ! #include ! #include static d_open_t mps_open; static d_close_t mps_close; *************** *** 103,110 **** --- 142,193 ---- struct mps_usr_command *); static int mps_user_command(struct mps_softc *, struct mps_usr_command *); + static int mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data); + static void mps_user_get_adapter_data(struct mps_softc *sc, + mps_adapter_data_t *data); + static void mps_user_read_pci_info(struct mps_softc *sc, + mps_pci_info_t *data); + static uint8_t mps_get_fw_diag_buffer_number(struct mps_softc *sc, + uint32_t unique_id); + static int mps_post_fw_diag_buffer(struct mps_softc *sc, + mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code); + static int mps_release_fw_diag_buffer(struct mps_softc *sc, + mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, + uint32_t diag_type); + static int mps_diag_register(struct mps_softc *sc, + mps_fw_diag_register_t *diag_register, uint32_t *return_code); + static int mps_diag_unregister(struct mps_softc *sc, + mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code); + static int mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, + uint32_t *return_code); + static int mps_diag_read_buffer(struct mps_softc *sc, + mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, + uint32_t *return_code); + static int mps_diag_release(struct mps_softc *sc, + mps_fw_diag_release_t *diag_release, uint32_t *return_code); + static int mps_do_diag_action(struct mps_softc *sc, uint32_t action, + uint8_t *diag_action, uint32_t length, uint32_t *return_code); + static int mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data); + static void mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data); + static void mps_user_event_enable(struct mps_softc *sc, + mps_event_enable_t *data); + static int mps_user_event_report(struct mps_softc *sc, + mps_event_report_t *data); + static int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data); + static int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data); + static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); + /* Macros from compat/freebsd32/freebsd32.h */ + #define PTRIN(v) (void *)(uintptr_t)(v) + #define PTROUT(v) (uint32_t)(uintptr_t)(v) + + #define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) + #define PTRIN_CP(src,dst,fld) \ + do { (dst).fld = PTRIN((src).fld); } while (0) + #define PTROUT_CP(src,dst,fld) \ + do { (dst).fld = PTROUT((src).fld); } while (0) + int mps_attach_user(struct mps_softc *sc) { *************** *** 625,642 **** cm->cm_length = 0; } ! cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; mps_lock(sc); ! err = mps_map_command(sc, cm); ! if (err != 0 && err != EINPROGRESS) { mps_printf(sc, "%s: invalid request: error %d\n", __func__, err); goto Ret; } - msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0); rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; --- 708,724 ---- cm->cm_length = 0; } ! cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; mps_lock(sc); ! err = mps_wait_command(sc, cm, 0); ! if (err) { mps_printf(sc, "%s: invalid request: error %d\n", __func__, err); goto Ret; } rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; *************** *** 664,670 **** if (buf != NULL) free(buf, M_MPSUSER); return (err); ! } static int mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, --- 746,2047 ---- if (buf != NULL) free(buf, M_MPSUSER); return (err); ! } ! ! static int ! mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data) ! { ! MPI2_REQUEST_HEADER *hdr, tmphdr; ! MPI2_DEFAULT_REPLY *rpl; ! struct mps_command *cm = NULL; ! int err = 0, dir = 0, sz; ! uint8_t function = 0; ! u_int sense_len; ! ! /* ! * Only allow one passthru command at a time. Use the MPS_FLAGS_BUSY ! * bit to denote that a passthru is being processed. ! */ ! mps_lock(sc); ! if (sc->mps_flags & MPS_FLAGS_BUSY) { ! mps_dprint(sc, MPS_INFO, "%s: Only one passthru command " ! "allowed at a single time.", __func__); ! mps_unlock(sc); ! return (EBUSY); ! } ! sc->mps_flags |= MPS_FLAGS_BUSY; ! mps_unlock(sc); ! ! /* ! * Do some validation on data direction. Valid cases are: ! * 1) DataSize is 0 and direction is NONE ! * 2) DataSize is non-zero and one of: ! * a) direction is READ or ! * b) direction is WRITE or ! * c) direction is BOTH and DataOutSize is non-zero ! * If valid and the direction is BOTH, change the direction to READ. ! * if valid and the direction is not BOTH, make sure DataOutSize is 0. ! */ ! if (((data->DataSize == 0) && ! (data->DataDirection == MPS_PASS_THRU_DIRECTION_NONE)) || ! ((data->DataSize != 0) && ! ((data->DataDirection == MPS_PASS_THRU_DIRECTION_READ) || ! (data->DataDirection == MPS_PASS_THRU_DIRECTION_WRITE) || ! ((data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) && ! (data->DataOutSize != 0))))) { ! if (data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) ! data->DataDirection = MPS_PASS_THRU_DIRECTION_READ; ! else ! data->DataOutSize = 0; ! } else ! return (EINVAL); ! ! mps_dprint(sc, MPS_INFO, "%s: req 0x%jx %d rpl 0x%jx %d " ! "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__, ! data->PtrRequest, data->RequestSize, data->PtrReply, ! data->ReplySize, data->PtrData, data->DataSize, ! data->PtrDataOut, data->DataOutSize, data->DataDirection); ! ! /* ! * copy in the header so we know what we're dealing with before we ! * commit to allocating a command for it. ! */ ! err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize); ! if (err != 0) ! goto RetFreeUnlocked; ! ! if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) { ! err = EINVAL; ! goto RetFreeUnlocked; ! } ! ! function = tmphdr.Function; ! mps_dprint(sc, MPS_INFO, "%s: Function %02X MsgFlags %02X\n", __func__, ! function, tmphdr.MsgFlags); ! ! /* ! * Handle a passthru TM request. ! */ ! if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) { ! MPI2_SCSI_TASK_MANAGE_REQUEST *task; ! ! mps_lock(sc); ! cm = mpssas_alloc_tm(sc); ! if (cm == NULL) { ! err = EINVAL; ! goto Ret; ! } ! ! /* Copy the header in. Only a small fixup is needed. */ ! task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; ! bcopy(&tmphdr, task, data->RequestSize); ! task->TaskMID = cm->cm_desc.Default.SMID; ! ! cm->cm_data = NULL; ! cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; ! cm->cm_complete = NULL; ! cm->cm_complete_data = NULL; ! ! err = mps_wait_command(sc, cm, 0); ! ! if (err != 0) { ! err = EIO; ! mps_dprint(sc, MPS_FAULT, "%s: task management failed", ! __func__); ! } ! /* ! * Copy the reply data and sense data to user space. ! */ ! if (cm->cm_reply != NULL) { ! rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; ! sz = rpl->MsgLength * 4; ! ! if (sz > data->ReplySize) { ! mps_printf(sc, "%s: reply buffer too small: %d, " ! "required: %d\n", __func__, data->ReplySize, sz); ! err = EINVAL; ! } else { ! mps_unlock(sc); ! copyout(cm->cm_reply, PTRIN(data->PtrReply), ! data->ReplySize); ! mps_lock(sc); ! } ! } ! mpssas_free_tm(sc, cm); ! goto Ret; ! } ! ! mps_lock(sc); ! cm = mps_alloc_command(sc); ! ! if (cm == NULL) { ! mps_printf(sc, "%s: no mps requests\n", __func__); ! err = ENOMEM; ! goto Ret; ! } ! mps_unlock(sc); ! ! hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; ! bcopy(&tmphdr, hdr, data->RequestSize); ! ! /* ! * Do some checking to make sure the IOCTL request contains a valid ! * request. Then set the SGL info. ! */ ! mpi_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize)); ! ! /* ! * Set up for read, write or both. From check above, DataOutSize will ! * be 0 if direction is READ or WRITE, but it will have some non-zero ! * value if the direction is BOTH. So, just use the biggest size to get ! * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set ! * up; the first is for the request and the second will contain the ! * response data. cm_out_len needs to be set here and this will be used ! * when the SGLs are set up. ! */ ! cm->cm_data = NULL; ! cm->cm_length = MAX(data->DataSize, data->DataOutSize); ! cm->cm_out_len = data->DataOutSize; ! cm->cm_flags = 0; ! if (cm->cm_length != 0) { ! cm->cm_data = malloc(cm->cm_length, M_MPSUSER, M_WAITOK | ! M_ZERO); ! if (cm->cm_data == NULL) { ! mps_dprint(sc, MPS_FAULT, "%s: alloc failed for IOCTL " ! "passthru length %d\n", __func__, cm->cm_length); ! } else { ! cm->cm_flags = MPS_CM_FLAGS_DATAIN; ! if (data->DataOutSize) { ! cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; ! err = copyin(PTRIN(data->PtrDataOut), ! cm->cm_data, data->DataOutSize); ! } else if (data->DataDirection == ! MPS_PASS_THRU_DIRECTION_WRITE) { ! cm->cm_flags = MPS_CM_FLAGS_DATAOUT; ! err = copyin(PTRIN(data->PtrData), ! cm->cm_data, data->DataSize); ! } ! if (err != 0) ! mps_dprint(sc, MPS_FAULT, "%s: failed to copy " ! "IOCTL data from user space\n", __func__); ! } ! } ! cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! ! /* ! * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request ! * uses SCSI IO descriptor. ! */ ! if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || ! (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { ! MPI2_SCSI_IO_REQUEST *scsi_io_req; ! ! scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr; ! /* ! * Put SGE for data and data_out buffer at the end of ! * scsi_io_request message header (64 bytes in total). ! * Following above SGEs, the residual space will be used by ! * sense data. ! */ ! scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize - ! 64); ! scsi_io_req->SenseBufferLowAddress = cm->cm_sense_busaddr; ! ! /* ! * Set SGLOffset0 value. This is the number of dwords that SGL ! * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct. ! */ ! scsi_io_req->SGLOffset0 = 24; ! ! /* ! * Setup descriptor info. RAID passthrough must use the ! * default request descriptor which is already set, so if this ! * is a SCSI IO request, change the descriptor to SCSI IO. ! * Also, if this is a SCSI IO request, handle the reply in the ! * mpssas_scsio_complete function. ! */ ! if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { ! cm->cm_desc.SCSIIO.RequestFlags = ! MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; ! cm->cm_desc.SCSIIO.DevHandle = scsi_io_req->DevHandle; ! ! /* ! * Make sure the DevHandle is not 0 because this is a ! * likely error. ! */ ! if (scsi_io_req->DevHandle == 0) { ! err = EINVAL; ! goto RetFreeUnlocked; ! } ! } ! } ! ! mps_lock(sc); ! ! err = mps_wait_command(sc, cm, 0); ! ! if (err) { ! mps_printf(sc, "%s: invalid request: error %d\n", __func__, ! err); ! mps_unlock(sc); ! goto RetFreeUnlocked; ! } ! ! /* ! * Sync the DMA data, if any. Then copy the data to user space. ! */ ! if (cm->cm_data != NULL) { ! if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) ! dir = BUS_DMASYNC_POSTREAD; ! else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) ! dir = BUS_DMASYNC_POSTWRITE;; ! bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); ! bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); ! ! if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) { ! mps_unlock(sc); ! err = copyout(cm->cm_data, ! PTRIN(data->PtrData), data->DataSize); ! mps_lock(sc); ! if (err != 0) ! mps_dprint(sc, MPS_FAULT, "%s: failed to copy " ! "IOCTL data to user space\n", __func__); ! } ! } ! ! /* ! * Copy the reply data and sense data to user space. ! */ ! if (cm->cm_reply != NULL) { ! rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; ! sz = rpl->MsgLength * 4; ! ! if (sz > data->ReplySize) { ! mps_printf(sc, "%s: reply buffer too small: %d, " ! "required: %d\n", __func__, data->ReplySize, sz); ! err = EINVAL; ! } else { ! mps_unlock(sc); ! copyout(cm->cm_reply, PTRIN(data->PtrReply), ! data->ReplySize); ! mps_lock(sc); ! } ! ! if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || ! (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { ! if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & ! MPI2_SCSI_STATE_AUTOSENSE_VALID) { ! sense_len = ! MIN(((MPI2_SCSI_IO_REPLY *)rpl)->SenseCount, ! sizeof(struct scsi_sense_data)); ! mps_unlock(sc); ! copyout(cm->cm_sense, cm->cm_req + 64, sense_len); ! mps_lock(sc); ! } ! } ! } ! mps_unlock(sc); ! ! RetFreeUnlocked: ! mps_lock(sc); ! ! if (cm != NULL) { ! if (cm->cm_data) ! free(cm->cm_data, M_MPSUSER); ! mps_free_command(sc, cm); ! } ! Ret: ! sc->mps_flags &= ~MPS_FLAGS_BUSY; ! mps_unlock(sc); ! ! return (err); ! } ! ! static void ! mps_user_get_adapter_data(struct mps_softc *sc, mps_adapter_data_t *data) ! { ! Mpi2ConfigReply_t mpi_reply; ! Mpi2BiosPage3_t config_page; ! ! /* ! * Use the PCI interface functions to get the Bus, Device, and Function ! * information. ! */ ! data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mps_dev); ! data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mps_dev); ! data->PciInformation.u.bits.FunctionNumber = ! pci_get_function(sc->mps_dev); ! ! /* ! * Get the FW version that should already be saved in IOC Facts. ! */ ! data->MpiFirmwareVersion = sc->facts->FWVersion.Word; ! ! /* ! * General device info. ! */ ! data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2; ! if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) ! data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200; ! data->PCIDeviceHwId = pci_get_device(sc->mps_dev); ! data->PCIDeviceHwRev = pci_read_config(sc->mps_dev, PCIR_REVID, 1); ! data->SubSystemId = pci_get_subdevice(sc->mps_dev); ! data->SubsystemVendorId = pci_get_subvendor(sc->mps_dev); ! ! /* ! * Get the driver version. ! */ ! strcpy((char *)&data->DriverVersion[0], MPS_DRIVER_VERSION); ! ! /* ! * Need to get BIOS Config Page 3 for the BIOS Version. ! */ ! data->BiosVersion = 0; ! if (mps_config_get_bios_pg3(sc, &mpi_reply, &config_page)) ! printf("%s: Error while retrieving BIOS Version\n", __func__); ! else ! data->BiosVersion = config_page.BiosVersion; ! } ! ! static void ! mps_user_read_pci_info(struct mps_softc *sc, mps_pci_info_t *data) ! { ! int i; ! ! /* ! * Use the PCI interface functions to get the Bus, Device, and Function ! * information. ! */ ! data->BusNumber = pci_get_bus(sc->mps_dev); ! data->DeviceNumber = pci_get_slot(sc->mps_dev); ! data->FunctionNumber = pci_get_function(sc->mps_dev); ! ! /* ! * Now get the interrupt vector and the pci header. The vector can ! * only be 0 right now. The header is the first 256 bytes of config ! * space. ! */ ! data->InterruptVector = 0; ! for (i = 0; i < sizeof (data->PciHeader); i++) { ! data->PciHeader[i] = pci_read_config(sc->mps_dev, i, 1); ! } ! } ! ! static uint8_t ! mps_get_fw_diag_buffer_number(struct mps_softc *sc, uint32_t unique_id) ! { ! uint8_t index; ! ! for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { ! if (sc->fw_diag_buffer_list[index].unique_id == unique_id) { ! return (index); ! } ! } ! ! return (MPS_FW_DIAGNOSTIC_UID_NOT_FOUND); ! } ! ! static int ! mps_post_fw_diag_buffer(struct mps_softc *sc, ! mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code) ! { ! MPI2_DIAG_BUFFER_POST_REQUEST *req; ! MPI2_DIAG_BUFFER_POST_REPLY *reply; ! struct mps_command *cm = NULL; ! int i, status; ! ! /* ! * If buffer is not enabled, just leave. ! */ ! *return_code = MPS_FW_DIAG_ERROR_POST_FAILED; ! if (!pBuffer->enabled) { ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Clear some flags initially. ! */ ! pBuffer->force_release = FALSE; ! pBuffer->valid_data = FALSE; ! pBuffer->owned_by_firmware = FALSE; ! ! /* ! * Get a command. ! */ ! cm = mps_alloc_command(sc); ! if (cm == NULL) { ! mps_printf(sc, "%s: no mps requests\n", __func__); ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Build the request for releasing the FW Diag Buffer and send it. ! */ ! req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req; ! req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; ! req->BufferType = pBuffer->buffer_type; ! req->ExtendedType = pBuffer->extended_type; ! req->BufferLength = pBuffer->size; ! for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++) ! req->ProductSpecific[i] = pBuffer->product_specific[i]; ! mps_from_u64(sc->fw_diag_busaddr, &req->BufferAddress); ! cm->cm_data = NULL; ! cm->cm_length = 0; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! cm->cm_complete_data = NULL; ! ! /* ! * Send command synchronously. ! */ ! status = mps_wait_command(sc, cm, 0); ! if (status) { ! mps_printf(sc, "%s: invalid request: error %d\n", __func__, ! status); ! status = MPS_DIAG_FAILURE; ! goto done; ! } ! ! /* ! * Process POST reply. ! */ ! reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; ! if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { ! status = MPS_DIAG_FAILURE; ! mps_dprint(sc, MPS_FAULT, "%s: post of FW Diag Buffer failed " ! "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and " ! "TransferLength = 0x%x\n", __func__, reply->IOCStatus, ! reply->IOCLogInfo, reply->TransferLength); ! goto done; ! } ! ! /* ! * Post was successful. ! */ ! pBuffer->valid_data = TRUE; ! pBuffer->owned_by_firmware = TRUE; ! *return_code = MPS_FW_DIAG_ERROR_SUCCESS; ! status = MPS_DIAG_SUCCESS; ! ! done: ! mps_free_command(sc, cm); ! return (status); ! } ! ! static int ! mps_release_fw_diag_buffer(struct mps_softc *sc, ! mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, ! uint32_t diag_type) ! { ! MPI2_DIAG_RELEASE_REQUEST *req; ! MPI2_DIAG_RELEASE_REPLY *reply; ! struct mps_command *cm = NULL; ! int status; ! ! /* ! * If buffer is not enabled, just leave. ! */ ! *return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED; ! if (!pBuffer->enabled) { ! mps_dprint(sc, MPS_INFO, "%s: This buffer type is not supported " ! "by the IOC", __func__); ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Clear some flags initially. ! */ ! pBuffer->force_release = FALSE; ! pBuffer->valid_data = FALSE; ! pBuffer->owned_by_firmware = FALSE; ! ! /* ! * Get a command. ! */ ! cm = mps_alloc_command(sc); ! if (cm == NULL) { ! mps_printf(sc, "%s: no mps requests\n", __func__); ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Build the request for releasing the FW Diag Buffer and send it. ! */ ! req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req; ! req->Function = MPI2_FUNCTION_DIAG_RELEASE; ! req->BufferType = pBuffer->buffer_type; ! cm->cm_data = NULL; ! cm->cm_length = 0; ! cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; ! cm->cm_complete_data = NULL; ! ! /* ! * Send command synchronously. ! */ ! status = mps_wait_command(sc, cm, 0); ! if (status) { ! mps_printf(sc, "%s: invalid request: error %d\n", __func__, ! status); ! status = MPS_DIAG_FAILURE; ! goto done; ! } ! ! /* ! * Process RELEASE reply. ! */ ! reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; ! if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) || ! pBuffer->owned_by_firmware) { ! status = MPS_DIAG_FAILURE; ! mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer " ! "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n", ! __func__, reply->IOCStatus, reply->IOCLogInfo); ! goto done; ! } ! ! /* ! * Release was successful. ! */ ! *return_code = MPS_FW_DIAG_ERROR_SUCCESS; ! status = MPS_DIAG_SUCCESS; ! ! /* ! * If this was for an UNREGISTER diag type command, clear the unique ID. ! */ ! if (diag_type == MPS_FW_DIAG_TYPE_UNREGISTER) { ! pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; ! } ! ! done: ! return (status); ! } ! ! static int ! mps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register, ! uint32_t *return_code) ! { ! mps_fw_diagnostic_buffer_t *pBuffer; ! uint8_t extended_type, buffer_type, i; ! uint32_t buffer_size; ! uint32_t unique_id; ! int status; ! ! extended_type = diag_register->ExtendedType; ! buffer_type = diag_register->BufferType; ! buffer_size = diag_register->RequestedBufferSize; ! unique_id = diag_register->UniqueId; ! ! /* ! * Check for valid buffer type ! */ ! if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Get the current buffer and look up the unique ID. The unique ID ! * should not be found. If it is, the ID is already in use. ! */ ! i = mps_get_fw_diag_buffer_number(sc, unique_id); ! pBuffer = &sc->fw_diag_buffer_list[buffer_type]; ! if (i != MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * The buffer's unique ID should not be registered yet, and the given ! * unique ID cannot be 0. ! */ ! if ((pBuffer->unique_id != MPS_FW_DIAG_INVALID_UID) || ! (unique_id == MPS_FW_DIAG_INVALID_UID)) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * If this buffer is already posted as immediate, just change owner. ! */ ! if (pBuffer->immediate && pBuffer->owned_by_firmware && ! (pBuffer->unique_id == MPS_FW_DIAG_INVALID_UID)) { ! pBuffer->immediate = FALSE; ! pBuffer->unique_id = unique_id; ! return (MPS_DIAG_SUCCESS); ! } ! ! /* ! * Post a new buffer after checking if it's enabled. The DMA buffer ! * that is allocated will be contiguous (nsegments = 1). ! */ ! if (!pBuffer->enabled) { ! *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; ! return (MPS_DIAG_FAILURE); ! } ! if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ ! 1, 0, /* algnmnt, boundary */ ! BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ ! BUS_SPACE_MAXADDR, /* highaddr */ ! NULL, NULL, /* filter, filterarg */ ! buffer_size, /* maxsize */ ! 1, /* nsegments */ ! buffer_size, /* maxsegsize */ ! 0, /* flags */ ! NULL, NULL, /* lockfunc, lockarg */ ! &sc->fw_diag_dmat)) { ! device_printf(sc->mps_dev, "Cannot allocate FW diag buffer DMA " ! "tag\n"); ! return (ENOMEM); ! } ! if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, ! BUS_DMA_NOWAIT, &sc->fw_diag_map)) { ! device_printf(sc->mps_dev, "Cannot allocate FW diag buffer " ! "memory\n"); ! return (ENOMEM); ! } ! bzero(sc->fw_diag_buffer, buffer_size); ! bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, ! buffer_size, mps_memaddr_cb, &sc->fw_diag_busaddr, 0); ! pBuffer->size = buffer_size; ! ! /* ! * Copy the given info to the diag buffer and post the buffer. ! */ ! pBuffer->buffer_type = buffer_type; ! pBuffer->immediate = FALSE; ! if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) { ! for (i = 0; i < (sizeof (pBuffer->product_specific) / 4); ! i++) { ! pBuffer->product_specific[i] = ! diag_register->ProductSpecific[i]; ! } ! } ! pBuffer->extended_type = extended_type; ! pBuffer->unique_id = unique_id; ! status = mps_post_fw_diag_buffer(sc, pBuffer, return_code); ! ! /* ! * In case there was a failure, free the DMA buffer. ! */ ! if (status == MPS_DIAG_FAILURE) { ! if (sc->fw_diag_busaddr != 0) ! bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); ! if (sc->fw_diag_buffer != NULL) ! bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, ! sc->fw_diag_map); ! if (sc->fw_diag_dmat != NULL) ! bus_dma_tag_destroy(sc->fw_diag_dmat); ! } ! ! return (status); ! } ! ! static int ! mps_diag_unregister(struct mps_softc *sc, ! mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code) ! { ! mps_fw_diagnostic_buffer_t *pBuffer; ! uint8_t i; ! uint32_t unique_id; ! int status; ! ! unique_id = diag_unregister->UniqueId; ! ! /* ! * Get the current buffer and look up the unique ID. The unique ID ! * should be there. ! */ ! i = mps_get_fw_diag_buffer_number(sc, unique_id); ! if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! ! pBuffer = &sc->fw_diag_buffer_list[i]; ! ! /* ! * Try to release the buffer from FW before freeing it. If release ! * fails, don't free the DMA buffer in case FW tries to access it ! * later. If buffer is not owned by firmware, can't release it. ! */ ! if (!pBuffer->owned_by_firmware) { ! status = MPS_DIAG_SUCCESS; ! } else { ! status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, ! MPS_FW_DIAG_TYPE_UNREGISTER); ! } ! ! /* ! * At this point, return the current status no matter what happens with ! * the DMA buffer. ! */ ! pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; ! if (status == MPS_DIAG_SUCCESS) { ! if (sc->fw_diag_busaddr != 0) ! bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); ! if (sc->fw_diag_buffer != NULL) ! bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, ! sc->fw_diag_map); ! if (sc->fw_diag_dmat != NULL) ! bus_dma_tag_destroy(sc->fw_diag_dmat); ! } ! ! return (status); ! } ! ! static int ! mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, ! uint32_t *return_code) ! { ! mps_fw_diagnostic_buffer_t *pBuffer; ! uint8_t i; ! uint32_t unique_id; ! ! unique_id = diag_query->UniqueId; ! ! /* ! * If ID is valid, query on ID. ! * If ID is invalid, query on buffer type. ! */ ! if (unique_id == MPS_FW_DIAG_INVALID_UID) { ! i = diag_query->BufferType; ! if (i >= MPI2_DIAG_BUF_TYPE_COUNT) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! } else { ! i = mps_get_fw_diag_buffer_number(sc, unique_id); ! if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! } ! ! /* ! * Fill query structure with the diag buffer info. ! */ ! pBuffer = &sc->fw_diag_buffer_list[i]; ! diag_query->BufferType = pBuffer->buffer_type; ! diag_query->ExtendedType = pBuffer->extended_type; ! if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) { ! for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4); ! i++) { ! diag_query->ProductSpecific[i] = ! pBuffer->product_specific[i]; ! } ! } ! diag_query->TotalBufferSize = pBuffer->size; ! diag_query->DriverAddedBufferSize = 0; ! diag_query->UniqueId = pBuffer->unique_id; ! diag_query->ApplicationFlags = 0; ! diag_query->DiagnosticFlags = 0; ! ! /* ! * Set/Clear application flags ! */ ! if (pBuffer->immediate) { ! diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_APP_OWNED; ! } else { ! diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_APP_OWNED; ! } ! if (pBuffer->valid_data || pBuffer->owned_by_firmware) { ! diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_BUFFER_VALID; ! } else { ! diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_BUFFER_VALID; ! } ! if (pBuffer->owned_by_firmware) { ! diag_query->ApplicationFlags |= ! MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; ! } else { ! diag_query->ApplicationFlags &= ! ~MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; ! } ! ! return (MPS_DIAG_SUCCESS); ! } ! ! static int ! mps_diag_read_buffer(struct mps_softc *sc, ! mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, ! uint32_t *return_code) ! { ! mps_fw_diagnostic_buffer_t *pBuffer; ! uint8_t i, *pData; ! uint32_t unique_id; ! int status; ! ! unique_id = diag_read_buffer->UniqueId; ! ! /* ! * Get the current buffer and look up the unique ID. The unique ID ! * should be there. ! */ ! i = mps_get_fw_diag_buffer_number(sc, unique_id); ! if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! ! pBuffer = &sc->fw_diag_buffer_list[i]; ! ! /* ! * Make sure requested read is within limits ! */ ! if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead > ! pBuffer->size) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Copy the requested data from DMA to the diag_read_buffer. The DMA ! * buffer that was allocated is one contiguous buffer. ! */ ! pData = (uint8_t *)(sc->fw_diag_buffer + ! diag_read_buffer->StartingOffset); ! if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0) ! return (MPS_DIAG_FAILURE); ! diag_read_buffer->Status = 0; ! ! /* ! * Set or clear the Force Release flag. ! */ ! if (pBuffer->force_release) { ! diag_read_buffer->Flags |= MPS_FW_DIAG_FLAG_FORCE_RELEASE; ! } else { ! diag_read_buffer->Flags &= ~MPS_FW_DIAG_FLAG_FORCE_RELEASE; ! } ! ! /* ! * If buffer is to be reregistered, make sure it's not already owned by ! * firmware first. ! */ ! status = MPS_DIAG_SUCCESS; ! if (!pBuffer->owned_by_firmware) { ! if (diag_read_buffer->Flags & MPS_FW_DIAG_FLAG_REREGISTER) { ! status = mps_post_fw_diag_buffer(sc, pBuffer, ! return_code); ! } ! } ! ! return (status); ! } ! ! static int ! mps_diag_release(struct mps_softc *sc, mps_fw_diag_release_t *diag_release, ! uint32_t *return_code) ! { ! mps_fw_diagnostic_buffer_t *pBuffer; ! uint8_t i; ! uint32_t unique_id; ! int status; ! ! unique_id = diag_release->UniqueId; ! ! /* ! * Get the current buffer and look up the unique ID. The unique ID ! * should be there. ! */ ! i = mps_get_fw_diag_buffer_number(sc, unique_id); ! if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { ! *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; ! return (MPS_DIAG_FAILURE); ! } ! ! pBuffer = &sc->fw_diag_buffer_list[i]; ! ! /* ! * If buffer is not owned by firmware, it's already been released. ! */ ! if (!pBuffer->owned_by_firmware) { ! *return_code = MPS_FW_DIAG_ERROR_ALREADY_RELEASED; ! return (MPS_DIAG_FAILURE); ! } ! ! /* ! * Release the buffer. ! */ ! status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, ! MPS_FW_DIAG_TYPE_RELEASE); ! return (status); ! } ! ! static int ! mps_do_diag_action(struct mps_softc *sc, uint32_t action, uint8_t *diag_action, ! uint32_t length, uint32_t *return_code) ! { ! mps_fw_diag_register_t diag_register; ! mps_fw_diag_unregister_t diag_unregister; ! mps_fw_diag_query_t diag_query; ! mps_diag_read_buffer_t diag_read_buffer; ! mps_fw_diag_release_t diag_release; ! int status = MPS_DIAG_SUCCESS; ! uint32_t original_return_code; ! ! original_return_code = *return_code; ! *return_code = MPS_FW_DIAG_ERROR_SUCCESS; ! ! switch (action) { ! case MPS_FW_DIAG_TYPE_REGISTER: ! if (!length) { ! *return_code = ! MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! if (copyin(diag_action, &diag_register, ! sizeof(diag_register)) != 0) ! return (MPS_DIAG_FAILURE); ! status = mps_diag_register(sc, &diag_register, ! return_code); ! break; ! ! case MPS_FW_DIAG_TYPE_UNREGISTER: ! if (length < sizeof(diag_unregister)) { ! *return_code = ! MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! if (copyin(diag_action, &diag_unregister, ! sizeof(diag_unregister)) != 0) ! return (MPS_DIAG_FAILURE); ! status = mps_diag_unregister(sc, &diag_unregister, ! return_code); ! break; ! ! case MPS_FW_DIAG_TYPE_QUERY: ! if (length < sizeof (diag_query)) { ! *return_code = ! MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! if (copyin(diag_action, &diag_query, sizeof(diag_query)) ! != 0) ! return (MPS_DIAG_FAILURE); ! status = mps_diag_query(sc, &diag_query, return_code); ! if (status == MPS_DIAG_SUCCESS) ! if (copyout(&diag_query, diag_action, ! sizeof (diag_query)) != 0) ! return (MPS_DIAG_FAILURE); ! break; ! ! case MPS_FW_DIAG_TYPE_READ_BUFFER: ! if (copyin(diag_action, &diag_read_buffer, ! sizeof(diag_read_buffer)) != 0) ! return (MPS_DIAG_FAILURE); ! if (length < diag_read_buffer.BytesToRead) { ! *return_code = ! MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! status = mps_diag_read_buffer(sc, &diag_read_buffer, ! PTRIN(diag_read_buffer.PtrDataBuffer), ! return_code); ! if (status == MPS_DIAG_SUCCESS) { ! if (copyout(&diag_read_buffer, diag_action, ! sizeof(diag_read_buffer) - ! sizeof(diag_read_buffer.PtrDataBuffer)) != ! 0) ! return (MPS_DIAG_FAILURE); ! } ! break; ! ! case MPS_FW_DIAG_TYPE_RELEASE: ! if (length < sizeof(diag_release)) { ! *return_code = ! MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! if (copyin(diag_action, &diag_release, ! sizeof(diag_release)) != 0) ! return (MPS_DIAG_FAILURE); ! status = mps_diag_release(sc, &diag_release, ! return_code); ! break; ! ! default: ! *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; ! status = MPS_DIAG_FAILURE; ! break; ! } ! ! if ((status == MPS_DIAG_FAILURE) && ! (original_return_code == MPS_FW_DIAG_NEW) && ! (*return_code != MPS_FW_DIAG_ERROR_SUCCESS)) ! status = MPS_DIAG_SUCCESS; ! ! return (status); ! } ! ! static int ! mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data) ! { ! int status; ! ! /* ! * Only allow one diag action at one time. ! */ ! if (sc->mps_flags & MPS_FLAGS_BUSY) { ! mps_dprint(sc, MPS_INFO, "%s: Only one FW diag command " ! "allowed at a single time.", __func__); ! return (EBUSY); ! } ! sc->mps_flags |= MPS_FLAGS_BUSY; ! ! /* ! * Send diag action request ! */ ! if (data->Action == MPS_FW_DIAG_TYPE_REGISTER || ! data->Action == MPS_FW_DIAG_TYPE_UNREGISTER || ! data->Action == MPS_FW_DIAG_TYPE_QUERY || ! data->Action == MPS_FW_DIAG_TYPE_READ_BUFFER || ! data->Action == MPS_FW_DIAG_TYPE_RELEASE) { ! status = mps_do_diag_action(sc, data->Action, ! PTRIN(data->PtrDiagAction), data->Length, ! &data->ReturnCode); ! } else ! status = EINVAL; ! ! sc->mps_flags &= ~MPS_FLAGS_BUSY; ! return (status); ! } ! ! /* ! * Copy the event recording mask and the event queue size out. For ! * clarification, the event recording mask (events_to_record) is not the same ! * thing as the event mask (event_mask). events_to_record has a bit set for ! * every event type that is to be recorded by the driver, and event_mask has a ! * bit cleared for every event that is allowed into the driver from the IOC. ! * They really have nothing to do with each other. ! */ ! static void ! mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data) ! { ! uint8_t i; ! ! mps_lock(sc); ! data->Entries = MPS_EVENT_QUEUE_SIZE; ! ! for (i = 0; i < 4; i++) { ! data->Types[i] = sc->events_to_record[i]; ! } ! mps_unlock(sc); ! } ! ! /* ! * Set the driver's event mask according to what's been given. See ! * mps_user_event_query for explanation of the event recording mask and the IOC ! * event mask. It's the app's responsibility to enable event logging by setting ! * the bits in events_to_record. Initially, no events will be logged. ! */ ! static void ! mps_user_event_enable(struct mps_softc *sc, mps_event_enable_t *data) ! { ! uint8_t i; ! ! mps_lock(sc); ! for (i = 0; i < 4; i++) { ! sc->events_to_record[i] = data->Types[i]; ! } ! mps_unlock(sc); ! } ! ! /* ! * Copy out the events that have been recorded, up to the max events allowed. ! */ ! static int ! mps_user_event_report(struct mps_softc *sc, mps_event_report_t *data) ! { ! int status = 0; ! uint32_t size; ! ! mps_lock(sc); ! size = data->Size; ! if ((size >= sizeof(sc->recorded_events)) && (status == 0)) { ! mps_unlock(sc); ! if (copyout((void *)sc->recorded_events, ! PTRIN(data->PtrEvents), size) != 0) ! status = EFAULT; ! mps_lock(sc); ! } else { ! /* ! * data->Size value is not large enough to copy event data. ! */ ! status = EFAULT; ! } ! ! /* ! * Change size value to match the number of bytes that were copied. ! */ ! if (status == 0) ! data->Size = sizeof(sc->recorded_events); ! mps_unlock(sc); ! ! return (status); ! } ! ! /* ! * Record events into the driver from the IOC if they are not masked. ! */ ! void ! mpssas_record_event(struct mps_softc *sc, ! MPI2_EVENT_NOTIFICATION_REPLY *event_reply) ! { ! uint32_t event; ! int i, j; ! uint16_t event_data_len; ! boolean_t sendAEN = FALSE; ! ! event = event_reply->Event; ! ! /* ! * Generate a system event to let anyone who cares know that a ! * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the ! * event mask is set to. ! */ ! if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { ! sendAEN = TRUE; ! } ! ! /* ! * Record the event only if its corresponding bit is set in ! * events_to_record. event_index is the index into recorded_events and ! * event_number is the overall number of an event being recorded since ! * start-of-day. event_index will roll over; event_number will never ! * roll over. ! */ ! i = (uint8_t)(event / 32); ! j = (uint8_t)(event % 32); ! if ((i < 4) && ((1 << j) & sc->events_to_record[i])) { ! i = sc->event_index; ! sc->recorded_events[i].Type = event; ! sc->recorded_events[i].Number = ++sc->event_number; ! bzero(sc->recorded_events[i].Data, MPS_MAX_EVENT_DATA_LENGTH * ! 4); ! event_data_len = event_reply->EventDataLength; ! ! if (event_data_len > 0) { ! /* ! * Limit data to size in m_event entry ! */ ! if (event_data_len > MPS_MAX_EVENT_DATA_LENGTH) { ! event_data_len = MPS_MAX_EVENT_DATA_LENGTH; ! } ! for (j = 0; j < event_data_len; j++) { ! sc->recorded_events[i].Data[j] = ! event_reply->EventData[j]; ! } ! ! /* ! * check for index wrap-around ! */ ! if (++i == MPS_EVENT_QUEUE_SIZE) { ! i = 0; ! } ! sc->event_index = (uint8_t)i; ! ! /* ! * Set flag to send the event. ! */ ! sendAEN = TRUE; ! } ! } ! ! /* ! * Generate a system event if flag is set to let anyone who cares know ! * that an event has occurred. ! */ ! if (sendAEN) { ! //SLM-how to send a system event (see kqueue, kevent) ! // (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS", ! // "SAS", NULL, NULL, DDI_NOSLEEP); ! } ! } ! ! static int ! mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data) ! { ! int status = 0; ! ! switch (data->Command) { ! /* ! * IO access is not supported. ! */ ! case REG_IO_READ: ! case REG_IO_WRITE: ! mps_dprint(sc, MPS_INFO, "IO access is not supported. " ! "Use memory access."); ! status = EINVAL; ! break; ! ! case REG_MEM_READ: ! data->RegData = mps_regread(sc, data->RegOffset); ! break; ! ! case REG_MEM_WRITE: ! mps_regwrite(sc, data->RegOffset, data->RegData); ! break; ! ! default: ! status = EINVAL; ! break; ! } ! ! return (status); ! } ! ! static int ! mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data) ! { ! uint8_t bt2dh = FALSE; ! uint8_t dh2bt = FALSE; ! uint16_t dev_handle, bus, target; ! ! bus = data->Bus; ! target = data->TargetID; ! dev_handle = data->DevHandle; ! ! /* ! * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/ ! * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is ! * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is ! * invalid. ! */ ! if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF)) ! dh2bt = TRUE; ! if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF)) ! bt2dh = TRUE; ! if (!dh2bt && !bt2dh) ! return (EINVAL); ! ! /* ! * Only handle bus of 0. Make sure target is within range. ! */ ! if (bt2dh) { ! if (bus != 0) ! return (EINVAL); ! ! if (target > sc->max_devices) { ! mps_dprint(sc, MPS_FAULT, "Target ID is out of range " ! "for Bus/Target to DevHandle mapping."); ! return (EINVAL); ! } ! dev_handle = sc->mapping_table[target].dev_handle; ! if (dev_handle) ! data->DevHandle = dev_handle; ! } else { ! bus = 0; ! target = mps_mapping_get_sas_id_from_handle(sc, dev_handle); ! data->Bus = bus; ! data->TargetID = target; ! } ! ! return (0); ! } static int mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, *************** *** 674,680 **** struct mps_cfg_page_req *page_req; struct mps_ext_cfg_page_req *ext_page_req; void *mps_page; ! int error; mps_page = NULL; sc = dev->si_drv1; --- 2051,2057 ---- struct mps_cfg_page_req *page_req; struct mps_ext_cfg_page_req *ext_page_req; void *mps_page; ! int error, reset_loop; mps_page = NULL; sc = dev->si_drv1; *************** *** 730,735 **** --- 2107,2204 ---- case MPSIO_MPS_COMMAND: error = mps_user_command(sc, (struct mps_usr_command *)arg); break; + case MPTIOCTL_PASS_THRU: + /* + * The user has requested to pass through a command to be + * executed by the MPT firmware. Call our routine which does + * this. Only allow one passthru IOCTL at one time. + */ + error = mps_user_pass_thru(sc, (mps_pass_thru_t *)arg); + break; + case MPTIOCTL_GET_ADAPTER_DATA: + /* + * The user has requested to read adapter data. Call our + * routine which does this. + */ + error = 0; + mps_user_get_adapter_data(sc, (mps_adapter_data_t *)arg); + break; + case MPTIOCTL_GET_PCI_INFO: + /* + * The user has requested to read pci info. Call + * our routine which does this. + */ + mps_lock(sc); + error = 0; + mps_user_read_pci_info(sc, (mps_pci_info_t *)arg); + mps_unlock(sc); + break; + case MPTIOCTL_RESET_ADAPTER: + mps_lock(sc); + sc->port_enable_complete = 0; + error = mps_reinit(sc); + mps_unlock(sc); + /* + * Wait no more than 5 minutes for Port Enable to complete + */ + for (reset_loop = 0; (reset_loop < MPS_DIAG_RESET_TIMEOUT) && + (!sc->port_enable_complete); reset_loop++) { + DELAY(1000); + } + if (reset_loop == MPS_DIAG_RESET_TIMEOUT) { + printf("Port Enable did not complete after Diag " + "Reset.\n"); + } + break; + case MPTIOCTL_DIAG_ACTION: + /* + * The user has done a diag buffer action. Call our routine + * which does this. Only allow one diag action at one time. + */ + mps_lock(sc); + error = mps_user_diag_action(sc, (mps_diag_action_t *)arg); + mps_unlock(sc); + break; + case MPTIOCTL_EVENT_QUERY: + /* + * The user has done an event query. Call our routine which does + * this. + */ + error = 0; + mps_user_event_query(sc, (mps_event_query_t *)arg); + break; + case MPTIOCTL_EVENT_ENABLE: + /* + * The user has done an event enable. Call our routine which + * does this. + */ + error = 0; + mps_user_event_enable(sc, (mps_event_enable_t *)arg); + break; + case MPTIOCTL_EVENT_REPORT: + /* + * The user has done an event report. Call our routine which + * does this. + */ + error = mps_user_event_report(sc, (mps_event_report_t *)arg); + break; + case MPTIOCTL_REG_ACCESS: + /* + * The user has requested register access. Call our routine + * which does this. + */ + mps_lock(sc); + error = mps_user_reg_access(sc, (mps_reg_access_t *)arg); + mps_unlock(sc); + break; + case MPTIOCTL_BTDH_MAPPING: + /* + * The user has requested to translate a bus/target to a + * DevHandle or a DevHandle to a bus/target. Call our routine + * which does this. + */ + error = mps_user_btdh(sc, (mps_btdh_mapping_t *)arg); + break; default: error = ENOIOCTL; break; *************** *** 743,758 **** #ifdef COMPAT_FREEBSD32 - /* Macros from compat/freebsd32/freebsd32.h */ - #define PTRIN(v) (void *)(uintptr_t)(v) - #define PTROUT(v) (uint32_t)(uintptr_t)(v) - - #define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) - #define PTRIN_CP(src,dst,fld) \ - do { (dst).fld = PTRIN((src).fld); } while (0) - #define PTROUT_CP(src,dst,fld) \ - do { (dst).fld = PTROUT((src).fld); } while (0) - struct mps_cfg_page_req32 { MPI2_CONFIG_PAGE_HEADER header; uint32_t page_address; --- 2212,2217 ---- *** src/sys/dev/mps/mpsvar.h.orig --- src/sys/dev/mps/mpsvar.h *************** *** 22,34 **** * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. ! * ! * $FreeBSD: head/sys/dev/mps/mpsvar.h 219036 2011-02-25 17:30:25Z ken $ */ #ifndef _MPSVAR_H #define _MPSVAR_H #define MPS_DB_MAX_WAIT 2500 #define MPS_REQ_FRAMES 1024 --- 22,65 ---- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. ! * ! * $FreeBSD$ ! */ ! /*- ! * Copyright (c) 2011 LSI Corp. ! * All rights reserved. ! * ! * Redistribution and use in source and binary forms, with or without ! * modification, are permitted provided that the following conditions ! * are met: ! * 1. Redistributions of source code must retain the above copyright ! * notice, this list of conditions and the following disclaimer. ! * 2. Redistributions in binary form must reproduce the above copyright ! * notice, this list of conditions and the following disclaimer in the ! * documentation and/or other materials provided with the distribution. ! * ! * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ! * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ! * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! * SUCH DAMAGE. ! * ! * LSI MPT-Fusion Host Adapter FreeBSD ! * ! * $FreeBSD$ */ #ifndef _MPSVAR_H #define _MPSVAR_H + #define MPS_DRIVER_VERSION "11.255.03.00-fbsd" + #define MPS_DB_MAX_WAIT 2500 #define MPS_REQ_FRAMES 1024 *************** *** 41,52 **** --- 72,208 ---- #define MPS_SGE32_SIZE 8 #define MPS_SGC_SIZE 8 + #define CAN_SLEEP 1 + #define NO_SLEEP 0 + #define MPS_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */ + #define MPS_SCSI_RI_INVALID_FRAME (0x00000002) + + /* + * host mapping related macro definitions + */ + #define MPS_MAPTABLE_BAD_IDX 0xFFFFFFFF + #define MPS_DPM_BAD_IDX 0xFFFF + #define MPS_ENCTABLE_BAD_IDX 0xFF + #define MPS_MAX_MISSING_COUNT 0x0F + #define MPS_DEV_RESERVED 0x20000000 + #define MPS_MAP_IN_USE 0x10000000 + #define MPS_RAID_CHANNEL 1 + #define MPS_MAP_BAD_ID 0xFFFFFFFF + + /* + * WarpDrive controller + */ + #define MPS_CHIP_WD_DEVICE_ID 0x007E + #define MPS_WD_LSI_OEM 0x80 + #define MPS_WD_HIDE_EXPOSE_MASK 0x03 + #define MPS_WD_HIDE_ALWAYS 0x00 + #define MPS_WD_EXPOSE_ALWAYS 0x01 + #define MPS_WD_HIDE_IF_VOLUME 0x02 + #define MPS_WD_RETRY 0x01 + #define MPS_MAN_PAGE10_SIZE 0x5C /* Hardcode for now */ + #define MPS_MAX_DISKS_IN_VOL 10 + + /* + * WarpDrive Event Logging + */ + #define MPI2_WD_LOG_ENTRY 0x8002 + #define MPI2_WD_SSD_THROTTLING 0x0041 + #define MPI2_WD_DRIVE_LIFE_WARN 0x0043 + #define MPI2_WD_DRIVE_LIFE_DEAD 0x0044 + #define MPI2_WD_RAIL_MON_FAIL 0x004D + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + /** + * struct dev_mapping_table - device mapping information + * @physical_id: SAS address for drives or WWID for RAID volumes + * @device_info: bitfield provides detailed info about the device + * @phy_bits: bitfields indicating controller phys + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + * @channel: target channel + * @id: target id + * @missing_count: number of times the device not detected by driver + * @hide_flag: Hide this physical disk/not (foreign configuration) + * @init_complete: Whether the start of the day checks completed or not + */ + struct dev_mapping_table { + u64 physical_id; + u32 device_info; + u32 phy_bits; + u16 dpm_entry_num; + u16 dev_handle; + u8 reserved1; + u8 channel; + u16 id; + u8 missing_count; + u8 init_complete; + u8 TLR_bits; + u8 reserved2; + }; + + /** + * struct enc_mapping_table - mapping information about an enclosure + * @enclosure_id: Logical ID of this enclosure + * @start_index: index to the entry in dev_mapping_table + * @phy_bits: bitfields indicating controller phys + * @dpm_entry_num: index of this enclosure in device persistent map table + * @enc_handle: device handle for the enclosure pointed by this entry + * @num_slots: number of slots in the enclosure + * @start_slot: Starting slot id + * @missing_count: number of times the device not detected by driver + * @removal_flag: used to mark the device for removal + * @skip_search: used as a flag to include/exclude enclosure for search + * @init_complete: Whether the start of the day checks completed or not + */ + struct enc_mapping_table { + u64 enclosure_id; + u32 start_index; + u32 phy_bits; + u16 dpm_entry_num; + u16 enc_handle; + u16 num_slots; + u16 start_slot; + u8 missing_count; + u8 removal_flag; + u8 skip_search; + u8 init_complete; + }; + + /** + * struct map_removal_table - entries to be removed from mapping table + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + */ + struct map_removal_table{ + u16 dpm_entry_num; + u16 dev_handle; + }; + + typedef struct mps_fw_diagnostic_buffer { + size_t size; + uint8_t extended_type; + uint8_t buffer_type; + uint8_t force_release; + uint32_t product_specific[23]; + uint8_t immediate; + uint8_t enabled; + uint8_t valid_data; + uint8_t owned_by_firmware; + uint32_t unique_id; + } mps_fw_diagnostic_buffer_t; + struct mps_softc; struct mps_command; struct mpssas_softc; + union ccb; struct mpssas_target; + struct mps_column_map; MALLOC_DECLARE(M_MPT2); *************** *** 63,75 **** /* * This needs to be at least 2 to support SMP passthrough. */ ! #define MPS_IOVEC_COUNT 2 struct mps_command { TAILQ_ENTRY(mps_command) cm_link; struct mps_softc *cm_sc; void *cm_data; u_int cm_length; struct uio cm_uio; struct iovec cm_iovec[MPS_IOVEC_COUNT]; u_int cm_max_segs; --- 219,234 ---- /* * This needs to be at least 2 to support SMP passthrough. */ ! #define MPS_IOVEC_COUNT 2 struct mps_command { TAILQ_ENTRY(mps_command) cm_link; + TAILQ_ENTRY(mps_command) cm_recovery; struct mps_softc *cm_sc; + union ccb *cm_ccb; void *cm_data; u_int cm_length; + u_int cm_out_len; struct uio cm_uio; struct iovec cm_iovec[MPS_IOVEC_COUNT]; u_int cm_max_segs; *************** *** 82,87 **** --- 241,247 ---- void *cm_complete_data; struct mpssas_target *cm_targ; MPI2_REQUEST_DESCRIPTOR_UNION cm_desc; + u_int cm_lun; u_int cm_flags; #define MPS_CM_FLAGS_POLLED (1 << 0) #define MPS_CM_FLAGS_COMPLETE (1 << 1) *************** *** 89,95 **** #define MPS_CM_FLAGS_DATAOUT (1 << 3) #define MPS_CM_FLAGS_DATAIN (1 << 4) #define MPS_CM_FLAGS_WAKEUP (1 << 5) ! #define MPS_CM_FLAGS_ACTIVE (1 << 6) #define MPS_CM_FLAGS_USE_UIO (1 << 7) #define MPS_CM_FLAGS_SMP_PASS (1 << 8) #define MPS_CM_FLAGS_CHAIN_FAILED (1 << 9) --- 249,255 ---- #define MPS_CM_FLAGS_DATAOUT (1 << 3) #define MPS_CM_FLAGS_DATAIN (1 << 4) #define MPS_CM_FLAGS_WAKEUP (1 << 5) ! #define MPS_CM_FLAGS_DD_IO (1 << 6) #define MPS_CM_FLAGS_USE_UIO (1 << 7) #define MPS_CM_FLAGS_SMP_PASS (1 << 8) #define MPS_CM_FLAGS_CHAIN_FAILED (1 << 9) *************** *** 106,111 **** --- 266,276 ---- struct callout cm_callout; }; + struct mps_column_map { + uint16_t dev_handle; + uint8_t phys_disk_num; + }; + struct mps_event_handle { TAILQ_ENTRY(mps_event_handle) eh_list; mps_evt_callback_t *callback; *************** *** 121,137 **** #define MPS_FLAGS_MSI (1 << 1) #define MPS_FLAGS_BUSY (1 << 2) #define MPS_FLAGS_SHUTDOWN (1 << 3) ! #define MPS_FLAGS_ATTACH_DONE (1 << 4) u_int mps_debug; ! u_int allow_multiple_tm_cmds; int tm_cmds_active; int io_cmds_active; int io_cmds_highwater; int chain_free; int chain_free_lowwater; uint64_t chain_alloc_fail; struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; struct mps_command *commands; struct mps_chain *chains; struct callout periodic; --- 286,309 ---- #define MPS_FLAGS_MSI (1 << 1) #define MPS_FLAGS_BUSY (1 << 2) #define MPS_FLAGS_SHUTDOWN (1 << 3) ! #define MPS_FLAGS_DIAGRESET (1 << 4) ! #define MPS_FLAGS_ATTACH_DONE (1 << 5) ! #define MPS_FLAGS_WD_AVAILABLE (1 << 6) u_int mps_debug; ! u_int disable_msix; ! u_int disable_msi; int tm_cmds_active; int io_cmds_active; int io_cmds_highwater; int chain_free; + int max_chains; int chain_free_lowwater; + #if __FreeBSD_version >= 900030 uint64_t chain_alloc_fail; + #endif struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; + char fw_version[16]; struct mps_command *commands; struct mps_chain *chains; struct callout periodic; *************** *** 139,147 **** struct mpssas_softc *sassc; TAILQ_HEAD(, mps_command) req_list; TAILQ_HEAD(, mps_chain) chain_list; TAILQ_HEAD(, mps_command) tm_list; - TAILQ_HEAD(, mps_command) io_list; int replypostindex; int replyfreeindex; --- 311,319 ---- struct mpssas_softc *sassc; TAILQ_HEAD(, mps_command) req_list; + TAILQ_HEAD(, mps_command) high_priority_req_list; TAILQ_HEAD(, mps_chain) chain_list; TAILQ_HEAD(, mps_command) tm_list; int replypostindex; int replyfreeindex; *************** *** 196,201 **** --- 368,440 ---- bus_addr_t free_busaddr; bus_dma_tag_t queues_dmat; bus_dmamap_t queues_map; + + uint8_t *fw_diag_buffer; + bus_addr_t fw_diag_busaddr; + bus_dma_tag_t fw_diag_dmat; + bus_dmamap_t fw_diag_map; + + uint8_t ir_firmware; + + /* static config pages */ + Mpi2IOCPage8_t ioc_pg8; + + /* host mapping support */ + struct dev_mapping_table *mapping_table; + struct enc_mapping_table *enclosure_table; + struct map_removal_table *removal_table; + uint8_t *dpm_entry_used; + uint8_t *dpm_flush_entry; + Mpi2DriverMappingPage0_t *dpm_pg0; + uint16_t max_devices; + uint16_t max_enclosures; + uint16_t max_expanders; + uint8_t max_volumes; + uint8_t num_enc_table_entries; + uint8_t num_rsvd_entries; + uint8_t num_channels; + uint16_t max_dpm_entries; + uint8_t is_dpm_enable; + uint8_t track_mapping_events; + uint32_t pending_map_events; + uint8_t mt_full_retry; + uint8_t mt_add_device_failed; + + /* FW diag Buffer List */ + mps_fw_diagnostic_buffer_t + fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_COUNT]; + + /* Event Recording IOCTL support */ + uint32_t events_to_record[4]; + mps_event_entry_t recorded_events[MPS_EVENT_QUEUE_SIZE]; + uint8_t event_index; + uint32_t event_number; + + /* EEDP and TLR support */ + uint8_t eedp_enabled; + uint8_t control_TLR; + + /* Shutdown Event Handler */ + eventhandler_tag shutdown_eh; + + /* To track topo events during reset */ + #define MPS_DIAG_RESET_TIMEOUT 300000 + uint8_t wait_for_port_enable; + uint8_t port_enable_complete; + + /* WD controller */ + uint8_t WD_valid_config; + uint8_t WD_hide_expose; + + /* Direct Drive for WarpDrive */ + uint8_t DD_num_phys_disks; + uint16_t DD_dev_handle; + uint32_t DD_stripe_size; + uint32_t DD_stripe_exponent; + uint32_t DD_block_size; + uint16_t DD_block_exponent; + uint64_t DD_max_lba; + struct mps_column_map DD_column_map[MPS_MAX_DISKS_IN_VOL]; }; struct mps_config_params { *************** *** 210,215 **** --- 449,461 ---- void *cbdata; }; + struct scsi_read_capacity_eedp + { + uint8_t addr[8]; + uint8_t length[4]; + uint8_t protect; + }; + static __inline uint32_t mps_regread(struct mps_softc *sc, uint32_t offset) { *************** *** 225,231 **** static __inline void mps_free_reply(struct mps_softc *sc, uint32_t busaddr) { - if (++sc->replyfreeindex >= sc->fqdepth) sc->replyfreeindex = 0; sc->free_queue[sc->replyfreeindex] = busaddr; --- 471,476 ---- *************** *** 242,249 **** sc->chain_free--; if (sc->chain_free < sc->chain_free_lowwater) sc->chain_free_lowwater = sc->chain_free; ! } else sc->chain_alloc_fail++; return (chain); } --- 487,497 ---- sc->chain_free--; if (sc->chain_free < sc->chain_free_lowwater) sc->chain_free_lowwater = sc->chain_free; ! } ! #if __FreeBSD_version >= 900030 ! else sc->chain_alloc_fail++; + #endif return (chain); } *************** *** 262,276 **** { struct mps_chain *chain, *chain_temp; ! if (cm->cm_reply != NULL) { mps_free_reply(sc, cm->cm_reply_data); ! cm->cm_reply = NULL; ! } cm->cm_flags = 0; cm->cm_complete = NULL; cm->cm_complete_data = NULL; ! cm->cm_targ = 0; cm->cm_max_segs = 0; cm->cm_state = MPS_CM_STATE_FREE; TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); --- 510,525 ---- { struct mps_chain *chain, *chain_temp; ! if (cm->cm_reply != NULL) mps_free_reply(sc, cm->cm_reply_data); ! cm->cm_reply = NULL; cm->cm_flags = 0; cm->cm_complete = NULL; cm->cm_complete_data = NULL; ! cm->cm_ccb = NULL; ! cm->cm_targ = NULL; cm->cm_max_segs = 0; + cm->cm_lun = 0; cm->cm_state = MPS_CM_STATE_FREE; TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); *************** *** 295,300 **** --- 544,586 ---- } static __inline void + mps_free_high_priority_command(struct mps_softc *sc, struct mps_command *cm) + { + struct mps_chain *chain, *chain_temp; + + if (cm->cm_reply != NULL) + mps_free_reply(sc, cm->cm_reply_data); + cm->cm_reply = NULL; + cm->cm_flags = 0; + cm->cm_complete = NULL; + cm->cm_complete_data = NULL; + cm->cm_ccb = NULL; + cm->cm_targ = NULL; + cm->cm_lun = 0; + cm->cm_state = MPS_CM_STATE_FREE; + TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { + TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); + mps_free_chain(sc, chain); + } + TAILQ_INSERT_TAIL(&sc->high_priority_req_list, cm, cm_link); + } + + static __inline struct mps_command * + mps_alloc_high_priority_command(struct mps_softc *sc) + { + struct mps_command *cm; + + cm = TAILQ_FIRST(&sc->high_priority_req_list); + if (cm == NULL) + return (NULL); + + TAILQ_REMOVE(&sc->high_priority_req_list, cm, cm_link); + KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n")); + cm->cm_state = MPS_CM_STATE_BUSY; + return (cm); + } + + static __inline void mps_lock(struct mps_softc *sc) { mtx_lock(&sc->mps_mtx); *************** *** 315,320 **** --- 601,612 ---- #define mps_printf(sc, args...) \ device_printf((sc)->mps_dev, ##args) + #define mps_vprintf(sc, args...) \ + do { \ + if (bootverbose) \ + mps_printf(sc, ##args); \ + } while (0) + #define mps_dprint(sc, level, msg, args...) \ do { \ if (sc->mps_debug & level) \ *************** *** 375,381 **** mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); } ! int mps_pci_setup_interrupts(struct mps_softc *); int mps_attach(struct mps_softc *sc); int mps_free(struct mps_softc *sc); void mps_intr(void *); --- 667,675 ---- mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); } ! int mps_pci_setup_interrupts(struct mps_softc *sc); ! int mps_pci_restore(struct mps_softc *sc); ! int mps_attach(struct mps_softc *sc); int mps_free(struct mps_softc *sc); void mps_intr(void *); *************** *** 383,405 **** void mps_intr_locked(void *); int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *, void *, struct mps_event_handle **); int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *); int mps_deregister_events(struct mps_softc *, struct mps_event_handle *); - int mps_request_polled(struct mps_softc *sc, struct mps_command *cm); - void mps_enqueue_request(struct mps_softc *, struct mps_command *); int mps_push_sge(struct mps_command *, void *, size_t, int); int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int); int mps_attach_sas(struct mps_softc *sc); int mps_detach_sas(struct mps_softc *sc); - int mps_map_command(struct mps_softc *sc, struct mps_command *cm); int mps_read_config_page(struct mps_softc *, struct mps_config_params *); int mps_write_config_page(struct mps_softc *, struct mps_config_params *); void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int ); void mpi_init_sge(struct mps_command *cm, void *req, void *sge); int mps_attach_user(struct mps_softc *); void mps_detach_user(struct mps_softc *); SYSCTL_DECL(_hw_mps); #endif --- 677,773 ---- void mps_intr_locked(void *); int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *, void *, struct mps_event_handle **); + int mps_restart(struct mps_softc *); int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *); int mps_deregister_events(struct mps_softc *, struct mps_event_handle *); int mps_push_sge(struct mps_command *, void *, size_t, int); int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int); int mps_attach_sas(struct mps_softc *sc); int mps_detach_sas(struct mps_softc *sc); int mps_read_config_page(struct mps_softc *, struct mps_config_params *); int mps_write_config_page(struct mps_softc *, struct mps_config_params *); void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int ); void mpi_init_sge(struct mps_command *cm, void *req, void *sge); int mps_attach_user(struct mps_softc *); void mps_detach_user(struct mps_softc *); + void mpssas_record_event(struct mps_softc *sc, + MPI2_EVENT_NOTIFICATION_REPLY *event_reply); + + int mps_map_command(struct mps_softc *sc, struct mps_command *cm); + int mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout); + int mps_request_polled(struct mps_softc *sc, struct mps_command *cm); + + int mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2BiosPage3_t *config_page); + int mps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address); + int mps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *, + Mpi2IOCPage8_t *); + int mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply); + int mps_config_get_sas_device_pg0(struct mps_softc *, Mpi2ConfigReply_t *, + Mpi2SasDevicePage0_t *, u32 , u16 ); + int mps_config_get_dpm_pg0(struct mps_softc *, Mpi2ConfigReply_t *, + Mpi2DriverMappingPage0_t *, u16 ); + int mps_config_get_raid_volume_pg1(struct mps_softc *sc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, + u16 handle); + int mps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, + u64 *wwid); + int mps_config_get_raid_pd_pg0(struct mps_softc *sc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, + u32 page_address); + void mpssas_ir_shutdown(struct mps_softc *sc); + + int mps_reinit(struct mps_softc *sc); + void mpssas_handle_reinit(struct mps_softc *sc); + + void mps_base_static_config_pages(struct mps_softc *sc); + void mps_wd_config_pages(struct mps_softc *sc); + + int mps_mapping_initialize(struct mps_softc *); + void mps_mapping_topology_change_event(struct mps_softc *, + Mpi2EventDataSasTopologyChangeList_t *); + int mps_mapping_is_reinit_required(struct mps_softc *); + void mps_mapping_free_memory(struct mps_softc *sc); + int mps_config_set_dpm_pg0(struct mps_softc *, Mpi2ConfigReply_t *, + Mpi2DriverMappingPage0_t *, u16 ); + void mps_mapping_exit(struct mps_softc *); + void mps_mapping_check_devices(struct mps_softc *, int); + int mps_mapping_allocate_memory(struct mps_softc *sc); + unsigned int mps_mapping_get_sas_id(struct mps_softc *, uint64_t , u16); + unsigned int mps_mapping_get_sas_id_from_handle(struct mps_softc *sc, + u16 handle); + unsigned int mps_mapping_get_raid_id(struct mps_softc *sc, u64 wwid, + u16 handle); + unsigned int mps_mapping_get_raid_id_from_handle(struct mps_softc *sc, + u16 volHandle); + void mps_mapping_enclosure_dev_status_change_event(struct mps_softc *, + Mpi2EventDataSasEnclDevStatusChange_t *event_data); + void mps_mapping_ir_config_change_event(struct mps_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data); + void mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event); + void mpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle); + int mpssas_startup(struct mps_softc *sc); + SYSCTL_DECL(_hw_mps); + /* Compatibility shims for different OS versions */ + #if __FreeBSD_version >= 800001 + #define mps_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) + #define mps_kproc_exit(arg) kproc_exit(arg) + #else + #define mps_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kthread_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) + #define mps_kproc_exit(arg) kthread_exit(arg) + #endif + + #if defined(CAM_PRIORITY_XPT) + #define MPS_PRIORITY_XPT CAM_PRIORITY_XPT + #else + #define MPS_PRIORITY_XPT 5 + #endif #endif *** src/sys/modules/mps/Makefile.orig --- src/sys/modules/mps/Makefile *************** *** 1,13 **** ! # $FreeBSD: head/sys/modules/mps/Makefile 213993 2010-10-17 20:01:56Z scottl $ .PATH: ${.CURDIR}/../../dev/mps KMOD= mps SRCS= mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c ! SRCS+= opt_mps.h opt_cam.h opt_compat.h SRCS+= device_if.h bus_if.h pci_if.h #CFLAGS += -DMPS_DEBUG ! DEBUG += -g .include --- 1,14 ---- ! # $FreeBSD$ .PATH: ${.CURDIR}/../../dev/mps KMOD= mps SRCS= mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c ! SRCS+= mps_config.c mps_mapping.c mps_sas_lsi.c ! SRCS+= opt_cam.h opt_compat.h SRCS+= device_if.h bus_if.h pci_if.h #CFLAGS += -DMPS_DEBUG ! DEBUG_FLAGS += -g .include *** src/sys/sys/param.h.orig --- src/sys/sys/param.h *************** *** 58,64 **** * in the range 5 to 9. */ #undef __FreeBSD_version ! #define __FreeBSD_version 1000005 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, --- 58,64 ---- * in the range 5 to 9. */ #undef __FreeBSD_version ! #define __FreeBSD_version 1000006 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, *** src/usr.sbin/mptutil/mpt_cam.c.orig --- src/usr.sbin/mptutil/mpt_cam.c *************** *** 277,283 **** sizeof(struct ccb_hdr)); scsi_read_capacity_16(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, 0, 0, 0, ! &rcaplong, SSD_FULL_SIZE, 5000); /* Disable freezing the device queue */ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; --- 277,283 ---- sizeof(struct ccb_hdr)); scsi_read_capacity_16(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, 0, 0, 0, ! (uint8_t *)&rcaplong, sizeof(rcaplong), SSD_FULL_SIZE, 5000); /* Disable freezing the device queue */ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;