Deleted Added
sdiff udiff text old ( 265555 ) new ( 272737 )
full compact
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 265555 2014-05-07 16:16:49Z ambrisko $");
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);
55void mrsas_free_ioc_cmd(struct mrsas_softc *sc);
56void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
57void mrsas_dump_dcmd(struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd);
58void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc);
59void * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
60static int mrsas_create_frame_pool(struct mrsas_softc *sc);
61static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
62 int nsegs, int error);
63
64extern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc);
65extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
66extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
67 struct mrsas_mfi_cmd *cmd);
68
69
70/**
71 * mrsas_dump_ioctl: Print debug output for DCMDs
72 * input: Adapter instance soft state
73 * DCMD frame structure
74 *
75 * This function is called from mrsas_passthru() to print out debug information
76 * in the handling and routing of DCMD commands.
77 */
78void mrsas_dump_dcmd( struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd )
79{
80 int i;
81
82 device_printf(sc->mrsas_dev, "dcmd->cmd: 0x%02hhx\n", dcmd->cmd);
83 device_printf(sc->mrsas_dev, "dcmd->cmd_status: 0x%02hhx\n", dcmd->cmd_status);
84 device_printf(sc->mrsas_dev, "dcmd->sge_count: 0x%02hhx\n", dcmd->sge_count);
85 device_printf(sc->mrsas_dev, "dcmd->context: 0x%08x\n", dcmd->context);
86 device_printf(sc->mrsas_dev, "dcmd->flags: 0x%04hx\n", dcmd->flags);
87 device_printf(sc->mrsas_dev, "dcmd->timeout: 0x%04hx\n", dcmd->timeout);
88 device_printf(sc->mrsas_dev, "dcmd->data_xfer_len: 0x%08x\n", dcmd->data_xfer_len);
89 device_printf(sc->mrsas_dev, "dcmd->opcode: 0x%08x\n", dcmd->opcode);
90 device_printf(sc->mrsas_dev, "dcmd->mbox.w[0]: 0x%08x\n", dcmd->mbox.w[0]);
91 device_printf(sc->mrsas_dev, "dcmd->mbox.w[1]: 0x%08x\n", dcmd->mbox.w[1]);
92 device_printf(sc->mrsas_dev, "dcmd->mbox.w[2]: 0x%08x\n", dcmd->mbox.w[2]);
93 for (i=0; i< MIN(MAX_IOCTL_SGE, dcmd->sge_count); i++) {
94 device_printf(sc->mrsas_dev, "sgl[%02d]\n", i);
95 device_printf(sc->mrsas_dev, " sge32[%02d].phys_addr: 0x%08x\n",
96 i, dcmd->sgl.sge32[i].phys_addr);
97 device_printf(sc->mrsas_dev, " sge32[%02d].length: 0x%08x\n",
98 i, dcmd->sgl.sge32[i].length);
99 device_printf(sc->mrsas_dev, " sge64[%02d].phys_addr: 0x%08llx\n",
100 i, (long long unsigned int) dcmd->sgl.sge64[i].phys_addr);
101 device_printf(sc->mrsas_dev, " sge64[%02d].length: 0x%08x\n",
102 i, dcmd->sgl.sge64[i].length);
103 }
104}
105
106/**
107 * mrsas_dump_ioctl: Print debug output for ioctl
108 * input: Adapter instance soft state
109 * iocpacket structure
110 *
111 * This function is called from mrsas_passthru() to print out debug information
112 * in the handling and routing of ioctl commands.
113 */
114void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc)
115{
116 union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
117 struct mrsas_dcmd_frame* dcmd = (struct mrsas_dcmd_frame *) &(in_cmd->dcmd);
118 int i;
119
120 device_printf(sc->mrsas_dev,
121 "====== In %s() ======================================\n", __func__);
122 device_printf(sc->mrsas_dev, "host_no: 0x%04hx\n", user_ioc->host_no);
123 device_printf(sc->mrsas_dev, " __pad1: 0x%04hx\n", user_ioc->__pad1);
124 device_printf(sc->mrsas_dev, "sgl_off: 0x%08x\n", user_ioc->sgl_off);
125 device_printf(sc->mrsas_dev, "sge_count: 0x%08x\n", user_ioc->sge_count);
126 device_printf(sc->mrsas_dev, "sense_off: 0x%08x\n", user_ioc->sense_off);
127 device_printf(sc->mrsas_dev, "sense_len: 0x%08x\n", user_ioc->sense_len);
128
129 mrsas_dump_dcmd(sc, dcmd);
130
131 for (i=0; i< MIN(MAX_IOCTL_SGE, user_ioc->sge_count); i++) {
132 device_printf(sc->mrsas_dev, "sge[%02d]\n", i);
133 device_printf(sc->mrsas_dev,
134 " iov_base: %p\n", user_ioc->sgl[i].iov_base);
135 device_printf(sc->mrsas_dev, " iov_len: %p\n",
136 (void*)user_ioc->sgl[i].iov_len);
137 }
138 device_printf(sc->mrsas_dev,
139 "==================================================================\n");
140}
141
142/**
143 * mrsas_passthru: Handle pass-through commands
144 * input: Adapter instance soft state
145 * argument pointer
146 *
147 * This function is called from mrsas_ioctl() to handle pass-through and
148 * ioctl commands to Firmware.
149 */
150int mrsas_passthru( struct mrsas_softc *sc, void *arg )
151{
152 struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
153 union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
154 struct mrsas_mfi_cmd *cmd = NULL;
155 bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE];
156 bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE];
157 void *ioctl_data_mem[MAX_IOCTL_SGE]; // ioctl data virtual addr
158 bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr
159 bus_dma_tag_t ioctl_sense_tag = 0;
160 bus_dmamap_t ioctl_sense_dmamap = 0;
161 void *ioctl_sense_mem = 0;
162 bus_addr_t ioctl_sense_phys_addr = 0;
163 int i, adapter, ioctl_data_size, ioctl_sense_size, ret=0;
164 struct mrsas_sge32 *kern_sge32;
165 unsigned long *sense_ptr;
166
167 /* For debug - uncomment the following line for debug output */
168 //mrsas_dump_ioctl(sc, user_ioc);
169
170 /*
171 * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this
172 * case do nothing and return 0 to it as status.
173 */
174 if (in_cmd->dcmd.opcode == 0) {
175 device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__);
176 user_ioc->frame.hdr.cmd_status = MFI_STAT_OK;
177 return (0);
178 }
179
180 /* Validate host_no */
181 adapter = user_ioc->host_no;
182 if (adapter != device_get_unit(sc->mrsas_dev)) {
183 device_printf(sc->mrsas_dev, "In %s() IOCTL not for me!\n", __func__);
184 return(ENOENT);
185 }
186
187 /* Validate SGL length */
188 if (user_ioc->sge_count > MAX_IOCTL_SGE) {
189 device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n",
190 __func__, user_ioc->sge_count);
191 return(ENOENT);
192 }
193
194 /* Get a command */

