diff options
Diffstat (limited to 'drivers/scsi/aacraid/commctrl.c')
-rw-r--r-- | drivers/scsi/aacraid/commctrl.c | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c new file mode 100644 index 000000000000..30dd1f7120f4 --- /dev/null +++ b/drivers/scsi/aacraid/commctrl.c | |||
@@ -0,0 +1,683 @@ | |||
1 | /* | ||
2 | * Adaptec AAC series RAID controller driver | ||
3 | * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> | ||
4 | * | ||
5 | * based on the old aacraid driver that is.. | ||
6 | * Adaptec aacraid device driver for Linux. | ||
7 | * | ||
8 | * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2, or (at your option) | ||
13 | * any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; see the file COPYING. If not, write to | ||
22 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | * Module Name: | ||
25 | * commctrl.c | ||
26 | * | ||
27 | * Abstract: Contains all routines for control of the AFA comm layer | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/completion.h> | ||
39 | #include <linux/dma-mapping.h> | ||
40 | #include <linux/blkdev.h> | ||
41 | #include <asm/semaphore.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | |||
44 | #include "aacraid.h" | ||
45 | |||
46 | /** | ||
47 | * ioctl_send_fib - send a FIB from userspace | ||
48 | * @dev: adapter is being processed | ||
49 | * @arg: arguments to the ioctl call | ||
50 | * | ||
51 | * This routine sends a fib to the adapter on behalf of a user level | ||
52 | * program. | ||
53 | */ | ||
54 | |||
55 | static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) | ||
56 | { | ||
57 | struct hw_fib * kfib; | ||
58 | struct fib *fibptr; | ||
59 | |||
60 | fibptr = fib_alloc(dev); | ||
61 | if(fibptr == NULL) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | kfib = fibptr->hw_fib; | ||
65 | /* | ||
66 | * First copy in the header so that we can check the size field. | ||
67 | */ | ||
68 | if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { | ||
69 | fib_free(fibptr); | ||
70 | return -EFAULT; | ||
71 | } | ||
72 | /* | ||
73 | * Since we copy based on the fib header size, make sure that we | ||
74 | * will not overrun the buffer when we copy the memory. Return | ||
75 | * an error if we would. | ||
76 | */ | ||
77 | if (le16_to_cpu(kfib->header.Size) > | ||
78 | sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) { | ||
79 | fib_free(fibptr); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | |||
83 | if (copy_from_user(kfib, arg, le16_to_cpu(kfib->header.Size) + | ||
84 | sizeof(struct aac_fibhdr))) { | ||
85 | fib_free(fibptr); | ||
86 | return -EFAULT; | ||
87 | } | ||
88 | |||
89 | if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) { | ||
90 | aac_adapter_interrupt(dev); | ||
91 | /* | ||
92 | * Since we didn't really send a fib, zero out the state to allow | ||
93 | * cleanup code not to assert. | ||
94 | */ | ||
95 | kfib->header.XferState = 0; | ||
96 | } else { | ||
97 | int retval = fib_send(kfib->header.Command, fibptr, | ||
98 | le16_to_cpu(kfib->header.Size) , FsaNormal, | ||
99 | 1, 1, NULL, NULL); | ||
100 | if (retval) { | ||
101 | fib_free(fibptr); | ||
102 | return retval; | ||
103 | } | ||
104 | if (fib_complete(fibptr) != 0) { | ||
105 | fib_free(fibptr); | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | } | ||
109 | /* | ||
110 | * Make sure that the size returned by the adapter (which includes | ||
111 | * the header) is less than or equal to the size of a fib, so we | ||
112 | * don't corrupt application data. Then copy that size to the user | ||
113 | * buffer. (Don't try to add the header information again, since it | ||
114 | * was already included by the adapter.) | ||
115 | */ | ||
116 | |||
117 | if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) { | ||
118 | fib_free(fibptr); | ||
119 | return -EFAULT; | ||
120 | } | ||
121 | fib_free(fibptr); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * open_getadapter_fib - Get the next fib | ||
127 | * | ||
128 | * This routine will get the next Fib, if available, from the AdapterFibContext | ||
129 | * passed in from the user. | ||
130 | */ | ||
131 | |||
132 | static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) | ||
133 | { | ||
134 | struct aac_fib_context * fibctx; | ||
135 | int status; | ||
136 | |||
137 | fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); | ||
138 | if (fibctx == NULL) { | ||
139 | status = -ENOMEM; | ||
140 | } else { | ||
141 | unsigned long flags; | ||
142 | struct list_head * entry; | ||
143 | struct aac_fib_context * context; | ||
144 | |||
145 | fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; | ||
146 | fibctx->size = sizeof(struct aac_fib_context); | ||
147 | /* | ||
148 | * Yes yes, I know this could be an index, but we have a | ||
149 | * better guarantee of uniqueness for the locked loop below. | ||
150 | * Without the aid of a persistent history, this also helps | ||
151 | * reduce the chance that the opaque context would be reused. | ||
152 | */ | ||
153 | fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); | ||
154 | /* | ||
155 | * Initialize the mutex used to wait for the next AIF. | ||
156 | */ | ||
157 | init_MUTEX_LOCKED(&fibctx->wait_sem); | ||
158 | fibctx->wait = 0; | ||
159 | /* | ||
160 | * Initialize the fibs and set the count of fibs on | ||
161 | * the list to 0. | ||
162 | */ | ||
163 | fibctx->count = 0; | ||
164 | INIT_LIST_HEAD(&fibctx->fib_list); | ||
165 | fibctx->jiffies = jiffies/HZ; | ||
166 | /* | ||
167 | * Now add this context onto the adapter's | ||
168 | * AdapterFibContext list. | ||
169 | */ | ||
170 | spin_lock_irqsave(&dev->fib_lock, flags); | ||
171 | /* Ensure that we have a unique identifier */ | ||
172 | entry = dev->fib_list.next; | ||
173 | while (entry != &dev->fib_list) { | ||
174 | context = list_entry(entry, struct aac_fib_context, next); | ||
175 | if (context->unique == fibctx->unique) { | ||
176 | /* Not unique (32 bits) */ | ||
177 | fibctx->unique++; | ||
178 | entry = dev->fib_list.next; | ||
179 | } else { | ||
180 | entry = entry->next; | ||
181 | } | ||
182 | } | ||
183 | list_add_tail(&fibctx->next, &dev->fib_list); | ||
184 | spin_unlock_irqrestore(&dev->fib_lock, flags); | ||
185 | if (copy_to_user(arg, &fibctx->unique, | ||
186 | sizeof(fibctx->unique))) { | ||
187 | status = -EFAULT; | ||
188 | } else { | ||
189 | status = 0; | ||
190 | } | ||
191 | } | ||
192 | return status; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * next_getadapter_fib - get the next fib | ||
197 | * @dev: adapter to use | ||
198 | * @arg: ioctl argument | ||
199 | * | ||
200 | * This routine will get the next Fib, if available, from the AdapterFibContext | ||
201 | * passed in from the user. | ||
202 | */ | ||
203 | |||
204 | static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) | ||
205 | { | ||
206 | struct fib_ioctl f; | ||
207 | struct fib *fib; | ||
208 | struct aac_fib_context *fibctx; | ||
209 | int status; | ||
210 | struct list_head * entry; | ||
211 | unsigned long flags; | ||
212 | |||
213 | if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) | ||
214 | return -EFAULT; | ||
215 | /* | ||
216 | * Verify that the HANDLE passed in was a valid AdapterFibContext | ||
217 | * | ||
218 | * Search the list of AdapterFibContext addresses on the adapter | ||
219 | * to be sure this is a valid address | ||
220 | */ | ||
221 | entry = dev->fib_list.next; | ||
222 | fibctx = NULL; | ||
223 | |||
224 | while (entry != &dev->fib_list) { | ||
225 | fibctx = list_entry(entry, struct aac_fib_context, next); | ||
226 | /* | ||
227 | * Extract the AdapterFibContext from the Input parameters. | ||
228 | */ | ||
229 | if (fibctx->unique == f.fibctx) { /* We found a winner */ | ||
230 | break; | ||
231 | } | ||
232 | entry = entry->next; | ||
233 | fibctx = NULL; | ||
234 | } | ||
235 | if (!fibctx) { | ||
236 | dprintk ((KERN_INFO "Fib Context not found\n")); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || | ||
241 | (fibctx->size != sizeof(struct aac_fib_context))) { | ||
242 | dprintk ((KERN_INFO "Fib Context corrupt?\n")); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | status = 0; | ||
246 | spin_lock_irqsave(&dev->fib_lock, flags); | ||
247 | /* | ||
248 | * If there are no fibs to send back, then either wait or return | ||
249 | * -EAGAIN | ||
250 | */ | ||
251 | return_fib: | ||
252 | if (!list_empty(&fibctx->fib_list)) { | ||
253 | struct list_head * entry; | ||
254 | /* | ||
255 | * Pull the next fib from the fibs | ||
256 | */ | ||
257 | entry = fibctx->fib_list.next; | ||
258 | list_del(entry); | ||
259 | |||
260 | fib = list_entry(entry, struct fib, fiblink); | ||
261 | fibctx->count--; | ||
262 | spin_unlock_irqrestore(&dev->fib_lock, flags); | ||
263 | if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) { | ||
264 | kfree(fib->hw_fib); | ||
265 | kfree(fib); | ||
266 | return -EFAULT; | ||
267 | } | ||
268 | /* | ||
269 | * Free the space occupied by this copy of the fib. | ||
270 | */ | ||
271 | kfree(fib->hw_fib); | ||
272 | kfree(fib); | ||
273 | status = 0; | ||
274 | fibctx->jiffies = jiffies/HZ; | ||
275 | } else { | ||
276 | spin_unlock_irqrestore(&dev->fib_lock, flags); | ||
277 | if (f.wait) { | ||
278 | if(down_interruptible(&fibctx->wait_sem) < 0) { | ||
279 | status = -EINTR; | ||
280 | } else { | ||
281 | /* Lock again and retry */ | ||
282 | spin_lock_irqsave(&dev->fib_lock, flags); | ||
283 | goto return_fib; | ||
284 | } | ||
285 | } else { | ||
286 | status = -EAGAIN; | ||
287 | } | ||
288 | } | ||
289 | return status; | ||
290 | } | ||
291 | |||
292 | int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) | ||
293 | { | ||
294 | struct fib *fib; | ||
295 | |||
296 | /* | ||
297 | * First free any FIBs that have not been consumed. | ||
298 | */ | ||
299 | while (!list_empty(&fibctx->fib_list)) { | ||
300 | struct list_head * entry; | ||
301 | /* | ||
302 | * Pull the next fib from the fibs | ||
303 | */ | ||
304 | entry = fibctx->fib_list.next; | ||
305 | list_del(entry); | ||
306 | fib = list_entry(entry, struct fib, fiblink); | ||
307 | fibctx->count--; | ||
308 | /* | ||
309 | * Free the space occupied by this copy of the fib. | ||
310 | */ | ||
311 | kfree(fib->hw_fib); | ||
312 | kfree(fib); | ||
313 | } | ||
314 | /* | ||
315 | * Remove the Context from the AdapterFibContext List | ||
316 | */ | ||
317 | list_del(&fibctx->next); | ||
318 | /* | ||
319 | * Invalidate context | ||
320 | */ | ||
321 | fibctx->type = 0; | ||
322 | /* | ||
323 | * Free the space occupied by the Context | ||
324 | */ | ||
325 | kfree(fibctx); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * close_getadapter_fib - close down user fib context | ||
331 | * @dev: adapter | ||
332 | * @arg: ioctl arguments | ||
333 | * | ||
334 | * This routine will close down the fibctx passed in from the user. | ||
335 | */ | ||
336 | |||
337 | static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) | ||
338 | { | ||
339 | struct aac_fib_context *fibctx; | ||
340 | int status; | ||
341 | unsigned long flags; | ||
342 | struct list_head * entry; | ||
343 | |||
344 | /* | ||
345 | * Verify that the HANDLE passed in was a valid AdapterFibContext | ||
346 | * | ||
347 | * Search the list of AdapterFibContext addresses on the adapter | ||
348 | * to be sure this is a valid address | ||
349 | */ | ||
350 | |||
351 | entry = dev->fib_list.next; | ||
352 | fibctx = NULL; | ||
353 | |||
354 | while(entry != &dev->fib_list) { | ||
355 | fibctx = list_entry(entry, struct aac_fib_context, next); | ||
356 | /* | ||
357 | * Extract the fibctx from the input parameters | ||
358 | */ | ||
359 | if (fibctx->unique == (u32)(unsigned long)arg) { | ||
360 | /* We found a winner */ | ||
361 | break; | ||
362 | } | ||
363 | entry = entry->next; | ||
364 | fibctx = NULL; | ||
365 | } | ||
366 | |||
367 | if (!fibctx) | ||
368 | return 0; /* Already gone */ | ||
369 | |||
370 | if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || | ||
371 | (fibctx->size != sizeof(struct aac_fib_context))) | ||
372 | return -EINVAL; | ||
373 | spin_lock_irqsave(&dev->fib_lock, flags); | ||
374 | status = aac_close_fib_context(dev, fibctx); | ||
375 | spin_unlock_irqrestore(&dev->fib_lock, flags); | ||
376 | return status; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * check_revision - close down user fib context | ||
381 | * @dev: adapter | ||
382 | * @arg: ioctl arguments | ||
383 | * | ||
384 | * This routine returns the driver version. | ||
385 | * Under Linux, there have been no version incompatibilities, so this is | ||
386 | * simple! | ||
387 | */ | ||
388 | |||
389 | static int check_revision(struct aac_dev *dev, void __user *arg) | ||
390 | { | ||
391 | struct revision response; | ||
392 | |||
393 | response.compat = 1; | ||
394 | response.version = dev->adapter_info.kernelrev; | ||
395 | response.build = dev->adapter_info.kernelbuild; | ||
396 | |||
397 | if (copy_to_user(arg, &response, sizeof(response))) | ||
398 | return -EFAULT; | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * | ||
404 | * aac_send_raw_scb | ||
405 | * | ||
406 | */ | ||
407 | |||
408 | int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | ||
409 | { | ||
410 | struct fib* srbfib; | ||
411 | int status; | ||
412 | struct aac_srb *srbcmd; | ||
413 | struct aac_srb __user *user_srb = arg; | ||
414 | struct aac_srb_reply __user *user_reply; | ||
415 | struct aac_srb_reply* reply; | ||
416 | u32 fibsize = 0; | ||
417 | u32 flags = 0; | ||
418 | s32 rcode = 0; | ||
419 | u32 data_dir; | ||
420 | void __user *sg_user[32]; | ||
421 | void *sg_list[32]; | ||
422 | u32 sg_indx = 0; | ||
423 | u32 byte_count = 0; | ||
424 | u32 actual_fibsize = 0; | ||
425 | int i; | ||
426 | |||
427 | |||
428 | if (!capable(CAP_SYS_ADMIN)){ | ||
429 | printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); | ||
430 | return -EPERM; | ||
431 | } | ||
432 | /* | ||
433 | * Allocate and initialize a Fib then setup a BlockWrite command | ||
434 | */ | ||
435 | if (!(srbfib = fib_alloc(dev))) { | ||
436 | return -1; | ||
437 | } | ||
438 | fib_init(srbfib); | ||
439 | |||
440 | srbcmd = (struct aac_srb*) fib_data(srbfib); | ||
441 | |||
442 | if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ | ||
443 | printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); | ||
444 | rcode = -EFAULT; | ||
445 | goto cleanup; | ||
446 | } | ||
447 | |||
448 | if (fibsize > FIB_DATA_SIZE_IN_BYTES) { | ||
449 | rcode = -EINVAL; | ||
450 | goto cleanup; | ||
451 | } | ||
452 | |||
453 | if(copy_from_user(srbcmd, user_srb,fibsize)){ | ||
454 | printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); | ||
455 | rcode = -EFAULT; | ||
456 | goto cleanup; | ||
457 | } | ||
458 | |||
459 | user_reply = arg+fibsize; | ||
460 | |||
461 | flags = srbcmd->flags; | ||
462 | // Fix up srb for endian and force some values | ||
463 | srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this | ||
464 | srbcmd->channel = cpu_to_le32(srbcmd->channel); | ||
465 | srbcmd->id = cpu_to_le32(srbcmd->id); | ||
466 | srbcmd->lun = cpu_to_le32(srbcmd->lun); | ||
467 | srbcmd->flags = cpu_to_le32(srbcmd->flags); | ||
468 | srbcmd->timeout = cpu_to_le32(srbcmd->timeout); | ||
469 | srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter | ||
470 | srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size); | ||
471 | |||
472 | switch (srbcmd->flags & (SRB_DataIn | SRB_DataOut)) { | ||
473 | case SRB_DataOut: | ||
474 | data_dir = DMA_TO_DEVICE; | ||
475 | break; | ||
476 | case (SRB_DataIn | SRB_DataOut): | ||
477 | data_dir = DMA_BIDIRECTIONAL; | ||
478 | break; | ||
479 | case SRB_DataIn: | ||
480 | data_dir = DMA_FROM_DEVICE; | ||
481 | break; | ||
482 | default: | ||
483 | data_dir = DMA_NONE; | ||
484 | } | ||
485 | if (dev->dac_support == 1) { | ||
486 | struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; | ||
487 | byte_count = 0; | ||
488 | |||
489 | /* | ||
490 | * This should also catch if user used the 32 bit sgmap | ||
491 | */ | ||
492 | actual_fibsize = sizeof(struct aac_srb) - | ||
493 | sizeof(struct sgentry) + ((srbcmd->sg.count & 0xff) * | ||
494 | sizeof(struct sgentry64)); | ||
495 | if(actual_fibsize != fibsize){ // User made a mistake - should not continue | ||
496 | printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"); | ||
497 | rcode = -EINVAL; | ||
498 | goto cleanup; | ||
499 | } | ||
500 | if ((data_dir == DMA_NONE) && psg->count) { | ||
501 | printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"); | ||
502 | rcode = -EINVAL; | ||
503 | goto cleanup; | ||
504 | } | ||
505 | |||
506 | for (i = 0; i < psg->count; i++) { | ||
507 | dma_addr_t addr; | ||
508 | u64 le_addr; | ||
509 | void* p; | ||
510 | p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA); | ||
511 | if(p == 0) { | ||
512 | printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
513 | psg->sg[i].count,i,psg->count); | ||
514 | rcode = -ENOMEM; | ||
515 | goto cleanup; | ||
516 | } | ||
517 | sg_user[i] = (void __user *)psg->sg[i].addr; | ||
518 | sg_list[i] = p; // save so we can clean up later | ||
519 | sg_indx = i; | ||
520 | |||
521 | if( flags & SRB_DataOut ){ | ||
522 | if(copy_from_user(p,sg_user[i],psg->sg[i].count)){ | ||
523 | printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); | ||
524 | rcode = -EFAULT; | ||
525 | goto cleanup; | ||
526 | } | ||
527 | } | ||
528 | addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir); | ||
529 | |||
530 | le_addr = cpu_to_le64(addr); | ||
531 | psg->sg[i].addr[1] = (u32)(le_addr>>32); | ||
532 | psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff); | ||
533 | psg->sg[i].count = cpu_to_le32(psg->sg[i].count); | ||
534 | byte_count += psg->sg[i].count; | ||
535 | } | ||
536 | |||
537 | srbcmd->count = cpu_to_le32(byte_count); | ||
538 | status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); | ||
539 | } else { | ||
540 | struct sgmap* psg = &srbcmd->sg; | ||
541 | byte_count = 0; | ||
542 | |||
543 | actual_fibsize = sizeof (struct aac_srb) + | ||
544 | (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * | ||
545 | sizeof (struct sgentry)); | ||
546 | if(actual_fibsize != fibsize){ // User made a mistake - should not continue | ||
547 | printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"); | ||
548 | rcode = -EINVAL; | ||
549 | goto cleanup; | ||
550 | } | ||
551 | if ((data_dir == DMA_NONE) && psg->count) { | ||
552 | printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"); | ||
553 | rcode = -EINVAL; | ||
554 | goto cleanup; | ||
555 | } | ||
556 | for (i = 0; i < psg->count; i++) { | ||
557 | dma_addr_t addr; | ||
558 | void* p; | ||
559 | p = kmalloc(psg->sg[i].count,GFP_KERNEL); | ||
560 | if(p == 0) { | ||
561 | printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
562 | psg->sg[i].count,i,psg->count); | ||
563 | rcode = -ENOMEM; | ||
564 | goto cleanup; | ||
565 | } | ||
566 | sg_user[i] = (void __user *)(psg->sg[i].addr); | ||
567 | sg_list[i] = p; // save so we can clean up later | ||
568 | sg_indx = i; | ||
569 | |||
570 | if( flags & SRB_DataOut ){ | ||
571 | if(copy_from_user(p,sg_user[i],psg->sg[i].count)){ | ||
572 | printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); | ||
573 | rcode = -EFAULT; | ||
574 | goto cleanup; | ||
575 | } | ||
576 | } | ||
577 | addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir); | ||
578 | |||
579 | psg->sg[i].addr = cpu_to_le32(addr); | ||
580 | psg->sg[i].count = cpu_to_le32(psg->sg[i].count); | ||
581 | byte_count += psg->sg[i].count; | ||
582 | } | ||
583 | srbcmd->count = cpu_to_le32(byte_count); | ||
584 | status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); | ||
585 | } | ||
586 | |||
587 | if (status != 0){ | ||
588 | printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); | ||
589 | rcode = -1; | ||
590 | goto cleanup; | ||
591 | } | ||
592 | |||
593 | if( flags & SRB_DataIn ) { | ||
594 | for(i = 0 ; i <= sg_indx; i++){ | ||
595 | if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){ | ||
596 | printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); | ||
597 | rcode = -EFAULT; | ||
598 | goto cleanup; | ||
599 | |||
600 | } | ||
601 | } | ||
602 | } | ||
603 | |||
604 | reply = (struct aac_srb_reply *) fib_data(srbfib); | ||
605 | if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){ | ||
606 | printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); | ||
607 | rcode = -EFAULT; | ||
608 | goto cleanup; | ||
609 | } | ||
610 | |||
611 | cleanup: | ||
612 | for(i=0; i <= sg_indx; i++){ | ||
613 | kfree(sg_list[i]); | ||
614 | } | ||
615 | fib_complete(srbfib); | ||
616 | fib_free(srbfib); | ||
617 | |||
618 | return rcode; | ||
619 | } | ||
620 | |||
621 | |||
622 | struct aac_pci_info { | ||
623 | u32 bus; | ||
624 | u32 slot; | ||
625 | }; | ||
626 | |||
627 | |||
628 | int aac_get_pci_info(struct aac_dev* dev, void __user *arg) | ||
629 | { | ||
630 | struct aac_pci_info pci_info; | ||
631 | |||
632 | pci_info.bus = dev->pdev->bus->number; | ||
633 | pci_info.slot = PCI_SLOT(dev->pdev->devfn); | ||
634 | |||
635 | if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { | ||
636 | printk(KERN_DEBUG "aacraid: Could not copy pci info\n"); | ||
637 | return -EFAULT; | ||
638 | } | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | |||
643 | int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) | ||
644 | { | ||
645 | int status; | ||
646 | |||
647 | /* | ||
648 | * HBA gets first crack | ||
649 | */ | ||
650 | |||
651 | status = aac_dev_ioctl(dev, cmd, arg); | ||
652 | if(status != -ENOTTY) | ||
653 | return status; | ||
654 | |||
655 | switch (cmd) { | ||
656 | case FSACTL_MINIPORT_REV_CHECK: | ||
657 | status = check_revision(dev, arg); | ||
658 | break; | ||
659 | case FSACTL_SENDFIB: | ||
660 | status = ioctl_send_fib(dev, arg); | ||
661 | break; | ||
662 | case FSACTL_OPEN_GET_ADAPTER_FIB: | ||
663 | status = open_getadapter_fib(dev, arg); | ||
664 | break; | ||
665 | case FSACTL_GET_NEXT_ADAPTER_FIB: | ||
666 | status = next_getadapter_fib(dev, arg); | ||
667 | break; | ||
668 | case FSACTL_CLOSE_GET_ADAPTER_FIB: | ||
669 | status = close_getadapter_fib(dev, arg); | ||
670 | break; | ||
671 | case FSACTL_SEND_RAW_SRB: | ||
672 | status = aac_send_raw_srb(dev,arg); | ||
673 | break; | ||
674 | case FSACTL_GET_PCI_INFO: | ||
675 | status = aac_get_pci_info(dev,arg); | ||
676 | break; | ||
677 | default: | ||
678 | status = -ENOTTY; | ||
679 | break; | ||
680 | } | ||
681 | return status; | ||
682 | } | ||
683 | |||