From 175660922b2422bdda81a5967c5dadd176fe1c3c Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Thu, 11 Aug 2011 20:31:01 +0200 Subject: [PATCH] mfi(4): Merge LSI's latest driver changes (updates us to version 3.981). This adds support for a number of cards (according to LSI's README): * LSI MegaRAID SAS 9240-4i * LSI MegaRAID SAS 9240-8i * LSI MegaRAID SAS 9260-4i * LSI MegaRAID SAS 9260-8i * LSI MegaRAID SAS 9260DE-8i * LSI MegaRAID SAS 9260-16i * LSI MegaRAID SAS 9261-8i * LSI MegaRAID SAS 9280-4i4e * LSI MegaRAID SAS 9280-8e * LSI MegaRAID SAS 9280DE-8e * LSI MegaRAID SAS 9280-16i4e * LSI MegaRAID SAS 9280-24i4e It was tested by Tomi Juvonen on an IBM ServeRAID M1015 controller using LSI's 9240-8i IR firmware. --- share/man/man4/mfi.4 | 53 ++- sys/conf/files | 1 + sys/dev/raid/mfi/Makefile | 2 +- sys/dev/raid/mfi/mfi.c | 659 ++++++++++++++++++++++++++++++++--- sys/dev/raid/mfi/mfi_cam.c | 38 +- sys/dev/raid/mfi/mfi_disk.c | 36 +- sys/dev/raid/mfi/mfi_pci.c | 46 ++- sys/dev/raid/mfi/mfi_syspd.c | 323 +++++++++++++++++ sys/dev/raid/mfi/mfireg.h | 86 ++++- sys/dev/raid/mfi/mfivar.h | 64 ++++ 10 files changed, 1241 insertions(+), 67 deletions(-) create mode 100644 sys/dev/raid/mfi/mfi_syspd.c diff --git a/share/man/man4/mfi.4 b/share/man/man4/mfi.4 index a49dcd4554..ffad85e590 100644 --- a/share/man/man4/mfi.4 +++ b/share/man/man4/mfi.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD: src/share/man/man4/mfi.4,v 1.13 2010/05/12 17:12:38 brueffer Exp $ .\" -.Dd November 30, 2010 +.Dd August 11, 2011 .Dt MFI 4 .Os .Sh NAME @@ -49,6 +49,8 @@ mfi_load="YES" This driver is for LSI's next generation PCI Express SAS RAID controllers. Access to RAID arrays (logical disks) from this driver is provided via .Pa /dev/mfid? +and access to JBOD disks is provided via +.Pa /dev/mfisyspd? device nodes. A simple management interface is also provided on a per-controller basis via the @@ -64,6 +66,18 @@ Older SCSI and SATA MegaRAID cards are supported by .Xr amr 4 and will not work with this driver. .Pp +3 Gb/s and 6 Gb/s support both initiator target (IT) and integrated RAID (IR) +firmware (see +.Pa http://kb.lsi.com/KnowledgebaseArticle16266.aspx ) . +The +.Nm +driver supports controllers with an IR image. +At least some cards (such as the +.Tn IBM ServeRAID M1015 ) +will attach to the +.Xr mps 4 +driver when IT firmware is used. +.Pp Two sysctls are provided to tune the .Nm driver's behavior when a request is made to remove a mounted volume. @@ -85,12 +99,36 @@ LSI MegaRAID SAS 8408E .It LSI MegaRAID SAS 8480E .It -LSI MegaRAID SAS 9260 +LSI MegaRAID SAS 9240-4i +.It +LSI MegaRAID SAS 9240-8i +.It +LSI MegaRAID SAS 9260-4i +.It +LSI MegaRAID SAS 9260-8i +.It +LSI MegaRAID SAS 9260DE-8i +.It +LSI MegaRAID SAS 9260-16i +.It +LSI MegaRAID SAS 9261-8i +.It +LSI MegaRAID SAS 9280-4i4e +.It +LSI MegaRAID SAS 9280-8e +.It +LSI MegaRAID SAS 9280DE-8e +.It +LSI MegaRAID SAS 9280-16i4e +.It +LSI MegaRAID SAS 9280-24i4e .It Dell PERC5 .It Dell PERC6 .It +IBM ServeRAID M1015 SAS/SATA +.It IBM ServeRAID M5015 SAS/SATA .It IBM ServeRAID-MR10i @@ -98,9 +136,11 @@ IBM ServeRAID-MR10i Intel RAID Controller SROMBSAS18E .El .Sh FILES -.Bl -tag -width ".Pa /dev/mfid?" -compact +.Bl -tag -width ".Pa /dev/mfisyspd?" -compact .It Pa /dev/mfid? array/logical disk interface +.It Pa /dev/mfisyspd? +JBOD disk interface .It Pa /dev/mfi? management interface .El @@ -108,9 +148,12 @@ management interface .Bl -diag .It "mfid%d: Unable to delete busy device" An attempt was made to remove a mounted volume. +.It "mfisyspd%d: Unable to delete busy device" +dito for JBOD disks .El .Sh SEE ALSO .Xr amr 4 , +.Xr mps 4 , .Xr pci 4 , .Xr mfiutil 8 .Sh HISTORY @@ -123,5 +166,5 @@ The .Nm driver and this manual page were written by .An Scott Long Aq scottl@FreeBSD.org . -.Sh BUGS -The driver does not support big-endian architectures at this time. +.\".Sh BUGS +.\"The driver does not support big-endian architectures at this time. diff --git a/sys/conf/files b/sys/conf/files index 09fb92589c..44f9272ea8 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -592,6 +592,7 @@ dev/raid/mfi/mfi.c optional mfi dev/raid/mfi/mfi_debug.c optional mfi dev/raid/mfi/mfi_pci.c optional mfi pci dev/raid/mfi/mfi_disk.c optional mfi +dev/raid/mfi/mfi_syspd.c optional mfi dev/raid/mfi/mfi_linux.c optional mfi compat_linux dev/raid/mfi/mfi_cam.c optional mfip scbus dev/netif/mii_layer/mii.c optional miibus diff --git a/sys/dev/raid/mfi/Makefile b/sys/dev/raid/mfi/Makefile index 5a81b72629..809eac3af3 100644 --- a/sys/dev/raid/mfi/Makefile +++ b/sys/dev/raid/mfi/Makefile @@ -8,7 +8,7 @@ SUBDIR+= mfi_linux .endif KMOD= mfi -SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c +SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c mfi_syspd.c SRCS+= opt_mfi.h opt_cam.h SRCS+= device_if.h bus_if.h pci_if.h diff --git a/sys/dev/raid/mfi/mfi.c b/sys/dev/raid/mfi/mfi.c index 210f5f8292..e48d06d637 100644 --- a/sys/dev/raid/mfi/mfi.c +++ b/sys/dev/raid/mfi/mfi.c @@ -48,6 +48,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi.c,v 1.57 2011/07/14 20:20:33 jhb Exp $ */ @@ -71,6 +101,8 @@ #include #include +#include + #include #include #include @@ -88,13 +120,18 @@ static void mfi_data_cb(void *, bus_dma_segment_t *, int, int); static void mfi_startup(void *arg); static void mfi_intr(void *arg); static void mfi_ldprobe(struct mfi_softc *sc); +static void mfi_syspdprobe(struct mfi_softc *sc); static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale); static void mfi_aen_complete(struct mfi_command *); static int mfi_aen_setup(struct mfi_softc *, uint32_t); static int mfi_add_ld(struct mfi_softc *sc, int); static void mfi_add_ld_complete(struct mfi_command *); +static int mfi_add_sys_pd(struct mfi_softc *sc, int); +static void mfi_add_sys_pd_complete(struct mfi_command *); static struct mfi_command * mfi_bio_command(struct mfi_softc *); static void mfi_bio_complete(struct mfi_command *); +static struct mfi_command * mfi_build_ldio(struct mfi_softc *,struct bio*); +static struct mfi_command * mfi_build_syspdio(struct mfi_softc *,struct bio*); static int mfi_mapcmd(struct mfi_softc *, struct mfi_command *); static int mfi_send_frame(struct mfi_softc *, struct mfi_command *); static void mfi_complete(struct mfi_softc *, struct mfi_command *); @@ -163,11 +200,14 @@ mfi_enable_intr_xscale(struct mfi_softc *sc) static void mfi_enable_intr_ppc(struct mfi_softc *sc) { - MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); if (sc->mfi_flags & MFI_FLAGS_1078) { + MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM); } else if (sc->mfi_flags & MFI_FLAGS_GEN2) { + MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM); + } else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { + MFI_WRITE4(sc, MFI_OMSK, ~0x00000001); } } @@ -202,30 +242,33 @@ mfi_check_clear_intr_ppc(struct mfi_softc *sc) int32_t status; status = MFI_READ4(sc, MFI_OSTS); - if (sc->mfi_flags & MFI_FLAGS_1078) { - if (!(status & MFI_1078_RM)) { - return 1; - } - } else if (sc->mfi_flags & MFI_FLAGS_GEN2) { - if (!(status & MFI_GEN2_RM)) { - return 1; - } - } + if (((sc->mfi_flags & MFI_FLAGS_1078) && !(status & MFI_1078_RM)) || + ((sc->mfi_flags & MFI_FLAGS_GEN2) && !(status & MFI_GEN2_RM)) || + ((sc->mfi_flags & MFI_FLAGS_SKINNY) && !(status & MFI_SKINNY_RM))) + return 1; - MFI_WRITE4(sc, MFI_ODCR0, status); + if (sc->mfi_flags & MFI_FLAGS_SKINNY) + MFI_WRITE4(sc, MFI_OSTS, status); + else + MFI_WRITE4(sc, MFI_ODCR0, status); return 0; } static void mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt) { - MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt); + MFI_WRITE4(sc, MFI_IQP,(bus_add >>3) | frame_cnt); } static void mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt) { - MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 ); + if (sc->mfi_flags & MFI_FLAGS_SKINNY) { + MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt << 1) | 1); + MFI_WRITE4(sc, MFI_IQPH, 0x00000000); + } else { + MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt << 1) | 1); + } } static int @@ -233,8 +276,13 @@ mfi_transition_firmware(struct mfi_softc *sc) { uint32_t fw_state, cur_state; int max_wait, i; + uint32_t cur_abs_reg_val = 0; + uint32_t prev_abs_reg_val = 0; + bus_space_handle_t idb; - fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK; + cur_abs_reg_val = sc->mfi_read_fw_status(sc); + fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; + idb = sc->mfi_flags & MFI_FLAGS_SKINNY ? MFI_SKINNY_IDB : MFI_IDB; while (fw_state != MFI_FWSTATE_READY) { if (bootverbose) device_printf(sc->mfi_dev, "Waiting for firmware to " @@ -245,11 +293,11 @@ mfi_transition_firmware(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Firmware fault\n"); return (ENXIO); case MFI_FWSTATE_WAIT_HANDSHAKE: - MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); + MFI_WRITE4(sc, idb, MFI_FWINIT_CLEAR_HANDSHAKE); max_wait = 2; break; case MFI_FWSTATE_OPERATIONAL: - MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); + MFI_WRITE4(sc, idb, MFI_FWINIT_READY); max_wait = 10; break; case MFI_FWSTATE_UNDEFINED: @@ -257,12 +305,15 @@ mfi_transition_firmware(struct mfi_softc *sc) max_wait = 2; break; case MFI_FWSTATE_FW_INIT: - case MFI_FWSTATE_DEVICE_SCAN: case MFI_FWSTATE_FLUSH_CACHE: max_wait = 20; break; + case MFI_FWSTATE_DEVICE_SCAN: + max_wait = 180; /* wait for 180 seconds */ + prev_abs_reg_val = cur_abs_reg_val; + break; case MFI_FWSTATE_BOOT_MESSAGE_PENDING: - MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); + MFI_WRITE4(sc, idb, MFI_FWINIT_HOTPLUG); max_wait = 10; break; default: @@ -271,12 +322,18 @@ mfi_transition_firmware(struct mfi_softc *sc) return (ENXIO); } for (i = 0; i < (max_wait * 10); i++) { - fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK; + cur_abs_reg_val = sc->mfi_read_fw_status(sc); + fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; if (fw_state == cur_state) DELAY(100000); else break; } + if (fw_state == MFI_FWSTATE_DEVICE_SCAN) { + /* Check the device scanning progress */ + if (prev_abs_reg_val != cur_abs_reg_val) + continue; + } if (fw_state == cur_state) { device_printf(sc->mfi_dev, "Firmware stuck in state " "%#x\n", fw_state); @@ -286,6 +343,16 @@ mfi_transition_firmware(struct mfi_softc *sc) return (0); } +#if defined(__x86_64__) +static void +mfi_addr64_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + uint64_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} +#else static void mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { @@ -294,6 +361,7 @@ mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) addr = arg; *addr = segs[0].ds_addr; } +#endif int mfi_attach(struct mfi_softc *sc) @@ -302,11 +370,12 @@ mfi_attach(struct mfi_softc *sc) int error, commsz, framessz, sensesz; int frames, unit, max_fw_sge; - device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n"); + device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.981\n"); lockinit(&sc->mfi_io_lock, "MFI I/O lock", 0, LK_CANRECURSE); lockinit(&sc->mfi_config_lock, "MFI config", 0, LK_CANRECURSE); TAILQ_INIT(&sc->mfi_ld_tqh); + TAILQ_INIT(&sc->mfi_syspd_tqh); TAILQ_INIT(&sc->mfi_aen_pids); TAILQ_INIT(&sc->mfi_cam_ccbq); @@ -393,8 +462,13 @@ mfi_attach(struct mfi_softc *sc) return (ENOMEM); } bzero(sc->mfi_comms, commsz); +#if defined(__x86_64__) + bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, + sc->mfi_comms, commsz, mfi_addr64_cb, &sc->mfi_comms_busaddr, 0); +#else bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0); +#endif /* * Allocate DMA memory for the command frames. Keep them in the @@ -412,6 +486,8 @@ mfi_attach(struct mfi_softc *sc) } else { sc->mfi_sge_size = sizeof(struct mfi_sg32); } + if (sc->mfi_flags & MFI_FLAGS_SKINNY) + sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; @@ -434,8 +510,13 @@ mfi_attach(struct mfi_softc *sc) return (ENOMEM); } bzero(sc->mfi_frames, framessz); +#if defined(__x86_64__) + bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, + sc->mfi_frames, framessz, mfi_addr64_cb, &sc->mfi_frames_busaddr,0); +#else bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0); +#endif /* * Allocate DMA memory for the frame sense data. Keep them in the @@ -460,8 +541,13 @@ mfi_attach(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); return (ENOMEM); } +#if defined(__x86_64__) + bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, + sc->mfi_sense, sensesz, mfi_addr64_cb, &sc->mfi_sense_busaddr, 0); +#else bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0); +#endif if ((error = mfi_alloc_commands(sc)) != 0) return (error); @@ -633,6 +719,7 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode struct mfi_command *cm; struct mfi_dcmd_frame *dcmd; void *buf = NULL; + uint32_t context = 0; KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); @@ -640,6 +727,11 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode if (cm == NULL) return (EBUSY); + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + if ((bufsize > 0) && (bufp != NULL)) { if (*bufp == NULL) { buf = kmalloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); @@ -659,6 +751,7 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode dcmd->header.timeout = 0; dcmd->header.flags = 0; dcmd->header.data_len = bufsize; + dcmd->header.scsi_status = 0; dcmd->opcode = opcode; cm->cm_sg = &dcmd->sgl; cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; @@ -680,11 +773,17 @@ mfi_comms_init(struct mfi_softc *sc) struct mfi_init_frame *init; struct mfi_init_qinfo *qinfo; int error; + uint32_t context = 0; lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); if ((cm = mfi_dequeue_free(sc)) == NULL) return (EBUSY); + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + /* * Abuse the SG list area of the frame to hold the init_qinfo * object; @@ -931,6 +1030,8 @@ mfi_startup(void *arg) lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE); lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_ldprobe(sc); + if (sc->mfi_flags & MFI_FLAGS_SKINNY) + mfi_syspdprobe(sc); lockmgr(&sc->mfi_io_lock, LK_RELEASE); lockmgr(&sc->mfi_config_lock, LK_RELEASE); } @@ -1004,6 +1105,75 @@ mfi_shutdown(struct mfi_softc *sc) lockmgr(&sc->mfi_io_lock, LK_RELEASE); return (error); } +static void +mfi_syspdprobe(struct mfi_softc *sc) +{ + struct mfi_frame_header *hdr; + struct mfi_command *cm = NULL; + struct mfi_pd_list *pdlist = NULL; + struct mfi_system_pd *syspd; + int error, i; + + KKASSERT(lockstatus(&sc->mfi_config_lock, curthread) != 0); + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + /* Add SYSTEM PD's */ + error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, + (void **)&pdlist, sizeof(*pdlist)); + if (error) { + device_printf(sc->mfi_dev,"Error while forming syspd list\n"); + goto out; + } + + cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; + cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; + cm->cm_frame->dcmd.mbox[1] = 0; + if (mfi_mapcmd(sc, cm) != 0) { + device_printf(sc->mfi_dev, "Failed to get syspd device list\n"); + goto out; + } + bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); + hdr = &cm->cm_frame->header; + if (hdr->cmd_status != MFI_STAT_OK) { + device_printf(sc->mfi_dev, "MFI_DCMD_PD_LIST_QUERY failed %x\n", + hdr->cmd_status); + goto out; + } + for (i = 0; i < pdlist->count; i++) { + if (pdlist->addr[i].device_id == pdlist->addr[i].encl_device_id) + goto skip_sys_pd_add; + /* Get each PD and add it to the system */ + if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { + if (syspd->pd_id == pdlist->addr[i].device_id) + goto skip_sys_pd_add; + } + } + mfi_add_sys_pd(sc,pdlist->addr[i].device_id); +skip_sys_pd_add: + ; + } + /* Delete SYSPD's whose state has been changed */ + if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { + for (i=0;icount;i++) { + if (syspd->pd_id == pdlist->addr[i].device_id) + goto skip_sys_pd_delete; + } + get_mplock(); + device_delete_child(sc->mfi_dev,syspd->pd_dev); + rel_mplock(); +skip_sys_pd_delete: + ; + } + } +out: + if (pdlist) + kfree(pdlist, M_MFIBUF); + if (cm) + mfi_release_command(cm); +} static void mfi_ldprobe(struct mfi_softc *sc) @@ -1216,6 +1386,7 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) struct mfi_evt_list *el; union mfi_evt class_locale; int error, i, seq, size; + uint32_t context = 0; class_locale.members.reserved = 0; class_locale.members.locale = mfi_event_locale; @@ -1233,11 +1404,17 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) return (EBUSY); } + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + dcmd = &cm->cm_frame->dcmd; bzero(dcmd->mbox, MFI_MBOX_SIZE); dcmd->header.cmd = MFI_CMD_DCMD; dcmd->header.timeout = 0; dcmd->header.data_len = size; + dcmd->header.scsi_status = 0; dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; ((uint32_t *)&dcmd->mbox)[0] = seq; ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; @@ -1322,8 +1499,13 @@ mfi_add_ld(struct mfi_softc *sc, int id) kfree(ld_info, M_MFIBUF); return (0); } - - mfi_add_ld_complete(cm); + if (ld_info->ld_config.params.isSSCD != 1) { + mfi_add_ld_complete(cm); + } else { + mfi_release_command(cm); + if(ld_info) /* SSCD drives ld_info free here */ + kfree(ld_info, M_MFIBUF); + } return (0); } @@ -1363,24 +1545,193 @@ mfi_add_ld_complete(struct mfi_command *cm) lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); } +static int +mfi_add_sys_pd(struct mfi_softc *sc,int id) +{ + struct mfi_command *cm; + struct mfi_dcmd_frame *dcmd = NULL; + struct mfi_pd_info *pd_info = NULL; + int error; + + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + + error = mfi_dcmd_command(sc,&cm,MFI_DCMD_PD_GET_INFO, + (void **)&pd_info, sizeof(*pd_info)); + if (error) { + device_printf(sc->mfi_dev, + "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", error); + if (pd_info) + kfree(pd_info,M_MFIBUF); + return (error); + } + cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; + dcmd = &cm->cm_frame->dcmd; + dcmd->mbox[0] = id; + dcmd->header.scsi_status = 0; + dcmd->header.pad0 = 0; + if (mfi_mapcmd(sc, cm) != 0) { + device_printf(sc->mfi_dev, + "Failed to get physical drive info %d\n", id); + kfree(pd_info,M_MFIBUF); + return (0); + } + bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->mfi_buffer_dmat,cm->cm_dmamap); + mfi_add_sys_pd_complete(cm); + return (0); +} + +static void +mfi_add_sys_pd_complete(struct mfi_command *cm) +{ + struct mfi_frame_header *hdr; + struct mfi_pd_info *pd_info; + struct mfi_softc *sc; + device_t child; + + sc = cm->cm_sc; + hdr = &cm->cm_frame->header; + pd_info = cm->cm_private; + + if (hdr->cmd_status != MFI_STAT_OK) { + kfree(pd_info, M_MFIBUF); + mfi_release_command(cm); + return; + } + if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { + device_printf(sc->mfi_dev,"PD=%x is not SYSTEM PD\n", + pd_info->ref.v.device_id); + kfree(pd_info, M_MFIBUF); + mfi_release_command(cm); + return; + } + mfi_release_command(cm); + + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + get_mplock(); + if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { + device_printf(sc->mfi_dev, "Failed to add system pd\n"); + kfree(pd_info, M_MFIBUF); + rel_mplock(); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + return; + } + + device_set_ivars(child, pd_info); + device_set_desc(child, "MFI System PD"); + bus_generic_attach(sc->mfi_dev); + rel_mplock(); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); +} + static struct mfi_command * mfi_bio_command(struct mfi_softc *sc) { - struct mfi_io_frame *io; - struct mfi_command *cm; struct bio *bio; + struct mfi_command *cm = NULL; + struct mfi_disk *mfid; + + /* reserving two commands to avoid starvation for IOCTL */ + if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) + return (NULL); + if ((bio = mfi_dequeue_bio(sc)) == NULL) + return (NULL); + mfid = bio->bio_driver_info; + if (mfid->ld_flags & MFI_DISK_FLAGS_SYSPD) + cm = mfi_build_syspdio(sc, bio); + else + cm = mfi_build_ldio(sc, bio); + if (!cm) + mfi_enqueue_bio(sc,bio); + return cm; +} + +static struct mfi_command * +mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) +{ + struct mfi_command *cm; struct buf *bp; - struct mfi_disk *disk; - int flags, blkcount; + struct mfi_system_pd *disk; + struct mfi_pass_frame *pass; + int flags = 0,blkcount = 0; + uint32_t context = 0; if ((cm = mfi_dequeue_free(sc)) == NULL) return (NULL); - if ((bio = mfi_dequeue_bio(sc)) == NULL) { - mfi_release_command(cm); - return (NULL); + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + bp = bio->bio_buf; + pass = &cm->cm_frame->pass; + bzero(pass->cdb, 16); + pass->header.cmd = MFI_CMD_PD_SCSI_IO; + switch (bp->b_cmd & 0x03) { + case BUF_CMD_READ: + pass->cdb[0] = READ_10; + flags = MFI_CMD_DATAIN; + break; + case BUF_CMD_WRITE: + pass->cdb[0] = WRITE_10; + flags = MFI_CMD_DATAOUT; + break; + default: + panic("Invalid bio command"); } + /* Cheat with the sector length to avoid a non-constant division */ + blkcount = (bp->b_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; + disk = bio->bio_driver_info; + /* Fill the LBA and Transfer length in CDB */ + pass->cdb[2] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0xff000000) >> 24; + pass->cdb[3] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0x00ff0000) >> 16; + pass->cdb[4] = ((bio->bio_offset / MFI_SECTOR_LEN) & 0x0000ff00) >> 8; + pass->cdb[5] = (bio->bio_offset / MFI_SECTOR_LEN) & 0x000000ff; + pass->cdb[7] = (blkcount & 0xff00) >> 8; + pass->cdb[8] = (blkcount & 0x00ff); + pass->header.target_id = disk->pd_id; + pass->header.timeout = 0; + pass->header.flags = 0; + pass->header.scsi_status = 0; + pass->header.sense_len = MFI_SENSE_LEN; + pass->header.data_len = bp->b_bcount; + pass->header.cdb_len = 10; +#if defined(__x86_64__) + pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); + pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; +#else + pass->sense_addr_lo = cm->cm_sense_busaddr; + pass->sense_addr_hi = 0; +#endif + cm->cm_complete = mfi_bio_complete; + cm->cm_private = bio; + cm->cm_data = bp->b_data; + cm->cm_len = bp->b_bcount; + cm->cm_sg = &pass->sgl; + cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; + cm->cm_flags = flags; + return (cm); +} + +static struct mfi_command * +mfi_build_ldio(struct mfi_softc *sc,struct bio *bio) +{ + struct mfi_io_frame *io; + struct buf *bp; + struct mfi_disk *disk; + struct mfi_command *cm; + int flags, blkcount; + uint32_t context = 0; + + if ((cm = mfi_dequeue_free(sc)) == NULL) + return (NULL); + + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame,sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; bp = bio->bio_buf; io = &cm->cm_frame->io; switch (bp->b_cmd & 0x03) { @@ -1402,10 +1753,16 @@ mfi_bio_command(struct mfi_softc *sc) io->header.target_id = disk->ld_id; io->header.timeout = 0; io->header.flags = 0; + io->header.scsi_status = 0; io->header.sense_len = MFI_SENSE_LEN; io->header.data_len = blkcount; +#if defined(__x86_64__) + io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); + io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; +#else io->sense_addr_lo = cm->cm_sense_busaddr; io->sense_addr_hi = 0; +#endif io->lba_hi = ((bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff00000000) >> 32; io->lba_lo = (bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff; cm->cm_complete = mfi_bio_complete; @@ -1510,6 +1867,8 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) union mfi_sgl *sgl; struct mfi_softc *sc; int i, dir; + int sgl_mapped = 0; + int sge_size = 0; cm = (struct mfi_command *)arg; sc = cm->cm_sc; @@ -1523,17 +1882,40 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) return; } - if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { - for (i = 0; i < nsegs; i++) { - sgl->sg32[i].addr = segs[i].ds_addr; - sgl->sg32[i].len = segs[i].ds_len; - } - } else { + /* Use IEEE sgl only for IO's on a SKINNY controller + * For other commands on a SKINNY controller use either + * sg32 or sg64 based on the sizeof(bus_addr_t). + * Also calculate the total frame size based on the type + * of SGL used. + */ + if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || + (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || + (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && + (sc->mfi_flags & MFI_FLAGS_SKINNY)) { for (i = 0; i < nsegs; i++) { - sgl->sg64[i].addr = segs[i].ds_addr; - sgl->sg64[i].len = segs[i].ds_len; + sgl->sg_skinny[i].addr = segs[i].ds_addr; + sgl->sg_skinny[i].len = segs[i].ds_len; + sgl->sg_skinny[i].flag = 0; + } + hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; + sgl_mapped = 1; + sge_size = sizeof(struct mfi_sg_skinny); + } + if (!sgl_mapped) { + if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { + for (i = 0; i < nsegs; i++) { + sgl->sg32[i].addr = segs[i].ds_addr; + sgl->sg32[i].len = segs[i].ds_len; + } + sge_size = sizeof(struct mfi_sg32); + } else { + for (i = 0; i < nsegs; i++) { + sgl->sg64[i].addr = segs[i].ds_addr; + sgl->sg64[i].len = segs[i].ds_len; + } + hdr->flags |= MFI_FRAME_SGL64; + sge_size = sizeof(struct mfi_sg64); } - hdr->flags |= MFI_FRAME_SGL64; } hdr->sg_count = nsegs; @@ -1555,12 +1937,10 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) * least 1 frame, so don't compensate for the modulo of the * following division. */ - cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); + cm->cm_total_frame_size += (sge_size * nsegs); cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; mfi_send_frame(sc, cm); - - return; } static int @@ -1647,6 +2027,7 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) struct mfi_command *cm; struct mfi_abort_frame *abort; int i = 0; + uint32_t context = 0; KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); @@ -1654,12 +2035,23 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) return (EBUSY); } + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + abort = &cm->cm_frame->abort; abort->header.cmd = MFI_CMD_ABORT; abort->header.flags = 0; + abort->header.scsi_status = 0; abort->abort_context = cm_abort->cm_frame->header.context; +#if defined(__x86_64__) + abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr & 0xFFFFFFFF; + abort->abort_mfi_addr_hi = (cm_abort->cm_frame_busaddr & 0xFFFFFFFF00000000 ) >> 32 ; +#else abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr; abort->abort_mfi_addr_hi = 0; +#endif cm->cm_data = NULL; cm->cm_flags = MFI_CMD_POLLED; @@ -1681,19 +2073,31 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len) struct mfi_command *cm; struct mfi_io_frame *io; int error; + uint32_t context = 0; if ((cm = mfi_dequeue_free(sc)) == NULL) return (EBUSY); + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + io = &cm->cm_frame->io; io->header.cmd = MFI_CMD_LD_WRITE; io->header.target_id = id; io->header.timeout = 0; io->header.flags = 0; + io->header.scsi_status = 0; io->header.sense_len = MFI_SENSE_LEN; io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; +#if defined(__x86_64__) + io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); + io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32; +#else io->sense_addr_lo = cm->cm_sense_busaddr; io->sense_addr_hi = 0; +#endif io->lba_hi = (lba & 0xffffffff00000000) >> 32; io->lba_lo = lba & 0xffffffff; cm->cm_data = virt; @@ -1711,6 +2115,58 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len) return (error); } +int +mfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, + int len) +{ + struct mfi_command *cm; + struct mfi_pass_frame *pass; + int error; + int blkcount = 0; + + if ((cm = mfi_dequeue_free(sc)) == NULL) + return (EBUSY); + + pass = &cm->cm_frame->pass; + bzero(pass->cdb, 16); + pass->header.cmd = MFI_CMD_PD_SCSI_IO; + pass->cdb[0] = WRITE_10; + pass->cdb[2] = (lba & 0xff000000) >> 24; + pass->cdb[3] = (lba & 0x00ff0000) >> 16; + pass->cdb[4] = (lba & 0x0000ff00) >> 8; + pass->cdb[5] = (lba & 0x000000ff); + blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; + pass->cdb[7] = (blkcount & 0xff00) >> 8; + pass->cdb[8] = (blkcount & 0x00ff); + pass->header.target_id = id; + pass->header.timeout = 0; + pass->header.flags = 0; + pass->header.scsi_status = 0; + pass->header.sense_len = MFI_SENSE_LEN; + pass->header.data_len = len; + pass->header.cdb_len = 10; +#if defined(__x86_64__) + pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); + pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32; +#else + pass->sense_addr_lo = cm->cm_sense_busaddr; + pass->sense_addr_hi = 0; +#endif + cm->cm_data = virt; + cm->cm_len = len; + cm->cm_sg = &pass->sgl; + cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; + cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; + + error = mfi_mapcmd(sc, cm); + bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); + mfi_release_command(cm); + + return (error); +} + static int mfi_open(struct dev_open_args *ap) { @@ -1784,6 +2240,9 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) { struct mfi_disk *ld, *ld2; int error; + struct mfi_system_pd *syspd = NULL; + uint16_t syspd_id; + uint16_t *mbox; KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); error = 0; @@ -1812,6 +2271,22 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) } } break; + case MFI_DCMD_PD_STATE_SET: + mbox = (uint16_t *)cm->cm_frame->dcmd.mbox; + syspd_id = mbox[0]; + if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { + if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { + if (syspd->pd_id == syspd_id) + break; + } + } + } else { + break; + } + if(syspd) + error = mfi_syspd_disable(syspd); + break; default: break; } @@ -1823,6 +2298,9 @@ static void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) { struct mfi_disk *ld, *ldn; + struct mfi_system_pd *syspd = NULL; + uint16_t syspd_id; + uint16_t *mbox; switch (cm->cm_frame->dcmd.opcode) { case MFI_DCMD_LD_DELETE: @@ -1860,6 +2338,23 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) case MFI_DCMD_CFG_FOREIGN_IMPORT: mfi_ldprobe(sc); break; + case MFI_DCMD_PD_STATE_SET: + mbox = (uint16_t *)cm->cm_frame->dcmd.mbox; + syspd_id = mbox[0]; + if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { + if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { + TAILQ_FOREACH(syspd,&sc->mfi_syspd_tqh,pd_link) { + if (syspd->pd_id == syspd_id) + break; + } + } + } else { + break; + } + /* If the transition fails then enable the syspd again */ + if(syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) + mfi_syspd_enable(syspd); + break; } } @@ -1937,6 +2432,54 @@ out: #define PTRIN(p) (p) #endif +static int +mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) +{ + struct mfi_config_data *conf_data = cm->cm_data; + struct mfi_command *ld_cm = NULL; + struct mfi_ld_info *ld_info = NULL; + int error = 0; + + if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && + (conf_data->ld[0].params.isSSCD == 1)) { + error = 1; + } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { + error = mfi_dcmd_command(sc, &ld_cm, MFI_DCMD_LD_GET_INFO, + (void **)&ld_info, sizeof(*ld_info)); + if (error) { + device_printf(sc->mfi_dev,"Failed to allocate " + "MFI_DCMD_LD_GET_INFO %d", error); + if (ld_info) + kfree(ld_info, M_MFIBUF); + return 0; + } + ld_cm->cm_flags = MFI_CMD_DATAIN; + ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; + ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; + if (mfi_wait_command(sc, ld_cm) != 0) { + device_printf(sc->mfi_dev, "failed to get log drv\n"); + mfi_release_command(ld_cm); + kfree(ld_info, M_MFIBUF); + return 0; + } + + if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { + kfree(ld_info, M_MFIBUF); + mfi_release_command(ld_cm); + return 0; + } else { + ld_info = (struct mfi_ld_info *)ld_cm->cm_private; + } + + if (ld_info->ld_config.params.isSSCD == 1) + error = 1; + + mfi_release_command(ld_cm); + kfree(ld_info, M_MFIBUF); + } + return error; +} + static int mfi_ioctl(struct dev_ioctl_args *ap) { @@ -1954,7 +2497,7 @@ mfi_ioctl(struct dev_ioctl_args *ap) struct mfi_command *cm = NULL; uint32_t context; union mfi_sense_ptr sense_ptr; - uint8_t *data = NULL, *temp; + uint8_t *data = NULL, *temp, skip_pre_post = 0; int i; struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; #ifdef __x86_64__ @@ -2038,6 +2581,8 @@ mfi_ioctl(struct dev_ioctl_args *ap) 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off; + cm->cm_frame->header.scsi_status = 0; + cm->cm_frame->header.pad0 = 0; if (ioc->mfi_sge_count) { cm->cm_sg = (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; @@ -2103,15 +2648,25 @@ mfi_ioctl(struct dev_ioctl_args *ap) locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { +#if defined(__x86_64__) + cm->cm_frame->pass.sense_addr_lo = + (cm->cm_sense_busaddr & 0xFFFFFFFF); + cm->cm_frame->pass.sense_addr_hi = + (cm->cm_sense_busaddr& 0xFFFFFFFF00000000) >> 32; +#else cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr; cm->cm_frame->pass.sense_addr_hi = 0; +#endif } lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); - error = mfi_check_command_pre(sc, cm); - if (error) { - lockmgr(&sc->mfi_io_lock, LK_RELEASE); - goto out; + skip_pre_post = mfi_check_for_sscd(sc, cm); + if (!skip_pre_post) { + error = mfi_check_command_pre(sc, cm); + if (error) { + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + goto out; + } } if ((error = mfi_wait_command(sc, cm)) != 0) { @@ -2121,7 +2676,8 @@ mfi_ioctl(struct dev_ioctl_args *ap) goto out; } - mfi_check_command_post(sc, cm); + if (!skip_pre_post) + mfi_check_command_post(sc, cm); lockmgr(&sc->mfi_io_lock, LK_RELEASE); temp = data; @@ -2309,6 +2865,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag) 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; + cm->cm_frame->header.scsi_status = 0; + cm->cm_frame->header.pad0 = 0; if (l_ioc.lioc_sge_count) cm->cm_sg = (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; @@ -2352,8 +2910,15 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag) locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { +#if defined(__x86_64__) + cm->cm_frame->pass.sense_addr_lo = + (cm->cm_sense_busaddr & 0xFFFFFFFF); + cm->cm_frame->pass.sense_addr_hi = + (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; +#else cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr; cm->cm_frame->pass.sense_addr_hi = 0; +#endif } lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); diff --git a/sys/dev/raid/mfi/mfi_cam.c b/sys/dev/raid/mfi/mfi_cam.c index abf7e9e175..4d3933a17f 100644 --- a/sys/dev/raid/mfi/mfi_cam.c +++ b/sys/dev/raid/mfi/mfi_cam.c @@ -22,6 +22,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.6 2011/06/28 08:36:48 kevlo Exp $ */ @@ -260,12 +290,18 @@ mfip_start(void *data) struct mfip_softc *sc; struct mfi_pass_frame *pt; struct mfi_command *cm; + uint32_t context = 0; sc = ccbh->ccb_mfip_ptr; if ((cm = mfi_dequeue_free(sc->mfi_sc)) == NULL) return (NULL); + /* Zero out the MFI frame */ + context = cm->cm_frame->header.context; + bzero(cm->cm_frame, sizeof(union mfi_frame)); + cm->cm_frame->header.context = context; + pt = &cm->cm_frame->pass; pt->header.cmd = MFI_CMD_PD_SCSI_IO; pt->header.cmd_status = 0; @@ -314,10 +350,8 @@ mfip_done(struct mfi_command *cm) union ccb *ccb = cm->cm_private; struct ccb_hdr *ccbh = &ccb->ccb_h; struct ccb_scsiio *csio = &ccb->csio; - struct mfip_softc *sc; struct mfi_pass_frame *pt; - sc = ccbh->ccb_mfip_ptr; pt = &cm->cm_frame->pass; switch (pt->header.cmd_status) { diff --git a/sys/dev/raid/mfi/mfi_disk.c b/sys/dev/raid/mfi/mfi_disk.c index d0ff04ed5f..57732ea1a3 100644 --- a/sys/dev/raid/mfi/mfi_disk.c +++ b/sys/dev/raid/mfi/mfi_disk.c @@ -22,6 +22,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $ */ @@ -176,9 +206,9 @@ mfi_disk_detach(device_t dev) sc = device_get_softc(dev); lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); - if (((sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && + if ((sc->ld_flags & MFI_DISK_FLAGS_OPEN) && (sc->ld_controller->mfi_keep_deleted_volumes || - sc->ld_controller->mfi_detaching)) { + sc->ld_controller->mfi_detaching)) { lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); return (EBUSY); } @@ -231,7 +261,7 @@ mfi_disk_disable(struct mfi_disk *sc) if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { if (sc->ld_controller->mfi_delete_busy_volumes) return (0); - device_printf(sc->ld_dev, "Unable to delete busy device\n"); + device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); return (EBUSY); } sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; diff --git a/sys/dev/raid/mfi/mfi_pci.c b/sys/dev/raid/mfi/mfi_pci.c index 1a095bc7f6..cb3163d6b3 100644 --- a/sys/dev/raid/mfi/mfi_pci.c +++ b/sys/dev/raid/mfi/mfi_pci.c @@ -48,6 +48,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.16 2010/03/02 17:34:11 kib Exp $ */ @@ -114,12 +144,15 @@ struct mfi_ident { } mfi_identifiers[] = { {0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078, "Dell PERC 6"}, {0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"}, + {0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"}, + {0x1000, 0x0073, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"}, {0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"}, {0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2, "Dell PERC H800 Adapter"}, {0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2, "Dell PERC H700 Adapter"}, {0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2, "Dell PERC H700 Integrated"}, {0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2, "Dell PERC H700 Modular"}, {0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2, "Dell PERC H700"}, + {0x1000, 0x0079, 0x1028, 0x1f1a, MFI_FLAGS_GEN2, "Dell PERC H800 Proto Adapter"}, {0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2, "Dell PERC H800"}, {0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2, "Dell PERC Gen2"}, {0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"}, @@ -193,8 +226,9 @@ mfi_pci_attach(device_t dev) (sc->mfi_flags & MFI_FLAGS_1078)) { /* 1068/1078: Memory mapped BAR is at offset 0x10 */ sc->mfi_regs_rid = PCIR_BAR(0); - } else if (sc->mfi_flags & MFI_FLAGS_GEN2) { - /* GEN2: Memory mapped BAR is at offset 0x14 */ + } else if ((sc->mfi_flags & MFI_FLAGS_GEN2) || + (sc->mfi_flags & MFI_FLAGS_SKINNY)) { + /* GEN2/Skinny: Memory mapped BAR is at offset 0x14 */ sc->mfi_regs_rid = PCIR_BAR(1); } if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev, @@ -237,6 +271,7 @@ mfi_pci_detach(device_t dev) { struct mfi_softc *sc; struct mfi_disk *ld; + struct mfi_system_pd *syspd = NULL; int error; sc = device_get_softc(dev); @@ -258,6 +293,13 @@ mfi_pci_detach(device_t dev) return (error); } } + while ((syspd = TAILQ_FIRST(&sc->mfi_syspd_tqh)) != NULL) { + if ((error = device_delete_child(dev,syspd->pd_dev)) != 0) { + sc->mfi_detaching = 0; + lockmgr(&sc->mfi_config_lock, LK_RELEASE); + return (error); + } + } lockmgr(&sc->mfi_config_lock, LK_RELEASE); EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh); diff --git a/sys/dev/raid/mfi/mfi_syspd.c b/sys/dev/raid/mfi/mfi_syspd.c new file mode 100644 index 0000000000..0a3fca2560 --- /dev/null +++ b/sys/dev/raid/mfi/mfi_syspd.c @@ -0,0 +1,323 @@ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * $FreeBSD: src/sys/dev/mfi/mfi_pddisk.c,v 1.2.2.6 2007/08/24 17:29:18 jhb Exp $ + */ + +#include "opt_mfi.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +static int mfi_syspd_probe(device_t dev); +static int mfi_syspd_attach(device_t dev); +static int mfi_syspd_detach(device_t dev); + +static d_open_t mfi_syspd_open; +static d_close_t mfi_syspd_close; +static d_strategy_t mfi_syspd_strategy; +static d_dump_t mfi_syspd_dump; + +static struct dev_ops mfi_syspd_ops = { + { "mfisyspd", 0, D_DISK }, + .d_open = mfi_syspd_open, + .d_close = mfi_syspd_close, + .d_strategy = mfi_syspd_strategy, + .d_dump = mfi_syspd_dump, +}; + +static devclass_t mfi_syspd_devclass; + +static device_method_t mfi_syspd_methods[] = { + DEVMETHOD(device_probe, mfi_syspd_probe), + DEVMETHOD(device_attach, mfi_syspd_attach), + DEVMETHOD(device_detach, mfi_syspd_detach), + { 0, 0 } +}; + +static driver_t mfi_syspd_driver = { + "mfisyspd", + mfi_syspd_methods, + sizeof(struct mfi_system_pd) +}; + +DRIVER_MODULE(mfisyspd, mfi, mfi_syspd_driver, mfi_syspd_devclass, 0, 0); + +static int +mfi_syspd_probe(device_t dev) +{ + + return (0); +} + +static int +mfi_syspd_attach(device_t dev) +{ + struct mfi_system_pd *sc; + struct mfi_pd_info *pd_info; + struct disk_info info; + uint64_t sectors; + uint32_t secsize; + + sc = device_get_softc(dev); + pd_info = device_get_ivars(dev); + + sc->pd_dev = dev; + sc->pd_id = pd_info->ref.v.device_id; + sc->pd_unit = device_get_unit(dev); + sc->pd_info = pd_info; + sc->pd_controller = device_get_softc(device_get_parent(dev)); + sc->pd_flags = MFI_DISK_FLAGS_SYSPD; + + sectors = pd_info->raw_size; + secsize = MFI_SECTOR_LEN; + lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); + TAILQ_INSERT_TAIL(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link); + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + device_printf(dev, "%juMB (%ju sectors) SYSPD volume\n", + sectors / (1024 * 1024 / secsize), sectors); + + devstat_add_entry(&sc->pd_devstat, "mfisyspd", device_get_unit(dev), + MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, + DEVSTAT_PRIORITY_ARRAY); + + sc->pd_disk.d_cdev = disk_create(sc->pd_unit, &sc->pd_disk, + &mfi_syspd_ops); + sc->pd_disk.d_cdev->si_drv1 = sc; + sc->pd_disk.d_cdev->si_iosize_max = sc->pd_controller->mfi_max_io * + secsize; + + bzero(&info, sizeof(info)); + info.d_media_blksize = secsize; /* mandatory */ + info.d_media_blocks = sectors; + + if (info.d_media_blocks >= (1 * 1024 * 1024)) { + info.d_nheads = 255; + info.d_secpertrack = 63; + } else { + info.d_nheads = 64; + info.d_secpertrack = 32; + } + + disk_setdiskinfo(&sc->pd_disk, &info); + + device_printf(dev, " SYSPD volume attached\n"); + return (0); +} + +static int +mfi_syspd_detach(device_t dev) +{ + struct mfi_system_pd *sc; + + sc = device_get_softc(dev); + device_printf(dev, "Detaching syspd\n"); + lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); + if ((sc->pd_flags & MFI_DISK_FLAGS_OPEN) && + (sc->pd_controller->mfi_keep_deleted_volumes || + sc->pd_controller->mfi_detaching)) { + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + device_printf(dev,"Cant detach syspd\n"); + return (EBUSY); + } + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + + disk_destroy(&sc->pd_disk); + devstat_remove_entry(&sc->pd_devstat); + lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); + TAILQ_REMOVE(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link); + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + kfree(sc->pd_info, M_MFIBUF); + return (0); +} + +static int +mfi_syspd_open(struct dev_open_args *ap) +{ + struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; + int error; + + lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); + if (sc->pd_flags & MFI_DISK_FLAGS_DISABLED) + error = ENXIO; + else { + sc->pd_flags |= MFI_DISK_FLAGS_OPEN; + error = 0; + } + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + return (error); +} + +static int +mfi_syspd_close(struct dev_close_args *ap) +{ + struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; + + lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); + sc->pd_flags &= ~MFI_DISK_FLAGS_OPEN; + lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); + + return (0); +} + +int +mfi_syspd_disable(struct mfi_system_pd *sc) +{ + + device_printf(sc->pd_dev,"syspd disable \n"); + KKASSERT(lockstatus(&sc->pd_controller->mfi_io_lock, curthread) != 0); + if (sc->pd_flags & MFI_DISK_FLAGS_OPEN) { + if (sc->pd_controller->mfi_delete_busy_volumes) + return (0); + device_printf(sc->pd_dev, "Unable to delete busy syspd device\n"); + return (EBUSY); + } + sc->pd_flags |= MFI_DISK_FLAGS_DISABLED; + return (0); +} + +void +mfi_syspd_enable(struct mfi_system_pd *sc) +{ + + device_printf(sc->pd_dev,"syspd enable \n"); + KKASSERT(lockstatus(&sc->pd_controller->mfi_io_lock, curthread) != 0); + sc->pd_flags &= ~MFI_DISK_FLAGS_DISABLED; +} + +static int +mfi_syspd_strategy(struct dev_strategy_args *ap) +{ + struct bio *bio = ap->a_bio; + struct buf *bp = bio->bio_buf; + struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; + struct mfi_softc *controller; + + if (sc == NULL) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + biodone(bio); + return (0); + } + + /* + * XXX swildner + * + * If it's a null transfer, do nothing. FreeBSD's original driver + * doesn't have this, but that caused hard error messages (even + * though everything else continued to work fine). Interestingly, + * only when HAMMER was used. + * + * Several others of our RAID drivers have this check, such as + * aac(4) and ida(4), so we insert it here, too. + * + * The cause of null transfers is yet unknown. + */ + if (bp->b_bcount == 0) { + bp->b_resid = bp->b_bcount; + biodone(bio); + return (0); + } + + controller = sc->pd_controller; + bio->bio_driver_info = sc; + lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); + mfi_enqueue_bio(controller, bio); + devstat_start_transaction(&sc->pd_devstat); + mfi_startio(controller); + lockmgr(&controller->mfi_io_lock, LK_RELEASE); + return (0); +} + +#if 0 +void +mfi_disk_complete(struct bio *bio) +{ + struct mfi_system_pd *sc = bio->bio_driver_info; + struct buf *bp = bio->bio_buf; + + devstat_end_transaction_buf(&sc->pd_devstat, bp); + if (bio->b_flags & B_ERROR) { + if (bp->b_error == 0) + bp->b_error = EIO; + diskerr(bio, sc->pd_disk.d_cdev, "hard error", -1, 1); + kprintf("\n"); + } else { + bp->b_resid = 0; + } + biodone(bio); +} +#endif + +static int +mfi_syspd_dump(struct dev_dump_args *ap) +{ + cdev_t dev = ap->a_head.a_dev; + off_t offset = ap->a_offset; + void *virt = ap->a_virtual; + size_t len = ap->a_length; + struct mfi_system_pd *sc; + struct mfi_softc *parent_sc; + int error; + + sc = dev->si_drv1; + parent_sc = sc->pd_controller; + + if (len > 0) { + if ((error = mfi_dump_syspd_blocks(parent_sc, sc->pd_id, offset / + MFI_SECTOR_LEN, virt, len)) != 0) + return (error); + } else { + /* mfi_sync_cache(parent_sc, sc->ld_id); */ + } + return (0); +} diff --git a/sys/dev/raid/mfi/mfireg.h b/sys/dev/raid/mfi/mfireg.h index 92b6f190e7..f2396d40d1 100644 --- a/sys/dev/raid/mfi/mfireg.h +++ b/sys/dev/raid/mfi/mfireg.h @@ -48,6 +48,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.16 2011/07/14 20:20:33 jhb Exp $ */ @@ -98,6 +128,20 @@ #define MFI_GEN2_EIM 0x00000005 /* GEN2 enable interrupt mask */ #define MFI_GEN2_RM 0x00000001 /* reply GEN2 message interrupt */ +/* + * gen2 specific changes + */ +#define MFI_GEN2_EIM 0x00000005 /* gen2 enable interrupt mask */ +#define MFI_GEN2_RM 0x00000001 /* reply gen2 message interrupt */ + +/* + * skinny specific changes + */ +#define MFI_SKINNY_IDB 0x00 /* Inbound doorbell is at 0x00 for skinny */ +#define MFI_IQPL 0x000000c0 +#define MFI_IQPH 0x000000c4 +#define MFI_SKINNY_RM 0x00000001 /* reply skinny message interrupt */ + /* Bits for MFI_OSTS */ #define MFI_OSTS_INTR_VALID 0x00000002 @@ -118,6 +162,8 @@ #define MFI_FWSTATE_FAULT 0xf0000000 #define MFI_FWSTATE_MAXSGL_MASK 0x00ff0000 #define MFI_FWSTATE_MAXCMD_MASK 0x0000ffff +#define MFI_FWSTATE_HOSTMEMREQD_MASK 0x08000000 +#define MFI_FWSTATE_BOOT_MESSAGE_PENDING 0x90000000 /* * Control bits to drive the card to ready state. These go into the IDB @@ -144,6 +190,7 @@ typedef enum { /* Direct commands */ typedef enum { + MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC = 0x0100e100, MFI_DCMD_CTRL_GETINFO = 0x01010000, MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201, MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202, @@ -163,6 +210,7 @@ typedef enum { MFI_DCMD_FLASH_FW_FLASH = 0x010f0300, MFI_DCMD_FLASH_FW_CLOSE = 0x010f0400, MFI_DCMD_PD_GET_LIST = 0x02010000, + MFI_DCMD_PD_LIST_QUERY = 0x02010100, MFI_DCMD_PD_GET_INFO = 0x02020000, MFI_DCMD_PD_STATE_SET = 0x02030100, MFI_DCMD_PD_REBUILD_START = 0x02040100, @@ -212,6 +260,7 @@ typedef enum { #define MFI_FRAME_DIR_WRITE 0x0008 #define MFI_FRAME_DIR_READ 0x0010 #define MFI_FRAME_DIR_BOTH 0x0018 +#define MFI_FRAME_IEEE_SGL 0x0020 /* MFI Status codes */ typedef enum { @@ -351,6 +400,15 @@ typedef enum { MR_PD_CACHE_DISABLE = 2 } mfi_pd_cache; +typedef enum { + MR_PD_QUERY_TYPE_ALL = 0, + MR_PD_QUERY_TYPE_STATE = 1, + MR_PD_QUERY_TYPE_POWER_STATE = 2, + MR_PD_QUERY_TYPE_MEDIA_TYPE = 3, + MR_PD_QUERY_TYPE_SPEED = 4, + MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ +} mfi_pd_query_type; + /* * Other propertities and definitions */ @@ -383,9 +441,16 @@ struct mfi_sg64 { uint32_t len; } __packed; +struct mfi_sg_skinny { + uint64_t addr; + uint32_t len; + uint32_t flag; +} __packed; + union mfi_sgl { struct mfi_sg32 sg32[1]; struct mfi_sg64 sg64[1]; + struct mfi_sg_skinny sg_skinny[1]; } __packed; /* Message frames. All messages have a common header */ @@ -399,6 +464,10 @@ struct mfi_frame_header { uint8_t cdb_len; uint8_t sg_count; uint32_t context; + /* + * pad0 is MSI Specific. Not used by Driver. Zero the value before + * sending the command to f/w + */ uint32_t pad0; uint16_t flags; #define MFI_FRAME_DATAOUT 0x08 @@ -446,10 +515,10 @@ struct mfi_dcmd_frame { struct mfi_abort_frame { struct mfi_frame_header header; uint32_t abort_context; - uint32_t pad; + uint32_t reserved0; uint32_t abort_mfi_addr_lo; uint32_t abort_mfi_addr_hi; - uint32_t reserved[6]; + uint32_t reserved1[6]; } __packed; struct mfi_smp_frame { @@ -963,10 +1032,11 @@ struct mfi_pd_address { uint64_t sas_addr[2]; } __packed; +#define MAX_SYS_PDS 240 struct mfi_pd_list { uint32_t size; uint32_t count; - struct mfi_pd_address addr[0]; + struct mfi_pd_address addr[MAX_SYS_PDS]; } __packed; enum mfi_pd_state { @@ -1039,7 +1109,9 @@ struct mfi_ld_params { #define MFI_LD_PARAMS_INIT_QUICK 1 #define MFI_LD_PARAMS_INIT_FULL 2 uint8_t is_consistent; - uint8_t reserved[23]; + uint8_t reserved1[6]; + uint8_t isSSCD; + uint8_t reserved2[16]; } __packed; struct mfi_ld_progress { @@ -1117,9 +1189,9 @@ struct mfi_config_data { uint16_t spares_count; uint16_t spares_size; uint8_t reserved[16]; - struct mfi_array array[0]; - struct mfi_ld_config ld[0]; - struct mfi_spare spare[0]; + struct mfi_array array[1]; + struct mfi_ld_config ld[1]; + struct mfi_spare spare[1]; } __packed; struct mfi_bbu_capacity_info { diff --git a/sys/dev/raid/mfi/mfivar.h b/sys/dev/raid/mfi/mfivar.h index 99eca53fc4..4ec8907e0e 100644 --- a/sys/dev/raid/mfi/mfivar.h +++ b/sys/dev/raid/mfi/mfivar.h @@ -48,6 +48,36 @@ * 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. + */ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.13 2009/07/10 08:18:08 scottl Exp $ */ @@ -82,9 +112,17 @@ struct mfi_command { time_t cm_timestamp; struct mfi_softc *cm_sc; union mfi_frame *cm_frame; +#if defined(__x86_64__) + uint64_t cm_frame_busaddr; +#else uint32_t cm_frame_busaddr; +#endif struct mfi_sense *cm_sense; +#if defined(__x86_64__) + uint64_t cm_sense_busaddr; +#else uint32_t cm_sense_busaddr; +#endif bus_dmamap_t cm_dmamap; union mfi_sgl *cm_sg; void *cm_data; @@ -108,6 +146,12 @@ struct mfi_command { int cm_error; }; +/* + * XXX swildner + * + * At the moment we rely on mfi_disk and mfi_system_pd having the same size. + * A future cleanup should merge them. + */ struct mfi_disk { TAILQ_ENTRY(mfi_disk) ld_link; device_t ld_dev; @@ -120,6 +164,19 @@ struct mfi_disk { int ld_flags; #define MFI_DISK_FLAGS_OPEN 0x01 #define MFI_DISK_FLAGS_DISABLED 0x02 +#define MFI_DISK_FLAGS_SYSPD 0x04 +}; + +struct mfi_system_pd { + TAILQ_ENTRY(mfi_system_pd) pd_link; + device_t pd_dev; + int pd_id; + int pd_unit; + struct mfi_softc *pd_controller; + struct mfi_pd_info *pd_info; + struct disk pd_disk; + struct devstat pd_devstat; + int pd_flags; }; struct mfi_aen { @@ -137,6 +194,7 @@ struct mfi_softc { #define MFI_FLAGS_1064R (1<<4) #define MFI_FLAGS_1078 (1<<5) #define MFI_FLAGS_GEN2 (1<<6) +#define MFI_FLAGS_SKINNY (1<<7) struct mfi_hwcomms *mfi_comms; TAILQ_HEAD(,mfi_command) mfi_free; @@ -164,6 +222,7 @@ struct mfi_softc { TAILQ_HEAD(,mfi_aen) mfi_aen_pids; struct mfi_command *mfi_aen_cm; + struct mfi_command *mfi_skinny_cm; uint32_t mfi_aen_triggered; uint32_t mfi_poll_waiting; struct kqinfo mfi_kq; @@ -217,6 +276,7 @@ struct mfi_softc { uint32_t mfi_max_io; TAILQ_HEAD(,mfi_disk) mfi_ld_tqh; + TAILQ_HEAD(,mfi_system_pd) mfi_syspd_tqh; eventhandler_tag mfi_eh; struct cdev *mfi_cdev; @@ -244,6 +304,9 @@ extern void mfi_disk_complete(struct bio *); extern int mfi_disk_disable(struct mfi_disk *); extern void mfi_disk_enable(struct mfi_disk *); extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int); +extern int mfi_syspd_disable(struct mfi_system_pd *); +extern void mfi_syspd_enable(struct mfi_system_pd *); +extern int mfi_dump_syspd_blocks(struct mfi_softc *, int id, uint64_t, void *, int); #define MFIQ_ADD(sc, qname) \ do { \ @@ -386,6 +449,7 @@ MALLOC_DECLARE(M_MFIBUF); #define MFI_CMD_TIMEOUT 30 #define MFI_MAXPHYS (128 * 1024) +#define SKINNY_MEMORY 0x02000000 #ifdef MFI_DEBUG extern void mfi_print_cmd(struct mfi_command *cm); -- 2.41.0