--- 25 unchanged lines hidden (view full) ---

220 */
221 kern_sge32 = (struct mrsas_sge32 *)
222 ((unsigned long)cmd->frame + user_ioc->sgl_off);
223
224 /*
225 * For each user buffer, create a mirror buffer and copy in
226 */
227 for (i=0; i < user_ioc->sge_count; i++) {
228 if (!user_ioc->sgl[i].iov_len)
229 continue;
230 ioctl_data_size = user_ioc->sgl[i].iov_len;
231 if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
232 1, 0, // algnmnt, boundary
233 BUS_SPACE_MAXADDR_32BIT,// lowaddr
234 BUS_SPACE_MAXADDR, // highaddr
235 NULL, NULL, // filter, filterarg
236 ioctl_data_size, // maxsize
237 1, // msegments
238 ioctl_data_size, // maxsegsize
239 BUS_DMA_ALLOCNOW, // flags
240 NULL, NULL, // lockfunc, lockarg
241 &ioctl_data_tag[i])) {
242 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
243 return (ENOMEM);
244 }
245 if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
246 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
247 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
248 return (ENOMEM);
249 }
250 if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i],
251 ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb,
252 &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) {
253 device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n");
254 return (ENOMEM);
255 }
256
257 /* Save the physical address and length */
258 kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i];
259 kern_sge32[i].length = user_ioc->sgl[i].iov_len;
260
261 /* Copy in data from user space */
262 ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i],
263 user_ioc->sgl[i].iov_len);
264 if (ret) {
265 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
266 goto out;
267 }
268 }
269
270 ioctl_sense_size = user_ioc->sense_len;
271 if (user_ioc->sense_len) {
272 if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
273 1, 0, // algnmnt, boundary
274 BUS_SPACE_MAXADDR_32BIT,// lowaddr
275 BUS_SPACE_MAXADDR, // highaddr
276 NULL, NULL, // filter, filterarg
277 ioctl_sense_size, // maxsize
278 1, // msegments

--- 27 unchanged lines hidden (view full) ---

306 cmd->sync_cmd = 1;
307 mrsas_issue_blocked_cmd(sc, cmd);
308 cmd->sync_cmd = 0;
309
310 /*
311 * copy out the kernel buffers to user buffers
312 */
313 for (i = 0; i < user_ioc->sge_count; i++) {
314 ret = copyout(ioctl_data_mem[i], user_ioc->sgl[i].iov_base,
315 user_ioc->sgl[i].iov_len);
316 if (ret) {
317 device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n");
318 goto out;
319 }
320 }
321
322 /*
323 * copy out the sense

--- 39 unchanged lines hidden (view full) ---

363 if (ioctl_data_phys_addr[i])
364 bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]);
365 if (ioctl_data_mem[i] != NULL)
366 bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i],
367 ioctl_data_dmamap[i]);
368 if (ioctl_data_tag[i] != NULL)
369 bus_dma_tag_destroy(ioctl_data_tag[i]);
370 }
371
372 /* Free command */
373 mrsas_release_mfi_cmd(cmd);
374
375 return(ret);
376}
377
378/**
379 * mrsas_alloc_mfi_cmds: Allocates the command packets

--- 167 unchanged lines hidden ---