1/* 2 * Copyright (c) 2014, LSI Corp. 3 * All rights reserved. 4 * Author: Marian Choy 5 * Support: freebsdraid@lsi.com 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 28 unchanged lines hidden (view full) --- 37 * 38 * Send feedback to: <megaraidfbsd@lsi.com> 39 * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 40 * ATTN: MegaRaid FreeBSD 41 * 42 */ 43 44#include <sys/cdefs.h> |
45__FBSDID("$FreeBSD: head/sys/dev/mrsas/mrsas_ioctl.c 272737 2014-10-08 09:19:35Z kadesai $"); |
46 47#include <dev/mrsas/mrsas.h> 48#include <dev/mrsas/mrsas_ioctl.h> 49 50/* 51 * Function prototypes 52 */ 53int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc); |
54int mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd); |
55void mrsas_free_ioc_cmd(struct mrsas_softc *sc); 56void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); |
57void * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); 58static int mrsas_create_frame_pool(struct mrsas_softc *sc); 59static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 60 int nsegs, int error); 61 62extern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc); 63extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd); 64extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, 65 struct mrsas_mfi_cmd *cmd); 66 |
67/** |
68 * mrsas_passthru: Handle pass-through commands 69 * input: Adapter instance soft state 70 * argument pointer 71 * 72 * This function is called from mrsas_ioctl() to handle pass-through and 73 * ioctl commands to Firmware. 74 */ |
75int mrsas_passthru( struct mrsas_softc *sc, void *arg, u_long ioctlCmd ) |
76{ 77 struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg; |
78#ifdef COMPAT_FREEBSD32 79 struct mrsas_iocpacket32 *user_ioc32 = (struct mrsas_iocpacket32 *)arg; 80#endif |
81 union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw); 82 struct mrsas_mfi_cmd *cmd = NULL; 83 bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE]; 84 bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE]; 85 void *ioctl_data_mem[MAX_IOCTL_SGE]; // ioctl data virtual addr 86 bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr 87 bus_dma_tag_t ioctl_sense_tag = 0; 88 bus_dmamap_t ioctl_sense_dmamap = 0; 89 void *ioctl_sense_mem = 0; 90 bus_addr_t ioctl_sense_phys_addr = 0; |
91 int i, ioctl_data_size=0, ioctl_sense_size, ret=0; |
92 struct mrsas_sge32 *kern_sge32; 93 unsigned long *sense_ptr; |
94 uint8_t *iov_base_ptrin=NULL; 95 size_t iov_len=0; |
96 |
97 /* 98 * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this 99 * case do nothing and return 0 to it as status. 100 */ 101 if (in_cmd->dcmd.opcode == 0) { 102 device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__); 103 user_ioc->frame.hdr.cmd_status = MFI_STAT_OK; 104 return (0); 105 } 106 |
107 /* Validate SGL length */ 108 if (user_ioc->sge_count > MAX_IOCTL_SGE) { 109 device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n", 110 __func__, user_ioc->sge_count); 111 return(ENOENT); 112 } 113 114 /* Get a command */ --- 25 unchanged lines hidden (view full) --- 140 */ 141 kern_sge32 = (struct mrsas_sge32 *) 142 ((unsigned long)cmd->frame + user_ioc->sgl_off); 143 144 /* 145 * For each user buffer, create a mirror buffer and copy in 146 */ 147 for (i=0; i < user_ioc->sge_count; i++) { |
148 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 149 if (!user_ioc->sgl[i].iov_len) 150 continue; 151 ioctl_data_size = user_ioc->sgl[i].iov_len; 152#ifdef COMPAT_FREEBSD32 153 } else { 154 if (!user_ioc32->sgl[i].iov_len) 155 continue; 156 ioctl_data_size = user_ioc32->sgl[i].iov_len; 157#endif 158 } |
159 if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent 160 1, 0, // algnmnt, boundary 161 BUS_SPACE_MAXADDR_32BIT,// lowaddr 162 BUS_SPACE_MAXADDR, // highaddr 163 NULL, NULL, // filter, filterarg 164 ioctl_data_size, // maxsize 165 1, // msegments 166 ioctl_data_size, // maxsegsize 167 BUS_DMA_ALLOCNOW, // flags 168 NULL, NULL, // lockfunc, lockarg 169 &ioctl_data_tag[i])) { |
170 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); 171 return (ENOMEM); |
172 } 173 if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], 174 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { 175 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); 176 return (ENOMEM); 177 } 178 if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], 179 ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, 180 &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { 181 device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); 182 return (ENOMEM); 183 } 184 185 /* Save the physical address and length */ 186 kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; |
187 |
188 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 189 kern_sge32[i].length = user_ioc->sgl[i].iov_len; 190 191 iov_base_ptrin = user_ioc->sgl[i].iov_base; 192 iov_len = user_ioc->sgl[i].iov_len; 193#ifdef COMPAT_FREEBSD32 194 } else { 195 kern_sge32[i].length = user_ioc32->sgl[i].iov_len; 196 197 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 198 iov_len = user_ioc32->sgl[i].iov_len; 199#endif 200 } 201 |
202 /* Copy in data from user space */ |
203 ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len); |
204 if (ret) { |
205 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); 206 goto out; |
207 } 208 } 209 210 ioctl_sense_size = user_ioc->sense_len; |
211 |
212 if (user_ioc->sense_len) { 213 if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent 214 1, 0, // algnmnt, boundary 215 BUS_SPACE_MAXADDR_32BIT,// lowaddr 216 BUS_SPACE_MAXADDR, // highaddr 217 NULL, NULL, // filter, filterarg 218 ioctl_sense_size, // maxsize 219 1, // msegments --- 27 unchanged lines hidden (view full) --- 247 cmd->sync_cmd = 1; 248 mrsas_issue_blocked_cmd(sc, cmd); 249 cmd->sync_cmd = 0; 250 251 /* 252 * copy out the kernel buffers to user buffers 253 */ 254 for (i = 0; i < user_ioc->sge_count; i++) { |
255 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 256 iov_base_ptrin = user_ioc->sgl[i].iov_base; 257 iov_len = user_ioc->sgl[i].iov_len; 258#ifdef COMPAT_FREEBSD32 259 } else { 260 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 261 iov_len = user_ioc32->sgl[i].iov_len; 262#endif 263 } 264 265 ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len); |
266 if (ret) { 267 device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); 268 goto out; 269 } 270 } 271 272 /* 273 * copy out the sense --- 39 unchanged lines hidden (view full) --- 313 if (ioctl_data_phys_addr[i]) 314 bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); 315 if (ioctl_data_mem[i] != NULL) 316 bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], 317 ioctl_data_dmamap[i]); 318 if (ioctl_data_tag[i] != NULL) 319 bus_dma_tag_destroy(ioctl_data_tag[i]); 320 } |
321 /* Free command */ 322 mrsas_release_mfi_cmd(cmd); 323 324 return(ret); 325} 326 327/** 328 * mrsas_alloc_mfi_cmds: Allocates the command packets --- 167 unchanged lines hidden --- |