diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/message/fusion/mptctl.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/message/fusion/mptctl.c')
-rw-r--r-- | drivers/message/fusion/mptctl.c | 2878 |
1 files changed, 2878 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c new file mode 100644 index 000000000000..70b0cfb5ac5c --- /dev/null +++ b/drivers/message/fusion/mptctl.c | |||
@@ -0,0 +1,2878 @@ | |||
1 | /* | ||
2 | * linux/drivers/message/fusion/mptctl.c | ||
3 | * Fusion MPT misc device (ioctl) driver. | ||
4 | * For use with PCI chip/adapter(s): | ||
5 | * LSIFC9xx/LSI409xx Fibre Channel | ||
6 | * running LSI Logic Fusion MPT (Message Passing Technology) firmware. | ||
7 | * | ||
8 | * Credits: | ||
9 | * This driver would not exist if not for Alan Cox's development | ||
10 | * of the linux i2o driver. | ||
11 | * | ||
12 | * A special thanks to Pamela Delaney (LSI Logic) for tons of work | ||
13 | * and countless enhancements while adding support for the 1030 | ||
14 | * chip family. Pam has been instrumental in the development of | ||
15 | * of the 2.xx.xx series fusion drivers, and her contributions are | ||
16 | * far too numerous to hope to list in one place. | ||
17 | * | ||
18 | * A huge debt of gratitude is owed to David S. Miller (DaveM) | ||
19 | * for fixing much of the stupid and broken stuff in the early | ||
20 | * driver while porting to sparc64 platform. THANK YOU! | ||
21 | * | ||
22 | * A big THANKS to Eddie C. Dost for fixing the ioctl path | ||
23 | * and most importantly f/w download on sparc64 platform! | ||
24 | * (plus Eddie's other helpful hints and insights) | ||
25 | * | ||
26 | * Thanks to Arnaldo Carvalho de Melo for finding and patching | ||
27 | * a potential memory leak in mptctl_do_fw_download(), | ||
28 | * and for some kmalloc insight:-) | ||
29 | * | ||
30 | * (see also mptbase.c) | ||
31 | * | ||
32 | * Copyright (c) 1999-2004 LSI Logic Corporation | ||
33 | * Originally By: Steven J. Ralston, Noah Romer | ||
34 | * (mailto:sjralston1@netscape.net) | ||
35 | * (mailto:mpt_linux_developer@lsil.com) | ||
36 | * | ||
37 | * $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $ | ||
38 | */ | ||
39 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
40 | /* | ||
41 | This program is free software; you can redistribute it and/or modify | ||
42 | it under the terms of the GNU General Public License as published by | ||
43 | the Free Software Foundation; version 2 of the License. | ||
44 | |||
45 | This program is distributed in the hope that it will be useful, | ||
46 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
47 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
48 | GNU General Public License for more details. | ||
49 | |||
50 | NO WARRANTY | ||
51 | THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR | ||
52 | CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT | ||
53 | LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, | ||
54 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is | ||
55 | solely responsible for determining the appropriateness of using and | ||
56 | distributing the Program and assumes all risks associated with its | ||
57 | exercise of rights under this Agreement, including but not limited to | ||
58 | the risks and costs of program errors, damage to or loss of data, | ||
59 | programs or equipment, and unavailability or interruption of operations. | ||
60 | |||
61 | DISCLAIMER OF LIABILITY | ||
62 | NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY | ||
63 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
64 | DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND | ||
65 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
66 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
67 | USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | ||
68 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES | ||
69 | |||
70 | You should have received a copy of the GNU General Public License | ||
71 | along with this program; if not, write to the Free Software | ||
72 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
73 | */ | ||
74 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
75 | |||
76 | #include <linux/version.h> | ||
77 | #include <linux/kernel.h> | ||
78 | #include <linux/module.h> | ||
79 | #include <linux/errno.h> | ||
80 | #include <linux/init.h> | ||
81 | #include <linux/slab.h> | ||
82 | #include <linux/types.h> | ||
83 | #include <linux/pci.h> | ||
84 | #include <linux/delay.h> /* for mdelay */ | ||
85 | #include <linux/miscdevice.h> | ||
86 | #include <linux/smp_lock.h> | ||
87 | #include <linux/compat.h> | ||
88 | |||
89 | #include <asm/io.h> | ||
90 | #include <asm/uaccess.h> | ||
91 | |||
92 | #include <scsi/scsi.h> | ||
93 | #include <scsi/scsi_cmnd.h> | ||
94 | #include <scsi/scsi_device.h> | ||
95 | #include <scsi/scsi_host.h> | ||
96 | #include <scsi/scsi_tcq.h> | ||
97 | |||
98 | #define COPYRIGHT "Copyright (c) 1999-2004 LSI Logic Corporation" | ||
99 | #define MODULEAUTHOR "Steven J. Ralston, Noah Romer, Pamela Delaney" | ||
100 | #include "mptbase.h" | ||
101 | #include "mptctl.h" | ||
102 | |||
103 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
104 | #define my_NAME "Fusion MPT misc device (ioctl) driver" | ||
105 | #define my_VERSION MPT_LINUX_VERSION_COMMON | ||
106 | #define MYNAM "mptctl" | ||
107 | |||
108 | MODULE_AUTHOR(MODULEAUTHOR); | ||
109 | MODULE_DESCRIPTION(my_NAME); | ||
110 | MODULE_LICENSE("GPL"); | ||
111 | |||
112 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
113 | |||
114 | static int mptctl_id = -1; | ||
115 | |||
116 | static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); | ||
117 | |||
118 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
119 | |||
120 | struct buflist { | ||
121 | u8 *kptr; | ||
122 | int len; | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * Function prototypes. Called from OS entry point mptctl_ioctl. | ||
127 | * arg contents specific to function. | ||
128 | */ | ||
129 | static int mptctl_fw_download(unsigned long arg); | ||
130 | static int mptctl_getiocinfo (unsigned long arg, unsigned int cmd); | ||
131 | static int mptctl_gettargetinfo (unsigned long arg); | ||
132 | static int mptctl_readtest (unsigned long arg); | ||
133 | static int mptctl_mpt_command (unsigned long arg); | ||
134 | static int mptctl_eventquery (unsigned long arg); | ||
135 | static int mptctl_eventenable (unsigned long arg); | ||
136 | static int mptctl_eventreport (unsigned long arg); | ||
137 | static int mptctl_replace_fw (unsigned long arg); | ||
138 | |||
139 | static int mptctl_do_reset(unsigned long arg); | ||
140 | static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); | ||
141 | static int mptctl_hp_targetinfo(unsigned long arg); | ||
142 | |||
143 | static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); | ||
144 | static void mptctl_remove(struct pci_dev *); | ||
145 | |||
146 | #ifdef CONFIG_COMPAT | ||
147 | static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg); | ||
148 | #endif | ||
149 | /* | ||
150 | * Private function calls. | ||
151 | */ | ||
152 | static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr); | ||
153 | static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen); | ||
154 | static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags, | ||
155 | struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); | ||
156 | static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma, | ||
157 | struct buflist *buflist, MPT_ADAPTER *ioc); | ||
158 | static void mptctl_timeout_expired (MPT_IOCTL *ioctl); | ||
159 | static int mptctl_bus_reset(MPT_IOCTL *ioctl); | ||
160 | static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd); | ||
161 | static void mptctl_free_tm_flags(MPT_ADAPTER *ioc); | ||
162 | |||
163 | /* | ||
164 | * Reset Handler cleanup function | ||
165 | */ | ||
166 | static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase); | ||
167 | |||
168 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
169 | /* | ||
170 | * Scatter gather list (SGL) sizes and limits... | ||
171 | */ | ||
172 | //#define MAX_SCSI_FRAGS 9 | ||
173 | #define MAX_FRAGS_SPILL1 9 | ||
174 | #define MAX_FRAGS_SPILL2 15 | ||
175 | #define FRAGS_PER_BUCKET (MAX_FRAGS_SPILL2 + 1) | ||
176 | |||
177 | //#define MAX_CHAIN_FRAGS 64 | ||
178 | //#define MAX_CHAIN_FRAGS (15+15+15+16) | ||
179 | #define MAX_CHAIN_FRAGS (4 * MAX_FRAGS_SPILL2 + 1) | ||
180 | |||
181 | // Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each) | ||
182 | // Works out to: 592d bytes! (9+1)*8 + 4*(15+1)*8 | ||
183 | // ^----------------- 80 + 512 | ||
184 | #define MAX_SGL_BYTES ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8) | ||
185 | |||
186 | /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */ | ||
187 | #define MAX_KMALLOC_SZ (128*1024) | ||
188 | |||
189 | #define MPT_IOCTL_DEFAULT_TIMEOUT 10 /* Default timeout value (seconds) */ | ||
190 | |||
191 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
192 | /** | ||
193 | * mptctl_syscall_down - Down the MPT adapter syscall semaphore. | ||
194 | * @ioc: Pointer to MPT adapter | ||
195 | * @nonblock: boolean, non-zero if O_NONBLOCK is set | ||
196 | * | ||
197 | * All of the ioctl commands can potentially sleep, which is illegal | ||
198 | * with a spinlock held, thus we perform mutual exclusion here. | ||
199 | * | ||
200 | * Returns negative errno on error, or zero for success. | ||
201 | */ | ||
202 | static inline int | ||
203 | mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) | ||
204 | { | ||
205 | int rc = 0; | ||
206 | dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock)); | ||
207 | |||
208 | if (nonblock) { | ||
209 | if (down_trylock(&ioc->ioctl->sem_ioc)) | ||
210 | rc = -EAGAIN; | ||
211 | } else { | ||
212 | if (down_interruptible(&ioc->ioctl->sem_ioc)) | ||
213 | rc = -ERESTARTSYS; | ||
214 | } | ||
215 | dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); | ||
216 | return rc; | ||
217 | } | ||
218 | |||
219 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
220 | /* | ||
221 | * This is the callback for any message we have posted. The message itself | ||
222 | * will be returned to the message pool when we return from the IRQ | ||
223 | * | ||
224 | * This runs in irq context so be short and sweet. | ||
225 | */ | ||
226 | static int | ||
227 | mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) | ||
228 | { | ||
229 | char *sense_data; | ||
230 | int sz, req_index; | ||
231 | u16 iocStatus; | ||
232 | u8 cmd; | ||
233 | |||
234 | dctlprintk(("mptctl_reply()!\n")); | ||
235 | if (req) | ||
236 | cmd = req->u.hdr.Function; | ||
237 | else | ||
238 | return 1; | ||
239 | |||
240 | if (ioc->ioctl) { | ||
241 | |||
242 | if (reply==NULL) { | ||
243 | |||
244 | dctlprintk(("mptctl_reply() NULL Reply " | ||
245 | "Function=%x!\n", cmd)); | ||
246 | |||
247 | ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; | ||
248 | ioc->ioctl->reset &= ~MPTCTL_RESET_OK; | ||
249 | |||
250 | /* We are done, issue wake up | ||
251 | */ | ||
252 | ioc->ioctl->wait_done = 1; | ||
253 | wake_up (&mptctl_wait); | ||
254 | return 1; | ||
255 | |||
256 | } | ||
257 | |||
258 | dctlprintk(("mptctl_reply() with req=%p " | ||
259 | "reply=%p Function=%x!\n", req, reply, cmd)); | ||
260 | |||
261 | /* Copy the reply frame (which much exist | ||
262 | * for non-SCSI I/O) to the IOC structure. | ||
263 | */ | ||
264 | dctlprintk(("Copying Reply Frame @%p to ioc%d!\n", | ||
265 | reply, ioc->id)); | ||
266 | memcpy(ioc->ioctl->ReplyFrame, reply, | ||
267 | min(ioc->reply_sz, 4*reply->u.reply.MsgLength)); | ||
268 | ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; | ||
269 | |||
270 | /* Set the command status to GOOD if IOC Status is GOOD | ||
271 | * OR if SCSI I/O cmd and data underrun or recovered error. | ||
272 | */ | ||
273 | iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK; | ||
274 | if (iocStatus == MPI_IOCSTATUS_SUCCESS) | ||
275 | ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; | ||
276 | |||
277 | if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || | ||
278 | (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { | ||
279 | ioc->ioctl->reset &= ~MPTCTL_RESET_OK; | ||
280 | |||
281 | if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || | ||
282 | (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { | ||
283 | ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* Copy the sense data - if present | ||
288 | */ | ||
289 | if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && | ||
290 | (reply->u.sreply.SCSIState & | ||
291 | MPI_SCSI_STATE_AUTOSENSE_VALID)){ | ||
292 | sz = req->u.scsireq.SenseBufferLength; | ||
293 | req_index = | ||
294 | le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); | ||
295 | sense_data = | ||
296 | ((u8 *)ioc->sense_buf_pool + | ||
297 | (req_index * MPT_SENSE_BUFFER_ALLOC)); | ||
298 | memcpy(ioc->ioctl->sense, sense_data, sz); | ||
299 | ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; | ||
300 | } | ||
301 | |||
302 | if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) | ||
303 | mptctl_free_tm_flags(ioc); | ||
304 | |||
305 | /* We are done, issue wake up | ||
306 | */ | ||
307 | ioc->ioctl->wait_done = 1; | ||
308 | wake_up (&mptctl_wait); | ||
309 | } | ||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
314 | /* mptctl_timeout_expired | ||
315 | * | ||
316 | * Expecting an interrupt, however timed out. | ||
317 | * | ||
318 | */ | ||
319 | static void mptctl_timeout_expired (MPT_IOCTL *ioctl) | ||
320 | { | ||
321 | int rc = 1; | ||
322 | |||
323 | dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n", | ||
324 | ioctl->ioc->id)); | ||
325 | if (ioctl == NULL) | ||
326 | return; | ||
327 | |||
328 | ioctl->wait_done = 0; | ||
329 | if (ioctl->reset & MPTCTL_RESET_OK) | ||
330 | rc = mptctl_bus_reset(ioctl); | ||
331 | |||
332 | if (rc) { | ||
333 | /* Issue a reset for this device. | ||
334 | * The IOC is not responding. | ||
335 | */ | ||
336 | dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", | ||
337 | ioctl->ioc->name)); | ||
338 | mpt_HardResetHandler(ioctl->ioc, NO_SLEEP); | ||
339 | } | ||
340 | return; | ||
341 | |||
342 | } | ||
343 | |||
344 | /* mptctl_bus_reset | ||
345 | * | ||
346 | * Bus reset code. | ||
347 | * | ||
348 | */ | ||
349 | static int mptctl_bus_reset(MPT_IOCTL *ioctl) | ||
350 | { | ||
351 | MPT_FRAME_HDR *mf; | ||
352 | SCSITaskMgmt_t *pScsiTm; | ||
353 | MPT_SCSI_HOST *hd; | ||
354 | int ii; | ||
355 | int retval; | ||
356 | |||
357 | |||
358 | ioctl->reset &= ~MPTCTL_RESET_OK; | ||
359 | |||
360 | if (ioctl->ioc->sh == NULL) | ||
361 | return -EPERM; | ||
362 | |||
363 | hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata; | ||
364 | if (hd == NULL) | ||
365 | return -EPERM; | ||
366 | |||
367 | /* Single threading .... | ||
368 | */ | ||
369 | if (mptctl_set_tm_flags(hd) != 0) | ||
370 | return -EPERM; | ||
371 | |||
372 | /* Send request | ||
373 | */ | ||
374 | if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) { | ||
375 | dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", | ||
376 | ioctl->ioc->name)); | ||
377 | |||
378 | mptctl_free_tm_flags(ioctl->ioc); | ||
379 | return -ENOMEM; | ||
380 | } | ||
381 | |||
382 | dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", | ||
383 | ioctl->ioc->name, mf)); | ||
384 | |||
385 | pScsiTm = (SCSITaskMgmt_t *) mf; | ||
386 | pScsiTm->TargetID = ioctl->target; | ||
387 | pScsiTm->Bus = hd->port; /* 0 */ | ||
388 | pScsiTm->ChainOffset = 0; | ||
389 | pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; | ||
390 | pScsiTm->Reserved = 0; | ||
391 | pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; | ||
392 | pScsiTm->Reserved1 = 0; | ||
393 | pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; | ||
394 | |||
395 | for (ii= 0; ii < 8; ii++) | ||
396 | pScsiTm->LUN[ii] = 0; | ||
397 | |||
398 | for (ii=0; ii < 7; ii++) | ||
399 | pScsiTm->Reserved2[ii] = 0; | ||
400 | |||
401 | pScsiTm->TaskMsgContext = 0; | ||
402 | dtmprintk((MYIOC_s_INFO_FMT | ||
403 | "mptctl_bus_reset: issued.\n", ioctl->ioc->name)); | ||
404 | |||
405 | DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); | ||
406 | |||
407 | ioctl->wait_done=0; | ||
408 | if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, | ||
409 | sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { | ||
410 | dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" | ||
411 | " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, | ||
412 | hd->ioc, mf)); | ||
413 | goto mptctl_bus_reset_done; | ||
414 | } | ||
415 | |||
416 | /* Now wait for the command to complete */ | ||
417 | ii = wait_event_interruptible_timeout(mptctl_wait, | ||
418 | ioctl->wait_done == 1, | ||
419 | HZ*5 /* 5 second timeout */); | ||
420 | |||
421 | if(ii <=0 && (ioctl->wait_done != 1 )) { | ||
422 | ioctl->wait_done = 0; | ||
423 | retval = -1; /* return failure */ | ||
424 | } | ||
425 | |||
426 | mptctl_bus_reset_done: | ||
427 | |||
428 | mpt_free_msg_frame(hd->ioc, mf); | ||
429 | mptctl_free_tm_flags(ioctl->ioc); | ||
430 | return retval; | ||
431 | } | ||
432 | |||
433 | static int | ||
434 | mptctl_set_tm_flags(MPT_SCSI_HOST *hd) { | ||
435 | unsigned long flags; | ||
436 | |||
437 | spin_lock_irqsave(&hd->ioc->FreeQlock, flags); | ||
438 | |||
439 | if (hd->tmState == TM_STATE_NONE) { | ||
440 | hd->tmState = TM_STATE_IN_PROGRESS; | ||
441 | hd->tmPending = 1; | ||
442 | spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); | ||
443 | } else { | ||
444 | spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); | ||
445 | return -EBUSY; | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static void | ||
452 | mptctl_free_tm_flags(MPT_ADAPTER *ioc) | ||
453 | { | ||
454 | MPT_SCSI_HOST * hd; | ||
455 | unsigned long flags; | ||
456 | |||
457 | hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; | ||
458 | if (hd == NULL) | ||
459 | return; | ||
460 | |||
461 | spin_lock_irqsave(&ioc->FreeQlock, flags); | ||
462 | |||
463 | hd->tmState = TM_STATE_NONE; | ||
464 | hd->tmPending = 0; | ||
465 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | ||
466 | |||
467 | return; | ||
468 | } | ||
469 | |||
470 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
471 | /* mptctl_ioc_reset | ||
472 | * | ||
473 | * Clean-up functionality. Used only if there has been a | ||
474 | * reload of the FW due. | ||
475 | * | ||
476 | */ | ||
477 | static int | ||
478 | mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) | ||
479 | { | ||
480 | MPT_IOCTL *ioctl = ioc->ioctl; | ||
481 | dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n", | ||
482 | reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( | ||
483 | reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); | ||
484 | |||
485 | if(ioctl == NULL) | ||
486 | return 1; | ||
487 | |||
488 | switch(reset_phase) { | ||
489 | case MPT_IOC_SETUP_RESET: | ||
490 | ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; | ||
491 | break; | ||
492 | case MPT_IOC_POST_RESET: | ||
493 | ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET; | ||
494 | break; | ||
495 | case MPT_IOC_PRE_RESET: | ||
496 | default: | ||
497 | break; | ||
498 | } | ||
499 | |||
500 | return 1; | ||
501 | } | ||
502 | |||
503 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
504 | /* | ||
505 | * MPT ioctl handler | ||
506 | * cmd - specify the particular IOCTL command to be issued | ||
507 | * arg - data specific to the command. Must not be null. | ||
508 | */ | ||
509 | static long | ||
510 | __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
511 | { | ||
512 | mpt_ioctl_header __user *uhdr = (void __user *) arg; | ||
513 | mpt_ioctl_header khdr; | ||
514 | int iocnum; | ||
515 | unsigned iocnumX; | ||
516 | int nonblock = (file->f_flags & O_NONBLOCK); | ||
517 | int ret; | ||
518 | MPT_ADAPTER *iocp = NULL; | ||
519 | |||
520 | dctlprintk(("mptctl_ioctl() called\n")); | ||
521 | |||
522 | if (copy_from_user(&khdr, uhdr, sizeof(khdr))) { | ||
523 | printk(KERN_ERR "%s::mptctl_ioctl() @%d - " | ||
524 | "Unable to copy mpt_ioctl_header data @ %p\n", | ||
525 | __FILE__, __LINE__, uhdr); | ||
526 | return -EFAULT; | ||
527 | } | ||
528 | ret = -ENXIO; /* (-6) No such device or address */ | ||
529 | |||
530 | /* Verify intended MPT adapter - set iocnum and the adapter | ||
531 | * pointer (iocp) | ||
532 | */ | ||
533 | iocnumX = khdr.iocnum & 0xFF; | ||
534 | if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || | ||
535 | (iocp == NULL)) { | ||
536 | dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", | ||
537 | __FILE__, __LINE__, iocnumX)); | ||
538 | return -ENODEV; | ||
539 | } | ||
540 | |||
541 | if (!iocp->active) { | ||
542 | printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n", | ||
543 | __FILE__, __LINE__); | ||
544 | return -EFAULT; | ||
545 | } | ||
546 | |||
547 | /* Handle those commands that are just returning | ||
548 | * information stored in the driver. | ||
549 | * These commands should never time out and are unaffected | ||
550 | * by TM and FW reloads. | ||
551 | */ | ||
552 | if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) { | ||
553 | return mptctl_getiocinfo(arg, _IOC_SIZE(cmd)); | ||
554 | } else if (cmd == MPTTARGETINFO) { | ||
555 | return mptctl_gettargetinfo(arg); | ||
556 | } else if (cmd == MPTTEST) { | ||
557 | return mptctl_readtest(arg); | ||
558 | } else if (cmd == MPTEVENTQUERY) { | ||
559 | return mptctl_eventquery(arg); | ||
560 | } else if (cmd == MPTEVENTENABLE) { | ||
561 | return mptctl_eventenable(arg); | ||
562 | } else if (cmd == MPTEVENTREPORT) { | ||
563 | return mptctl_eventreport(arg); | ||
564 | } else if (cmd == MPTFWREPLACE) { | ||
565 | return mptctl_replace_fw(arg); | ||
566 | } | ||
567 | |||
568 | /* All of these commands require an interrupt or | ||
569 | * are unknown/illegal. | ||
570 | */ | ||
571 | if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) | ||
572 | return ret; | ||
573 | |||
574 | dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name)); | ||
575 | |||
576 | if (cmd == MPTFWDOWNLOAD) | ||
577 | ret = mptctl_fw_download(arg); | ||
578 | else if (cmd == MPTCOMMAND) | ||
579 | ret = mptctl_mpt_command(arg); | ||
580 | else if (cmd == MPTHARDRESET) | ||
581 | ret = mptctl_do_reset(arg); | ||
582 | else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK)) | ||
583 | ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd)); | ||
584 | else if (cmd == HP_GETTARGETINFO) | ||
585 | ret = mptctl_hp_targetinfo(arg); | ||
586 | else | ||
587 | ret = -EINVAL; | ||
588 | |||
589 | up(&iocp->ioctl->sem_ioc); | ||
590 | |||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | static long | ||
595 | mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
596 | { | ||
597 | long ret; | ||
598 | lock_kernel(); | ||
599 | ret = __mptctl_ioctl(file, cmd, arg); | ||
600 | unlock_kernel(); | ||
601 | return ret; | ||
602 | } | ||
603 | |||
604 | static int mptctl_do_reset(unsigned long arg) | ||
605 | { | ||
606 | struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg; | ||
607 | struct mpt_ioctl_diag_reset krinfo; | ||
608 | MPT_ADAPTER *iocp; | ||
609 | |||
610 | dctlprintk((KERN_INFO "mptctl_do_reset called.\n")); | ||
611 | |||
612 | if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { | ||
613 | printk(KERN_ERR "%s@%d::mptctl_do_reset - " | ||
614 | "Unable to copy mpt_ioctl_diag_reset struct @ %p\n", | ||
615 | __FILE__, __LINE__, urinfo); | ||
616 | return -EFAULT; | ||
617 | } | ||
618 | |||
619 | if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { | ||
620 | dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", | ||
621 | __FILE__, __LINE__, krinfo.hdr.iocnum)); | ||
622 | return -ENODEV; /* (-6) No such device or address */ | ||
623 | } | ||
624 | |||
625 | if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) { | ||
626 | printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", | ||
627 | __FILE__, __LINE__); | ||
628 | return -1; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
635 | /* | ||
636 | * MPT FW download function. Cast the arg into the mpt_fw_xfer structure. | ||
637 | * This structure contains: iocnum, firmware length (bytes), | ||
638 | * pointer to user space memory where the fw image is stored. | ||
639 | * | ||
640 | * Outputs: None. | ||
641 | * Return: 0 if successful | ||
642 | * -EFAULT if data unavailable | ||
643 | * -ENXIO if no such device | ||
644 | * -EAGAIN if resource problem | ||
645 | * -ENOMEM if no memory for SGE | ||
646 | * -EMLINK if too many chain buffers required | ||
647 | * -EBADRQC if adapter does not support FW download | ||
648 | * -EBUSY if adapter is busy | ||
649 | * -ENOMSG if FW upload returned bad status | ||
650 | */ | ||
651 | static int | ||
652 | mptctl_fw_download(unsigned long arg) | ||
653 | { | ||
654 | struct mpt_fw_xfer __user *ufwdl = (void __user *) arg; | ||
655 | struct mpt_fw_xfer kfwdl; | ||
656 | |||
657 | dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc | ||
658 | if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { | ||
659 | printk(KERN_ERR "%s@%d::_ioctl_fwdl - " | ||
660 | "Unable to copy mpt_fw_xfer struct @ %p\n", | ||
661 | __FILE__, __LINE__, ufwdl); | ||
662 | return -EFAULT; | ||
663 | } | ||
664 | |||
665 | return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); | ||
666 | } | ||
667 | |||
668 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
669 | /* | ||
670 | * FW Download engine. | ||
671 | * Outputs: None. | ||
672 | * Return: 0 if successful | ||
673 | * -EFAULT if data unavailable | ||
674 | * -ENXIO if no such device | ||
675 | * -EAGAIN if resource problem | ||
676 | * -ENOMEM if no memory for SGE | ||
677 | * -EMLINK if too many chain buffers required | ||
678 | * -EBADRQC if adapter does not support FW download | ||
679 | * -EBUSY if adapter is busy | ||
680 | * -ENOMSG if FW upload returned bad status | ||
681 | */ | ||
682 | static int | ||
683 | mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) | ||
684 | { | ||
685 | FWDownload_t *dlmsg; | ||
686 | MPT_FRAME_HDR *mf; | ||
687 | MPT_ADAPTER *iocp; | ||
688 | FWDownloadTCSGE_t *ptsge; | ||
689 | MptSge_t *sgl, *sgIn; | ||
690 | char *sgOut; | ||
691 | struct buflist *buflist; | ||
692 | struct buflist *bl; | ||
693 | dma_addr_t sgl_dma; | ||
694 | int ret; | ||
695 | int numfrags = 0; | ||
696 | int maxfrags; | ||
697 | int n = 0; | ||
698 | u32 sgdir; | ||
699 | u32 nib; | ||
700 | int fw_bytes_copied = 0; | ||
701 | int i; | ||
702 | int sge_offset = 0; | ||
703 | u16 iocstat; | ||
704 | pFWDownloadReply_t ReplyMsg = NULL; | ||
705 | |||
706 | dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); | ||
707 | |||
708 | dctlprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf)); | ||
709 | dctlprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen)); | ||
710 | dctlprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); | ||
711 | |||
712 | if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { | ||
713 | dctlprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n", | ||
714 | __FILE__, __LINE__, ioc)); | ||
715 | return -ENODEV; /* (-6) No such device or address */ | ||
716 | } | ||
717 | |||
718 | /* Valid device. Get a message frame and construct the FW download message. | ||
719 | */ | ||
720 | if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) | ||
721 | return -EAGAIN; | ||
722 | dlmsg = (FWDownload_t*) mf; | ||
723 | ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL; | ||
724 | sgOut = (char *) (ptsge + 1); | ||
725 | |||
726 | /* | ||
727 | * Construct f/w download request | ||
728 | */ | ||
729 | dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW; | ||
730 | dlmsg->Reserved = 0; | ||
731 | dlmsg->ChainOffset = 0; | ||
732 | dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD; | ||
733 | dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0; | ||
734 | dlmsg->MsgFlags = 0; | ||
735 | |||
736 | /* Set up the Transaction SGE. | ||
737 | */ | ||
738 | ptsge->Reserved = 0; | ||
739 | ptsge->ContextSize = 0; | ||
740 | ptsge->DetailsLength = 12; | ||
741 | ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; | ||
742 | ptsge->Reserved_0100_Checksum = 0; | ||
743 | ptsge->ImageOffset = 0; | ||
744 | ptsge->ImageSize = cpu_to_le32(fwlen); | ||
745 | |||
746 | /* Add the SGL | ||
747 | */ | ||
748 | |||
749 | /* | ||
750 | * Need to kmalloc area(s) for holding firmware image bytes. | ||
751 | * But we need to do it piece meal, using a proper | ||
752 | * scatter gather list (with 128kB MAX hunks). | ||
753 | * | ||
754 | * A practical limit here might be # of sg hunks that fit into | ||
755 | * a single IOC request frame; 12 or 8 (see below), so: | ||
756 | * For FC9xx: 12 x 128kB == 1.5 mB (max) | ||
757 | * For C1030: 8 x 128kB == 1 mB (max) | ||
758 | * We could support chaining, but things get ugly(ier:) | ||
759 | * | ||
760 | * Set the sge_offset to the start of the sgl (bytes). | ||
761 | */ | ||
762 | sgdir = 0x04000000; /* IOC will READ from sys mem */ | ||
763 | sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t); | ||
764 | if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset, | ||
765 | &numfrags, &buflist, &sgl_dma, iocp)) == NULL) | ||
766 | return -ENOMEM; | ||
767 | |||
768 | /* | ||
769 | * We should only need SGL with 2 simple_32bit entries (up to 256 kB) | ||
770 | * for FC9xx f/w image, but calculate max number of sge hunks | ||
771 | * we can fit into a request frame, and limit ourselves to that. | ||
772 | * (currently no chain support) | ||
773 | * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE | ||
774 | * Request maxfrags | ||
775 | * 128 12 | ||
776 | * 96 8 | ||
777 | * 64 4 | ||
778 | */ | ||
779 | maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) | ||
780 | / (sizeof(dma_addr_t) + sizeof(u32)); | ||
781 | if (numfrags > maxfrags) { | ||
782 | ret = -EMLINK; | ||
783 | goto fwdl_out; | ||
784 | } | ||
785 | |||
786 | dctlprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); | ||
787 | |||
788 | /* | ||
789 | * Parse SG list, copying sgl itself, | ||
790 | * plus f/w image hunks from user space as we go... | ||
791 | */ | ||
792 | ret = -EFAULT; | ||
793 | sgIn = sgl; | ||
794 | bl = buflist; | ||
795 | for (i=0; i < numfrags; i++) { | ||
796 | |||
797 | /* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE | ||
798 | * Skip everything but Simple. If simple, copy from | ||
799 | * user space into kernel space. | ||
800 | * Note: we should not have anything but Simple as | ||
801 | * Chain SGE are illegal. | ||
802 | */ | ||
803 | nib = (sgIn->FlagsLength & 0x30000000) >> 28; | ||
804 | if (nib == 0 || nib == 3) { | ||
805 | ; | ||
806 | } else if (sgIn->Address) { | ||
807 | mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); | ||
808 | n++; | ||
809 | if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { | ||
810 | printk(KERN_ERR "%s@%d::_ioctl_fwdl - " | ||
811 | "Unable to copy f/w buffer hunk#%d @ %p\n", | ||
812 | __FILE__, __LINE__, n, ufwbuf); | ||
813 | goto fwdl_out; | ||
814 | } | ||
815 | fw_bytes_copied += bl->len; | ||
816 | } | ||
817 | sgIn++; | ||
818 | bl++; | ||
819 | sgOut += (sizeof(dma_addr_t) + sizeof(u32)); | ||
820 | } | ||
821 | |||
822 | #ifdef MPT_DEBUG | ||
823 | { | ||
824 | u32 *m = (u32 *)mf; | ||
825 | printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " "); | ||
826 | for (i=0; i < 7+numfrags*2; i++) | ||
827 | printk(" %08x", le32_to_cpu(m[i])); | ||
828 | printk("\n"); | ||
829 | } | ||
830 | #endif | ||
831 | |||
832 | /* | ||
833 | * Finally, perform firmware download. | ||
834 | */ | ||
835 | iocp->ioctl->wait_done = 0; | ||
836 | mpt_put_msg_frame(mptctl_id, iocp, mf); | ||
837 | |||
838 | /* Now wait for the command to complete */ | ||
839 | ret = wait_event_interruptible_timeout(mptctl_wait, | ||
840 | iocp->ioctl->wait_done == 1, | ||
841 | HZ*60); | ||
842 | |||
843 | if(ret <=0 && (iocp->ioctl->wait_done != 1 )) { | ||
844 | /* Now we need to reset the board */ | ||
845 | mptctl_timeout_expired(iocp->ioctl); | ||
846 | ret = -ENODATA; | ||
847 | goto fwdl_out; | ||
848 | } | ||
849 | |||
850 | if (sgl) | ||
851 | kfree_sgl(sgl, sgl_dma, buflist, iocp); | ||
852 | |||
853 | ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; | ||
854 | iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; | ||
855 | if (iocstat == MPI_IOCSTATUS_SUCCESS) { | ||
856 | printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name); | ||
857 | return 0; | ||
858 | } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { | ||
859 | printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n", | ||
860 | iocp->name); | ||
861 | printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n"); | ||
862 | return -EBADRQC; | ||
863 | } else if (iocstat == MPI_IOCSTATUS_BUSY) { | ||
864 | printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); | ||
865 | printk(KERN_WARNING MYNAM ": (try again later?)\n"); | ||
866 | return -EBUSY; | ||
867 | } else { | ||
868 | printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", | ||
869 | iocp->name, iocstat); | ||
870 | printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); | ||
871 | return -ENOMSG; | ||
872 | } | ||
873 | return 0; | ||
874 | |||
875 | fwdl_out: | ||
876 | kfree_sgl(sgl, sgl_dma, buflist, iocp); | ||
877 | return ret; | ||
878 | } | ||
879 | |||
880 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
881 | /* | ||
882 | * SGE Allocation routine | ||
883 | * | ||
884 | * Inputs: bytes - number of bytes to be transferred | ||
885 | * sgdir - data direction | ||
886 | * sge_offset - offset (in bytes) from the start of the request | ||
887 | * frame to the first SGE | ||
888 | * ioc - pointer to the mptadapter | ||
889 | * Outputs: frags - number of scatter gather elements | ||
890 | * blp - point to the buflist pointer | ||
891 | * sglbuf_dma - pointer to the (dma) sgl | ||
892 | * Returns: Null if failes | ||
893 | * pointer to the (virtual) sgl if successful. | ||
894 | */ | ||
895 | static MptSge_t * | ||
896 | kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, | ||
897 | struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc) | ||
898 | { | ||
899 | MptSge_t *sglbuf = NULL; /* pointer to array of SGE */ | ||
900 | /* and chain buffers */ | ||
901 | struct buflist *buflist = NULL; /* kernel routine */ | ||
902 | MptSge_t *sgl; | ||
903 | int numfrags = 0; | ||
904 | int fragcnt = 0; | ||
905 | int alloc_sz = min(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg! | ||
906 | int bytes_allocd = 0; | ||
907 | int this_alloc; | ||
908 | dma_addr_t pa; // phys addr | ||
909 | int i, buflist_ent; | ||
910 | int sg_spill = MAX_FRAGS_SPILL1; | ||
911 | int dir; | ||
912 | /* initialization */ | ||
913 | *frags = 0; | ||
914 | *blp = NULL; | ||
915 | |||
916 | /* Allocate and initialize an array of kernel | ||
917 | * structures for the SG elements. | ||
918 | */ | ||
919 | i = MAX_SGL_BYTES / 8; | ||
920 | buflist = kmalloc(i, GFP_USER); | ||
921 | if (buflist == NULL) | ||
922 | return NULL; | ||
923 | memset(buflist, 0, i); | ||
924 | buflist_ent = 0; | ||
925 | |||
926 | /* Allocate a single block of memory to store the sg elements and | ||
927 | * the chain buffers. The calling routine is responsible for | ||
928 | * copying the data in this array into the correct place in the | ||
929 | * request and chain buffers. | ||
930 | */ | ||
931 | sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma); | ||
932 | if (sglbuf == NULL) | ||
933 | goto free_and_fail; | ||
934 | |||
935 | if (sgdir & 0x04000000) | ||
936 | dir = PCI_DMA_TODEVICE; | ||
937 | else | ||
938 | dir = PCI_DMA_FROMDEVICE; | ||
939 | |||
940 | /* At start: | ||
941 | * sgl = sglbuf = point to beginning of sg buffer | ||
942 | * buflist_ent = 0 = first kernel structure | ||
943 | * sg_spill = number of SGE that can be written before the first | ||
944 | * chain element. | ||
945 | * | ||
946 | */ | ||
947 | sgl = sglbuf; | ||
948 | sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; | ||
949 | while (bytes_allocd < bytes) { | ||
950 | this_alloc = min(alloc_sz, bytes-bytes_allocd); | ||
951 | buflist[buflist_ent].len = this_alloc; | ||
952 | buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev, | ||
953 | this_alloc, | ||
954 | &pa); | ||
955 | if (buflist[buflist_ent].kptr == NULL) { | ||
956 | alloc_sz = alloc_sz / 2; | ||
957 | if (alloc_sz == 0) { | ||
958 | printk(KERN_WARNING MYNAM "-SG: No can do - " | ||
959 | "not enough memory! :-(\n"); | ||
960 | printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", | ||
961 | numfrags); | ||
962 | goto free_and_fail; | ||
963 | } | ||
964 | continue; | ||
965 | } else { | ||
966 | dma_addr_t dma_addr; | ||
967 | |||
968 | bytes_allocd += this_alloc; | ||
969 | sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); | ||
970 | dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); | ||
971 | sgl->Address = dma_addr; | ||
972 | |||
973 | fragcnt++; | ||
974 | numfrags++; | ||
975 | sgl++; | ||
976 | buflist_ent++; | ||
977 | } | ||
978 | |||
979 | if (bytes_allocd >= bytes) | ||
980 | break; | ||
981 | |||
982 | /* Need to chain? */ | ||
983 | if (fragcnt == sg_spill) { | ||
984 | printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n"); | ||
985 | printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags); | ||
986 | goto free_and_fail; | ||
987 | } | ||
988 | |||
989 | /* overflow check... */ | ||
990 | if (numfrags*8 > MAX_SGL_BYTES){ | ||
991 | /* GRRRRR... */ | ||
992 | printk(KERN_WARNING MYNAM "-SG: No can do - " | ||
993 | "too many SG frags! :-(\n"); | ||
994 | printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", | ||
995 | numfrags); | ||
996 | goto free_and_fail; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | /* Last sge fixup: set LE+eol+eob bits */ | ||
1001 | sgl[-1].FlagsLength |= 0xC1000000; | ||
1002 | |||
1003 | *frags = numfrags; | ||
1004 | *blp = buflist; | ||
1005 | |||
1006 | dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " | ||
1007 | "%d SG frags generated!\n", | ||
1008 | numfrags)); | ||
1009 | |||
1010 | dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " | ||
1011 | "last (big) alloc_sz=%d\n", | ||
1012 | alloc_sz)); | ||
1013 | |||
1014 | return sglbuf; | ||
1015 | |||
1016 | free_and_fail: | ||
1017 | if (sglbuf != NULL) { | ||
1018 | int i; | ||
1019 | |||
1020 | for (i = 0; i < numfrags; i++) { | ||
1021 | dma_addr_t dma_addr; | ||
1022 | u8 *kptr; | ||
1023 | int len; | ||
1024 | |||
1025 | if ((sglbuf[i].FlagsLength >> 24) == 0x30) | ||
1026 | continue; | ||
1027 | |||
1028 | dma_addr = sglbuf[i].Address; | ||
1029 | kptr = buflist[i].kptr; | ||
1030 | len = buflist[i].len; | ||
1031 | |||
1032 | pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); | ||
1033 | } | ||
1034 | pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma); | ||
1035 | } | ||
1036 | kfree(buflist); | ||
1037 | return NULL; | ||
1038 | } | ||
1039 | |||
1040 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1041 | /* | ||
1042 | * Routine to free the SGL elements. | ||
1043 | */ | ||
1044 | static void | ||
1045 | kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc) | ||
1046 | { | ||
1047 | MptSge_t *sg = sgl; | ||
1048 | struct buflist *bl = buflist; | ||
1049 | u32 nib; | ||
1050 | int dir; | ||
1051 | int n = 0; | ||
1052 | |||
1053 | if (sg->FlagsLength & 0x04000000) | ||
1054 | dir = PCI_DMA_TODEVICE; | ||
1055 | else | ||
1056 | dir = PCI_DMA_FROMDEVICE; | ||
1057 | |||
1058 | nib = (sg->FlagsLength & 0xF0000000) >> 28; | ||
1059 | while (! (nib & 0x4)) { /* eob */ | ||
1060 | /* skip ignore/chain. */ | ||
1061 | if (nib == 0 || nib == 3) { | ||
1062 | ; | ||
1063 | } else if (sg->Address) { | ||
1064 | dma_addr_t dma_addr; | ||
1065 | void *kptr; | ||
1066 | int len; | ||
1067 | |||
1068 | dma_addr = sg->Address; | ||
1069 | kptr = bl->kptr; | ||
1070 | len = bl->len; | ||
1071 | pci_unmap_single(ioc->pcidev, dma_addr, len, dir); | ||
1072 | pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); | ||
1073 | n++; | ||
1074 | } | ||
1075 | sg++; | ||
1076 | bl++; | ||
1077 | nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28; | ||
1078 | } | ||
1079 | |||
1080 | /* we're at eob! */ | ||
1081 | if (sg->Address) { | ||
1082 | dma_addr_t dma_addr; | ||
1083 | void *kptr; | ||
1084 | int len; | ||
1085 | |||
1086 | dma_addr = sg->Address; | ||
1087 | kptr = bl->kptr; | ||
1088 | len = bl->len; | ||
1089 | pci_unmap_single(ioc->pcidev, dma_addr, len, dir); | ||
1090 | pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); | ||
1091 | n++; | ||
1092 | } | ||
1093 | |||
1094 | pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); | ||
1095 | kfree(buflist); | ||
1096 | dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); | ||
1097 | } | ||
1098 | |||
1099 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1100 | /* | ||
1101 | * mptctl_getiocinfo - Query the host adapter for IOC information. | ||
1102 | * @arg: User space argument | ||
1103 | * | ||
1104 | * Outputs: None. | ||
1105 | * Return: 0 if successful | ||
1106 | * -EFAULT if data unavailable | ||
1107 | * -ENODEV if no such device/adapter | ||
1108 | */ | ||
1109 | static int | ||
1110 | mptctl_getiocinfo (unsigned long arg, unsigned int data_size) | ||
1111 | { | ||
1112 | struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg; | ||
1113 | struct mpt_ioctl_iocinfo *karg; | ||
1114 | MPT_ADAPTER *ioc; | ||
1115 | struct pci_dev *pdev; | ||
1116 | struct Scsi_Host *sh; | ||
1117 | MPT_SCSI_HOST *hd; | ||
1118 | int iocnum; | ||
1119 | int numDevices = 0; | ||
1120 | unsigned int max_id; | ||
1121 | int ii; | ||
1122 | int port; | ||
1123 | int cim_rev; | ||
1124 | u8 revision; | ||
1125 | |||
1126 | dctlprintk((": mptctl_getiocinfo called.\n")); | ||
1127 | /* Add of PCI INFO results in unaligned access for | ||
1128 | * IA64 and Sparc. Reset long to int. Return no PCI | ||
1129 | * data for obsolete format. | ||
1130 | */ | ||
1131 | if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0)) | ||
1132 | cim_rev = 0; | ||
1133 | else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1)) | ||
1134 | cim_rev = 1; | ||
1135 | else if (data_size == sizeof(struct mpt_ioctl_iocinfo)) | ||
1136 | cim_rev = 2; | ||
1137 | else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12)) | ||
1138 | cim_rev = 0; /* obsolete */ | ||
1139 | else | ||
1140 | return -EFAULT; | ||
1141 | |||
1142 | karg = kmalloc(data_size, GFP_KERNEL); | ||
1143 | if (karg == NULL) { | ||
1144 | printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", | ||
1145 | __FILE__, __LINE__); | ||
1146 | return -ENOMEM; | ||
1147 | } | ||
1148 | |||
1149 | if (copy_from_user(karg, uarg, data_size)) { | ||
1150 | printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " | ||
1151 | "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", | ||
1152 | __FILE__, __LINE__, uarg); | ||
1153 | kfree(karg); | ||
1154 | return -EFAULT; | ||
1155 | } | ||
1156 | |||
1157 | if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || | ||
1158 | (ioc == NULL)) { | ||
1159 | dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", | ||
1160 | __FILE__, __LINE__, iocnum)); | ||
1161 | kfree(karg); | ||
1162 | return -ENODEV; | ||
1163 | } | ||
1164 | |||
1165 | /* Verify the data transfer size is correct. | ||
1166 | * Ignore the port setting. | ||
1167 | */ | ||
1168 | if (karg->hdr.maxDataSize != data_size) { | ||
1169 | printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " | ||
1170 | "Structure size mismatch. Command not completed.\n", | ||
1171 | __FILE__, __LINE__); | ||
1172 | kfree(karg); | ||
1173 | return -EFAULT; | ||
1174 | } | ||
1175 | |||
1176 | /* Fill in the data and return the structure to the calling | ||
1177 | * program | ||
1178 | */ | ||
1179 | if (ioc->bus_type == FC) | ||
1180 | karg->adapterType = MPT_IOCTL_INTERFACE_FC; | ||
1181 | else | ||
1182 | karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; | ||
1183 | |||
1184 | port = karg->hdr.port; | ||
1185 | |||
1186 | karg->port = port; | ||
1187 | pdev = (struct pci_dev *) ioc->pcidev; | ||
1188 | |||
1189 | karg->pciId = pdev->device; | ||
1190 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | ||
1191 | karg->hwRev = revision; | ||
1192 | karg->subSystemDevice = pdev->subsystem_device; | ||
1193 | karg->subSystemVendor = pdev->subsystem_vendor; | ||
1194 | |||
1195 | if (cim_rev == 1) { | ||
1196 | /* Get the PCI bus, device, and function numbers for the IOC | ||
1197 | */ | ||
1198 | karg->pciInfo.u.bits.busNumber = pdev->bus->number; | ||
1199 | karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); | ||
1200 | karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); | ||
1201 | } else if (cim_rev == 2) { | ||
1202 | /* Get the PCI bus, device, function and segment ID numbers | ||
1203 | for the IOC */ | ||
1204 | karg->pciInfo.u.bits.busNumber = pdev->bus->number; | ||
1205 | karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); | ||
1206 | karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); | ||
1207 | karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); | ||
1208 | karg->pciInfo.segmentID = pci_domain_nr(pdev->bus); | ||
1209 | } | ||
1210 | |||
1211 | /* Get number of devices | ||
1212 | */ | ||
1213 | if ((sh = ioc->sh) != NULL) { | ||
1214 | /* sh->max_id = maximum target ID + 1 | ||
1215 | */ | ||
1216 | max_id = sh->max_id - 1; | ||
1217 | hd = (MPT_SCSI_HOST *) sh->hostdata; | ||
1218 | |||
1219 | /* Check all of the target structures and | ||
1220 | * keep a counter. | ||
1221 | */ | ||
1222 | if (hd && hd->Targets) { | ||
1223 | for (ii = 0; ii <= max_id; ii++) { | ||
1224 | if (hd->Targets[ii]) | ||
1225 | numDevices++; | ||
1226 | } | ||
1227 | } | ||
1228 | } | ||
1229 | karg->numDevices = numDevices; | ||
1230 | |||
1231 | /* Set the BIOS and FW Version | ||
1232 | */ | ||
1233 | karg->FWVersion = ioc->facts.FWVersion.Word; | ||
1234 | karg->BIOSVersion = ioc->biosVersion; | ||
1235 | |||
1236 | /* Set the Version Strings. | ||
1237 | */ | ||
1238 | strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); | ||
1239 | karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; | ||
1240 | |||
1241 | karg->busChangeEvent = 0; | ||
1242 | karg->hostId = ioc->pfacts[port].PortSCSIID; | ||
1243 | karg->rsvd[0] = karg->rsvd[1] = 0; | ||
1244 | |||
1245 | /* Copy the data from kernel memory to user memory | ||
1246 | */ | ||
1247 | if (copy_to_user((char __user *)arg, karg, data_size)) { | ||
1248 | printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " | ||
1249 | "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", | ||
1250 | __FILE__, __LINE__, uarg); | ||
1251 | kfree(karg); | ||
1252 | return -EFAULT; | ||
1253 | } | ||
1254 | |||
1255 | kfree(karg); | ||
1256 | return 0; | ||
1257 | } | ||
1258 | |||
1259 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1260 | /* | ||
1261 | * mptctl_gettargetinfo - Query the host adapter for target information. | ||
1262 | * @arg: User space argument | ||
1263 | * | ||
1264 | * Outputs: None. | ||
1265 | * Return: 0 if successful | ||
1266 | * -EFAULT if data unavailable | ||
1267 | * -ENODEV if no such device/adapter | ||
1268 | */ | ||
1269 | static int | ||
1270 | mptctl_gettargetinfo (unsigned long arg) | ||
1271 | { | ||
1272 | struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; | ||
1273 | struct mpt_ioctl_targetinfo karg; | ||
1274 | MPT_ADAPTER *ioc; | ||
1275 | struct Scsi_Host *sh; | ||
1276 | MPT_SCSI_HOST *hd; | ||
1277 | VirtDevice *vdev; | ||
1278 | char *pmem; | ||
1279 | int *pdata; | ||
1280 | IOCPage2_t *pIoc2; | ||
1281 | IOCPage3_t *pIoc3; | ||
1282 | int iocnum; | ||
1283 | int numDevices = 0; | ||
1284 | unsigned int max_id; | ||
1285 | int id, jj, indexed_lun, lun_index; | ||
1286 | u32 lun; | ||
1287 | int maxWordsLeft; | ||
1288 | int numBytes; | ||
1289 | u8 port, devType, bus_id; | ||
1290 | |||
1291 | dctlprintk(("mptctl_gettargetinfo called.\n")); | ||
1292 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { | ||
1293 | printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " | ||
1294 | "Unable to read in mpt_ioctl_targetinfo struct @ %p\n", | ||
1295 | __FILE__, __LINE__, uarg); | ||
1296 | return -EFAULT; | ||
1297 | } | ||
1298 | |||
1299 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1300 | (ioc == NULL)) { | ||
1301 | dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", | ||
1302 | __FILE__, __LINE__, iocnum)); | ||
1303 | return -ENODEV; | ||
1304 | } | ||
1305 | |||
1306 | /* Get the port number and set the maximum number of bytes | ||
1307 | * in the returned structure. | ||
1308 | * Ignore the port setting. | ||
1309 | */ | ||
1310 | numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); | ||
1311 | maxWordsLeft = numBytes/sizeof(int); | ||
1312 | port = karg.hdr.port; | ||
1313 | |||
1314 | if (maxWordsLeft <= 0) { | ||
1315 | printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", | ||
1316 | __FILE__, __LINE__); | ||
1317 | return -ENOMEM; | ||
1318 | } | ||
1319 | |||
1320 | /* Fill in the data and return the structure to the calling | ||
1321 | * program | ||
1322 | */ | ||
1323 | |||
1324 | /* struct mpt_ioctl_targetinfo does not contain sufficient space | ||
1325 | * for the target structures so when the IOCTL is called, there is | ||
1326 | * not sufficient stack space for the structure. Allocate memory, | ||
1327 | * populate the memory, copy back to the user, then free memory. | ||
1328 | * targetInfo format: | ||
1329 | * bits 31-24: reserved | ||
1330 | * 23-16: LUN | ||
1331 | * 15- 8: Bus Number | ||
1332 | * 7- 0: Target ID | ||
1333 | */ | ||
1334 | pmem = kmalloc(numBytes, GFP_KERNEL); | ||
1335 | if (pmem == NULL) { | ||
1336 | printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", | ||
1337 | __FILE__, __LINE__); | ||
1338 | return -ENOMEM; | ||
1339 | } | ||
1340 | memset(pmem, 0, numBytes); | ||
1341 | pdata = (int *) pmem; | ||
1342 | |||
1343 | /* Get number of devices | ||
1344 | */ | ||
1345 | if ((sh = ioc->sh) != NULL) { | ||
1346 | |||
1347 | max_id = sh->max_id - 1; | ||
1348 | hd = (MPT_SCSI_HOST *) sh->hostdata; | ||
1349 | |||
1350 | /* Check all of the target structures. | ||
1351 | * Save the Id and increment the counter, | ||
1352 | * if ptr non-null. | ||
1353 | * sh->max_id = maximum target ID + 1 | ||
1354 | */ | ||
1355 | if (hd && hd->Targets) { | ||
1356 | mpt_findImVolumes(ioc); | ||
1357 | pIoc2 = ioc->spi_data.pIocPg2; | ||
1358 | for ( id = 0; id <= max_id; ) { | ||
1359 | if ( pIoc2 && pIoc2->NumActiveVolumes ) { | ||
1360 | if ( id == pIoc2->RaidVolume[0].VolumeID ) { | ||
1361 | if (maxWordsLeft <= 0) { | ||
1362 | printk(KERN_ERR "mptctl_gettargetinfo - " | ||
1363 | "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices); | ||
1364 | goto data_space_full; | ||
1365 | } | ||
1366 | if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 ) | ||
1367 | devType = 0x80; | ||
1368 | else | ||
1369 | devType = 0xC0; | ||
1370 | bus_id = pIoc2->RaidVolume[0].VolumeBus; | ||
1371 | numDevices++; | ||
1372 | *pdata = ( (devType << 24) | (bus_id << 8) | id ); | ||
1373 | dctlprintk((KERN_ERR "mptctl_gettargetinfo - " | ||
1374 | "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); | ||
1375 | pdata++; | ||
1376 | --maxWordsLeft; | ||
1377 | goto next_id; | ||
1378 | } else { | ||
1379 | pIoc3 = ioc->spi_data.pIocPg3; | ||
1380 | for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) { | ||
1381 | if ( pIoc3->PhysDisk[jj].PhysDiskID == id ) | ||
1382 | goto next_id; | ||
1383 | } | ||
1384 | } | ||
1385 | } | ||
1386 | if ( (vdev = hd->Targets[id]) ) { | ||
1387 | for (jj = 0; jj <= MPT_LAST_LUN; jj++) { | ||
1388 | lun_index = (jj >> 5); | ||
1389 | indexed_lun = (jj % 32); | ||
1390 | lun = (1 << indexed_lun); | ||
1391 | if (vdev->luns[lun_index] & lun) { | ||
1392 | if (maxWordsLeft <= 0) { | ||
1393 | printk(KERN_ERR "mptctl_gettargetinfo - " | ||
1394 | "buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices); | ||
1395 | goto data_space_full; | ||
1396 | } | ||
1397 | bus_id = vdev->bus_id; | ||
1398 | numDevices++; | ||
1399 | *pdata = ( (jj << 16) | (bus_id << 8) | id ); | ||
1400 | dctlprintk((KERN_ERR "mptctl_gettargetinfo - " | ||
1401 | "target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); | ||
1402 | pdata++; | ||
1403 | --maxWordsLeft; | ||
1404 | } | ||
1405 | } | ||
1406 | } | ||
1407 | next_id: | ||
1408 | id++; | ||
1409 | } | ||
1410 | } | ||
1411 | } | ||
1412 | data_space_full: | ||
1413 | karg.numDevices = numDevices; | ||
1414 | |||
1415 | /* Copy part of the data from kernel memory to user memory | ||
1416 | */ | ||
1417 | if (copy_to_user((char __user *)arg, &karg, | ||
1418 | sizeof(struct mpt_ioctl_targetinfo))) { | ||
1419 | printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " | ||
1420 | "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", | ||
1421 | __FILE__, __LINE__, uarg); | ||
1422 | kfree(pmem); | ||
1423 | return -EFAULT; | ||
1424 | } | ||
1425 | |||
1426 | /* Copy the remaining data from kernel memory to user memory | ||
1427 | */ | ||
1428 | if (copy_to_user(uarg->targetInfo, pmem, numBytes)) { | ||
1429 | printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " | ||
1430 | "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", | ||
1431 | __FILE__, __LINE__, pdata); | ||
1432 | kfree(pmem); | ||
1433 | return -EFAULT; | ||
1434 | } | ||
1435 | |||
1436 | kfree(pmem); | ||
1437 | |||
1438 | return 0; | ||
1439 | } | ||
1440 | |||
1441 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1442 | /* MPT IOCTL Test function. | ||
1443 | * | ||
1444 | * Outputs: None. | ||
1445 | * Return: 0 if successful | ||
1446 | * -EFAULT if data unavailable | ||
1447 | * -ENODEV if no such device/adapter | ||
1448 | */ | ||
1449 | static int | ||
1450 | mptctl_readtest (unsigned long arg) | ||
1451 | { | ||
1452 | struct mpt_ioctl_test __user *uarg = (void __user *) arg; | ||
1453 | struct mpt_ioctl_test karg; | ||
1454 | MPT_ADAPTER *ioc; | ||
1455 | int iocnum; | ||
1456 | |||
1457 | dctlprintk(("mptctl_readtest called.\n")); | ||
1458 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { | ||
1459 | printk(KERN_ERR "%s@%d::mptctl_readtest - " | ||
1460 | "Unable to read in mpt_ioctl_test struct @ %p\n", | ||
1461 | __FILE__, __LINE__, uarg); | ||
1462 | return -EFAULT; | ||
1463 | } | ||
1464 | |||
1465 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1466 | (ioc == NULL)) { | ||
1467 | dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", | ||
1468 | __FILE__, __LINE__, iocnum)); | ||
1469 | return -ENODEV; | ||
1470 | } | ||
1471 | |||
1472 | /* Fill in the data and return the structure to the calling | ||
1473 | * program | ||
1474 | */ | ||
1475 | |||
1476 | #ifdef MFCNT | ||
1477 | karg.chip_type = ioc->mfcnt; | ||
1478 | #else | ||
1479 | karg.chip_type = ioc->pcidev->device; | ||
1480 | #endif | ||
1481 | strncpy (karg.name, ioc->name, MPT_MAX_NAME); | ||
1482 | karg.name[MPT_MAX_NAME-1]='\0'; | ||
1483 | strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); | ||
1484 | karg.product[MPT_PRODUCT_LENGTH-1]='\0'; | ||
1485 | |||
1486 | /* Copy the data from kernel memory to user memory | ||
1487 | */ | ||
1488 | if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) { | ||
1489 | printk(KERN_ERR "%s@%d::mptctl_readtest - " | ||
1490 | "Unable to write out mpt_ioctl_test struct @ %p\n", | ||
1491 | __FILE__, __LINE__, uarg); | ||
1492 | return -EFAULT; | ||
1493 | } | ||
1494 | |||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1499 | /* | ||
1500 | * mptctl_eventquery - Query the host adapter for the event types | ||
1501 | * that are being logged. | ||
1502 | * @arg: User space argument | ||
1503 | * | ||
1504 | * Outputs: None. | ||
1505 | * Return: 0 if successful | ||
1506 | * -EFAULT if data unavailable | ||
1507 | * -ENODEV if no such device/adapter | ||
1508 | */ | ||
1509 | static int | ||
1510 | mptctl_eventquery (unsigned long arg) | ||
1511 | { | ||
1512 | struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg; | ||
1513 | struct mpt_ioctl_eventquery karg; | ||
1514 | MPT_ADAPTER *ioc; | ||
1515 | int iocnum; | ||
1516 | |||
1517 | dctlprintk(("mptctl_eventquery called.\n")); | ||
1518 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { | ||
1519 | printk(KERN_ERR "%s@%d::mptctl_eventquery - " | ||
1520 | "Unable to read in mpt_ioctl_eventquery struct @ %p\n", | ||
1521 | __FILE__, __LINE__, uarg); | ||
1522 | return -EFAULT; | ||
1523 | } | ||
1524 | |||
1525 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1526 | (ioc == NULL)) { | ||
1527 | dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", | ||
1528 | __FILE__, __LINE__, iocnum)); | ||
1529 | return -ENODEV; | ||
1530 | } | ||
1531 | |||
1532 | karg.eventEntries = ioc->eventLogSize; | ||
1533 | karg.eventTypes = ioc->eventTypes; | ||
1534 | |||
1535 | /* Copy the data from kernel memory to user memory | ||
1536 | */ | ||
1537 | if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) { | ||
1538 | printk(KERN_ERR "%s@%d::mptctl_eventquery - " | ||
1539 | "Unable to write out mpt_ioctl_eventquery struct @ %p\n", | ||
1540 | __FILE__, __LINE__, uarg); | ||
1541 | return -EFAULT; | ||
1542 | } | ||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1547 | static int | ||
1548 | mptctl_eventenable (unsigned long arg) | ||
1549 | { | ||
1550 | struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg; | ||
1551 | struct mpt_ioctl_eventenable karg; | ||
1552 | MPT_ADAPTER *ioc; | ||
1553 | int iocnum; | ||
1554 | |||
1555 | dctlprintk(("mptctl_eventenable called.\n")); | ||
1556 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { | ||
1557 | printk(KERN_ERR "%s@%d::mptctl_eventenable - " | ||
1558 | "Unable to read in mpt_ioctl_eventenable struct @ %p\n", | ||
1559 | __FILE__, __LINE__, uarg); | ||
1560 | return -EFAULT; | ||
1561 | } | ||
1562 | |||
1563 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1564 | (ioc == NULL)) { | ||
1565 | dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", | ||
1566 | __FILE__, __LINE__, iocnum)); | ||
1567 | return -ENODEV; | ||
1568 | } | ||
1569 | |||
1570 | if (ioc->events == NULL) { | ||
1571 | /* Have not yet allocated memory - do so now. | ||
1572 | */ | ||
1573 | int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); | ||
1574 | ioc->events = kmalloc(sz, GFP_KERNEL); | ||
1575 | if (ioc->events == NULL) { | ||
1576 | printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); | ||
1577 | return -ENOMEM; | ||
1578 | } | ||
1579 | memset(ioc->events, 0, sz); | ||
1580 | ioc->alloc_total += sz; | ||
1581 | |||
1582 | ioc->eventLogSize = MPTCTL_EVENT_LOG_SIZE; | ||
1583 | ioc->eventContext = 0; | ||
1584 | } | ||
1585 | |||
1586 | /* Update the IOC event logging flag. | ||
1587 | */ | ||
1588 | ioc->eventTypes = karg.eventTypes; | ||
1589 | |||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1594 | static int | ||
1595 | mptctl_eventreport (unsigned long arg) | ||
1596 | { | ||
1597 | struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg; | ||
1598 | struct mpt_ioctl_eventreport karg; | ||
1599 | MPT_ADAPTER *ioc; | ||
1600 | int iocnum; | ||
1601 | int numBytes, maxEvents, max; | ||
1602 | |||
1603 | dctlprintk(("mptctl_eventreport called.\n")); | ||
1604 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { | ||
1605 | printk(KERN_ERR "%s@%d::mptctl_eventreport - " | ||
1606 | "Unable to read in mpt_ioctl_eventreport struct @ %p\n", | ||
1607 | __FILE__, __LINE__, uarg); | ||
1608 | return -EFAULT; | ||
1609 | } | ||
1610 | |||
1611 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1612 | (ioc == NULL)) { | ||
1613 | dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", | ||
1614 | __FILE__, __LINE__, iocnum)); | ||
1615 | return -ENODEV; | ||
1616 | } | ||
1617 | |||
1618 | numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); | ||
1619 | maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS); | ||
1620 | |||
1621 | |||
1622 | max = ioc->eventLogSize < maxEvents ? ioc->eventLogSize : maxEvents; | ||
1623 | |||
1624 | /* If fewer than 1 event is requested, there must have | ||
1625 | * been some type of error. | ||
1626 | */ | ||
1627 | if ((max < 1) || !ioc->events) | ||
1628 | return -ENODATA; | ||
1629 | |||
1630 | /* Copy the data from kernel memory to user memory | ||
1631 | */ | ||
1632 | numBytes = max * sizeof(MPT_IOCTL_EVENTS); | ||
1633 | if (copy_to_user(uarg->eventData, ioc->events, numBytes)) { | ||
1634 | printk(KERN_ERR "%s@%d::mptctl_eventreport - " | ||
1635 | "Unable to write out mpt_ioctl_eventreport struct @ %p\n", | ||
1636 | __FILE__, __LINE__, ioc->events); | ||
1637 | return -EFAULT; | ||
1638 | } | ||
1639 | |||
1640 | return 0; | ||
1641 | } | ||
1642 | |||
1643 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1644 | static int | ||
1645 | mptctl_replace_fw (unsigned long arg) | ||
1646 | { | ||
1647 | struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg; | ||
1648 | struct mpt_ioctl_replace_fw karg; | ||
1649 | MPT_ADAPTER *ioc; | ||
1650 | int iocnum; | ||
1651 | int newFwSize; | ||
1652 | |||
1653 | dctlprintk(("mptctl_replace_fw called.\n")); | ||
1654 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { | ||
1655 | printk(KERN_ERR "%s@%d::mptctl_replace_fw - " | ||
1656 | "Unable to read in mpt_ioctl_replace_fw struct @ %p\n", | ||
1657 | __FILE__, __LINE__, uarg); | ||
1658 | return -EFAULT; | ||
1659 | } | ||
1660 | |||
1661 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1662 | (ioc == NULL)) { | ||
1663 | dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", | ||
1664 | __FILE__, __LINE__, iocnum)); | ||
1665 | return -ENODEV; | ||
1666 | } | ||
1667 | |||
1668 | /* If caching FW, Free the old FW image | ||
1669 | */ | ||
1670 | if (ioc->cached_fw == NULL) | ||
1671 | return 0; | ||
1672 | |||
1673 | mpt_free_fw_memory(ioc); | ||
1674 | |||
1675 | /* Allocate memory for the new FW image | ||
1676 | */ | ||
1677 | newFwSize = karg.newImageSize; | ||
1678 | |||
1679 | if (newFwSize & 0x01) | ||
1680 | newFwSize += 1; | ||
1681 | if (newFwSize & 0x02) | ||
1682 | newFwSize += 2; | ||
1683 | |||
1684 | mpt_alloc_fw_memory(ioc, newFwSize); | ||
1685 | if (ioc->cached_fw == NULL) | ||
1686 | return -ENOMEM; | ||
1687 | |||
1688 | /* Copy the data from user memory to kernel space | ||
1689 | */ | ||
1690 | if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) { | ||
1691 | printk(KERN_ERR "%s@%d::mptctl_replace_fw - " | ||
1692 | "Unable to read in mpt_ioctl_replace_fw image " | ||
1693 | "@ %p\n", __FILE__, __LINE__, uarg); | ||
1694 | mpt_free_fw_memory(ioc); | ||
1695 | return -EFAULT; | ||
1696 | } | ||
1697 | |||
1698 | /* Update IOCFactsReply | ||
1699 | */ | ||
1700 | ioc->facts.FWImageSize = newFwSize; | ||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1705 | /* MPT IOCTL MPTCOMMAND function. | ||
1706 | * Cast the arg into the mpt_ioctl_mpt_command structure. | ||
1707 | * | ||
1708 | * Outputs: None. | ||
1709 | * Return: 0 if successful | ||
1710 | * -EBUSY if previous command timout and IOC reset is not complete. | ||
1711 | * -EFAULT if data unavailable | ||
1712 | * -ENODEV if no such device/adapter | ||
1713 | * -ETIME if timer expires | ||
1714 | * -ENOMEM if memory allocation error | ||
1715 | */ | ||
1716 | static int | ||
1717 | mptctl_mpt_command (unsigned long arg) | ||
1718 | { | ||
1719 | struct mpt_ioctl_command __user *uarg = (void __user *) arg; | ||
1720 | struct mpt_ioctl_command karg; | ||
1721 | MPT_ADAPTER *ioc; | ||
1722 | int iocnum; | ||
1723 | int rc; | ||
1724 | |||
1725 | dctlprintk(("mptctl_command called.\n")); | ||
1726 | |||
1727 | if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) { | ||
1728 | printk(KERN_ERR "%s@%d::mptctl_mpt_command - " | ||
1729 | "Unable to read in mpt_ioctl_command struct @ %p\n", | ||
1730 | __FILE__, __LINE__, uarg); | ||
1731 | return -EFAULT; | ||
1732 | } | ||
1733 | |||
1734 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1735 | (ioc == NULL)) { | ||
1736 | dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", | ||
1737 | __FILE__, __LINE__, iocnum)); | ||
1738 | return -ENODEV; | ||
1739 | } | ||
1740 | |||
1741 | rc = mptctl_do_mpt_command (karg, &uarg->MF); | ||
1742 | |||
1743 | return rc; | ||
1744 | } | ||
1745 | |||
1746 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1747 | /* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands. | ||
1748 | * | ||
1749 | * Outputs: None. | ||
1750 | * Return: 0 if successful | ||
1751 | * -EBUSY if previous command timout and IOC reset is not complete. | ||
1752 | * -EFAULT if data unavailable | ||
1753 | * -ENODEV if no such device/adapter | ||
1754 | * -ETIME if timer expires | ||
1755 | * -ENOMEM if memory allocation error | ||
1756 | * -EPERM if SCSI I/O and target is untagged | ||
1757 | */ | ||
1758 | static int | ||
1759 | mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) | ||
1760 | { | ||
1761 | MPT_ADAPTER *ioc; | ||
1762 | MPT_FRAME_HDR *mf = NULL; | ||
1763 | MPIHeader_t *hdr; | ||
1764 | char *psge; | ||
1765 | struct buflist bufIn; /* data In buffer */ | ||
1766 | struct buflist bufOut; /* data Out buffer */ | ||
1767 | dma_addr_t dma_addr_in; | ||
1768 | dma_addr_t dma_addr_out; | ||
1769 | int sgSize = 0; /* Num SG elements */ | ||
1770 | int iocnum, flagsLength; | ||
1771 | int sz, rc = 0; | ||
1772 | int msgContext; | ||
1773 | u16 req_idx; | ||
1774 | ulong timeout; | ||
1775 | |||
1776 | dctlprintk(("mptctl_do_mpt_command called.\n")); | ||
1777 | bufIn.kptr = bufOut.kptr = NULL; | ||
1778 | |||
1779 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
1780 | (ioc == NULL)) { | ||
1781 | dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", | ||
1782 | __FILE__, __LINE__, iocnum)); | ||
1783 | return -ENODEV; | ||
1784 | } | ||
1785 | if (!ioc->ioctl) { | ||
1786 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1787 | "No memory available during driver init.\n", | ||
1788 | __FILE__, __LINE__); | ||
1789 | return -ENOMEM; | ||
1790 | } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { | ||
1791 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1792 | "Busy with IOC Reset \n", __FILE__, __LINE__); | ||
1793 | return -EBUSY; | ||
1794 | } | ||
1795 | |||
1796 | /* Verify that the final request frame will not be too large. | ||
1797 | */ | ||
1798 | sz = karg.dataSgeOffset * 4; | ||
1799 | if (karg.dataInSize > 0) | ||
1800 | sz += sizeof(dma_addr_t) + sizeof(u32); | ||
1801 | if (karg.dataOutSize > 0) | ||
1802 | sz += sizeof(dma_addr_t) + sizeof(u32); | ||
1803 | |||
1804 | if (sz > ioc->req_sz) { | ||
1805 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1806 | "Request frame too large (%d) maximum (%d)\n", | ||
1807 | __FILE__, __LINE__, sz, ioc->req_sz); | ||
1808 | return -EFAULT; | ||
1809 | } | ||
1810 | |||
1811 | /* Get a free request frame and save the message context. | ||
1812 | */ | ||
1813 | if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) | ||
1814 | return -EAGAIN; | ||
1815 | |||
1816 | hdr = (MPIHeader_t *) mf; | ||
1817 | msgContext = le32_to_cpu(hdr->MsgContext); | ||
1818 | req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); | ||
1819 | |||
1820 | /* Copy the request frame | ||
1821 | * Reset the saved message context. | ||
1822 | * Request frame in user space | ||
1823 | */ | ||
1824 | if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) { | ||
1825 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1826 | "Unable to read MF from mpt_ioctl_command struct @ %p\n", | ||
1827 | __FILE__, __LINE__, mfPtr); | ||
1828 | rc = -EFAULT; | ||
1829 | goto done_free_mem; | ||
1830 | } | ||
1831 | hdr->MsgContext = cpu_to_le32(msgContext); | ||
1832 | |||
1833 | |||
1834 | /* Verify that this request is allowed. | ||
1835 | */ | ||
1836 | switch (hdr->Function) { | ||
1837 | case MPI_FUNCTION_IOC_FACTS: | ||
1838 | case MPI_FUNCTION_PORT_FACTS: | ||
1839 | karg.dataOutSize = karg.dataInSize = 0; | ||
1840 | break; | ||
1841 | |||
1842 | case MPI_FUNCTION_CONFIG: | ||
1843 | case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: | ||
1844 | case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: | ||
1845 | case MPI_FUNCTION_FW_UPLOAD: | ||
1846 | case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: | ||
1847 | case MPI_FUNCTION_FW_DOWNLOAD: | ||
1848 | case MPI_FUNCTION_FC_PRIMITIVE_SEND: | ||
1849 | break; | ||
1850 | |||
1851 | case MPI_FUNCTION_SCSI_IO_REQUEST: | ||
1852 | if (ioc->sh) { | ||
1853 | SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; | ||
1854 | VirtDevice *pTarget = NULL; | ||
1855 | MPT_SCSI_HOST *hd = NULL; | ||
1856 | int qtag = MPI_SCSIIO_CONTROL_UNTAGGED; | ||
1857 | int scsidir = 0; | ||
1858 | int target = (int) pScsiReq->TargetID; | ||
1859 | int dataSize; | ||
1860 | |||
1861 | if ((target < 0) || (target >= ioc->sh->max_id)) { | ||
1862 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1863 | "Target ID out of bounds. \n", | ||
1864 | __FILE__, __LINE__); | ||
1865 | rc = -ENODEV; | ||
1866 | goto done_free_mem; | ||
1867 | } | ||
1868 | |||
1869 | pScsiReq->MsgFlags = mpt_msg_flags(); | ||
1870 | |||
1871 | /* verify that app has not requested | ||
1872 | * more sense data than driver | ||
1873 | * can provide, if so, reset this parameter | ||
1874 | * set the sense buffer pointer low address | ||
1875 | * update the control field to specify Q type | ||
1876 | */ | ||
1877 | if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) | ||
1878 | pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; | ||
1879 | else | ||
1880 | pScsiReq->SenseBufferLength = karg.maxSenseBytes; | ||
1881 | |||
1882 | pScsiReq->SenseBufferLowAddr = | ||
1883 | cpu_to_le32(ioc->sense_buf_low_dma | ||
1884 | + (req_idx * MPT_SENSE_BUFFER_ALLOC)); | ||
1885 | |||
1886 | if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { | ||
1887 | if (hd->Targets) | ||
1888 | pTarget = hd->Targets[target]; | ||
1889 | } | ||
1890 | |||
1891 | if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) | ||
1892 | qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; | ||
1893 | |||
1894 | /* Have the IOCTL driver set the direction based | ||
1895 | * on the dataOutSize (ordering issue with Sparc). | ||
1896 | */ | ||
1897 | if (karg.dataOutSize > 0) { | ||
1898 | scsidir = MPI_SCSIIO_CONTROL_WRITE; | ||
1899 | dataSize = karg.dataOutSize; | ||
1900 | } else { | ||
1901 | scsidir = MPI_SCSIIO_CONTROL_READ; | ||
1902 | dataSize = karg.dataInSize; | ||
1903 | } | ||
1904 | |||
1905 | pScsiReq->Control = cpu_to_le32(scsidir | qtag); | ||
1906 | pScsiReq->DataLength = cpu_to_le32(dataSize); | ||
1907 | |||
1908 | ioc->ioctl->reset = MPTCTL_RESET_OK; | ||
1909 | ioc->ioctl->target = target; | ||
1910 | |||
1911 | } else { | ||
1912 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1913 | "SCSI driver is not loaded. \n", | ||
1914 | __FILE__, __LINE__); | ||
1915 | rc = -EFAULT; | ||
1916 | goto done_free_mem; | ||
1917 | } | ||
1918 | break; | ||
1919 | |||
1920 | case MPI_FUNCTION_RAID_ACTION: | ||
1921 | /* Just add a SGE | ||
1922 | */ | ||
1923 | break; | ||
1924 | |||
1925 | case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: | ||
1926 | if (ioc->sh) { | ||
1927 | SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; | ||
1928 | int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; | ||
1929 | int scsidir = MPI_SCSIIO_CONTROL_READ; | ||
1930 | int dataSize; | ||
1931 | |||
1932 | pScsiReq->MsgFlags = mpt_msg_flags(); | ||
1933 | |||
1934 | /* verify that app has not requested | ||
1935 | * more sense data than driver | ||
1936 | * can provide, if so, reset this parameter | ||
1937 | * set the sense buffer pointer low address | ||
1938 | * update the control field to specify Q type | ||
1939 | */ | ||
1940 | if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) | ||
1941 | pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; | ||
1942 | else | ||
1943 | pScsiReq->SenseBufferLength = karg.maxSenseBytes; | ||
1944 | |||
1945 | pScsiReq->SenseBufferLowAddr = | ||
1946 | cpu_to_le32(ioc->sense_buf_low_dma | ||
1947 | + (req_idx * MPT_SENSE_BUFFER_ALLOC)); | ||
1948 | |||
1949 | /* All commands to physical devices are tagged | ||
1950 | */ | ||
1951 | |||
1952 | /* Have the IOCTL driver set the direction based | ||
1953 | * on the dataOutSize (ordering issue with Sparc). | ||
1954 | */ | ||
1955 | if (karg.dataOutSize > 0) { | ||
1956 | scsidir = MPI_SCSIIO_CONTROL_WRITE; | ||
1957 | dataSize = karg.dataOutSize; | ||
1958 | } else { | ||
1959 | scsidir = MPI_SCSIIO_CONTROL_READ; | ||
1960 | dataSize = karg.dataInSize; | ||
1961 | } | ||
1962 | |||
1963 | pScsiReq->Control = cpu_to_le32(scsidir | qtag); | ||
1964 | pScsiReq->DataLength = cpu_to_le32(dataSize); | ||
1965 | |||
1966 | ioc->ioctl->reset = MPTCTL_RESET_OK; | ||
1967 | ioc->ioctl->target = pScsiReq->TargetID; | ||
1968 | } else { | ||
1969 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1970 | "SCSI driver is not loaded. \n", | ||
1971 | __FILE__, __LINE__); | ||
1972 | rc = -EFAULT; | ||
1973 | goto done_free_mem; | ||
1974 | } | ||
1975 | break; | ||
1976 | |||
1977 | case MPI_FUNCTION_SCSI_TASK_MGMT: | ||
1978 | { | ||
1979 | MPT_SCSI_HOST *hd = NULL; | ||
1980 | if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) { | ||
1981 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
1982 | "SCSI driver not loaded or SCSI host not found. \n", | ||
1983 | __FILE__, __LINE__); | ||
1984 | rc = -EFAULT; | ||
1985 | goto done_free_mem; | ||
1986 | } else if (mptctl_set_tm_flags(hd) != 0) { | ||
1987 | rc = -EPERM; | ||
1988 | goto done_free_mem; | ||
1989 | } | ||
1990 | } | ||
1991 | break; | ||
1992 | |||
1993 | case MPI_FUNCTION_IOC_INIT: | ||
1994 | { | ||
1995 | IOCInit_t *pInit = (IOCInit_t *) mf; | ||
1996 | u32 high_addr, sense_high; | ||
1997 | |||
1998 | /* Verify that all entries in the IOC INIT match | ||
1999 | * existing setup (and in LE format). | ||
2000 | */ | ||
2001 | if (sizeof(dma_addr_t) == sizeof(u64)) { | ||
2002 | high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); | ||
2003 | sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); | ||
2004 | } else { | ||
2005 | high_addr = 0; | ||
2006 | sense_high= 0; | ||
2007 | } | ||
2008 | |||
2009 | if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) || | ||
2010 | (pInit->MaxBuses != ioc->facts.MaxBuses) || | ||
2011 | (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) || | ||
2012 | (pInit->HostMfaHighAddr != high_addr) || | ||
2013 | (pInit->SenseBufferHighAddr != sense_high)) { | ||
2014 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
2015 | "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n", | ||
2016 | __FILE__, __LINE__); | ||
2017 | rc = -EFAULT; | ||
2018 | goto done_free_mem; | ||
2019 | } | ||
2020 | } | ||
2021 | break; | ||
2022 | default: | ||
2023 | /* | ||
2024 | * MPI_FUNCTION_PORT_ENABLE | ||
2025 | * MPI_FUNCTION_TARGET_CMD_BUFFER_POST | ||
2026 | * MPI_FUNCTION_TARGET_ASSIST | ||
2027 | * MPI_FUNCTION_TARGET_STATUS_SEND | ||
2028 | * MPI_FUNCTION_TARGET_MODE_ABORT | ||
2029 | * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET | ||
2030 | * MPI_FUNCTION_IO_UNIT_RESET | ||
2031 | * MPI_FUNCTION_HANDSHAKE | ||
2032 | * MPI_FUNCTION_REPLY_FRAME_REMOVAL | ||
2033 | * MPI_FUNCTION_EVENT_NOTIFICATION | ||
2034 | * (driver handles event notification) | ||
2035 | * MPI_FUNCTION_EVENT_ACK | ||
2036 | */ | ||
2037 | |||
2038 | /* What to do with these??? CHECK ME!!! | ||
2039 | MPI_FUNCTION_FC_LINK_SRVC_BUF_POST | ||
2040 | MPI_FUNCTION_FC_LINK_SRVC_RSP | ||
2041 | MPI_FUNCTION_FC_ABORT | ||
2042 | MPI_FUNCTION_LAN_SEND | ||
2043 | MPI_FUNCTION_LAN_RECEIVE | ||
2044 | MPI_FUNCTION_LAN_RESET | ||
2045 | */ | ||
2046 | |||
2047 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
2048 | "Illegal request (function 0x%x) \n", | ||
2049 | __FILE__, __LINE__, hdr->Function); | ||
2050 | rc = -EFAULT; | ||
2051 | goto done_free_mem; | ||
2052 | } | ||
2053 | |||
2054 | /* Add the SGL ( at most one data in SGE and one data out SGE ) | ||
2055 | * In the case of two SGE's - the data out (write) will always | ||
2056 | * preceede the data in (read) SGE. psgList is used to free the | ||
2057 | * allocated memory. | ||
2058 | */ | ||
2059 | psge = (char *) (((int *) mf) + karg.dataSgeOffset); | ||
2060 | flagsLength = 0; | ||
2061 | |||
2062 | /* bufIn and bufOut are used for user to kernel space transfers | ||
2063 | */ | ||
2064 | bufIn.kptr = bufOut.kptr = NULL; | ||
2065 | bufIn.len = bufOut.len = 0; | ||
2066 | |||
2067 | if (karg.dataOutSize > 0) | ||
2068 | sgSize ++; | ||
2069 | |||
2070 | if (karg.dataInSize > 0) | ||
2071 | sgSize ++; | ||
2072 | |||
2073 | if (sgSize > 0) { | ||
2074 | |||
2075 | /* Set up the dataOut memory allocation */ | ||
2076 | if (karg.dataOutSize > 0) { | ||
2077 | if (karg.dataInSize > 0) { | ||
2078 | flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | | ||
2079 | MPI_SGE_FLAGS_END_OF_BUFFER | | ||
2080 | MPI_SGE_FLAGS_DIRECTION | | ||
2081 | mpt_addr_size() ) | ||
2082 | << MPI_SGE_FLAGS_SHIFT; | ||
2083 | } else { | ||
2084 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; | ||
2085 | } | ||
2086 | flagsLength |= karg.dataOutSize; | ||
2087 | bufOut.len = karg.dataOutSize; | ||
2088 | bufOut.kptr = pci_alloc_consistent( | ||
2089 | ioc->pcidev, bufOut.len, &dma_addr_out); | ||
2090 | |||
2091 | if (bufOut.kptr == NULL) { | ||
2092 | rc = -ENOMEM; | ||
2093 | goto done_free_mem; | ||
2094 | } else { | ||
2095 | /* Set up this SGE. | ||
2096 | * Copy to MF and to sglbuf | ||
2097 | */ | ||
2098 | mpt_add_sge(psge, flagsLength, dma_addr_out); | ||
2099 | psge += (sizeof(u32) + sizeof(dma_addr_t)); | ||
2100 | |||
2101 | /* Copy user data to kernel space. | ||
2102 | */ | ||
2103 | if (copy_from_user(bufOut.kptr, | ||
2104 | karg.dataOutBufPtr, | ||
2105 | bufOut.len)) { | ||
2106 | printk(KERN_ERR | ||
2107 | "%s@%d::mptctl_do_mpt_command - Unable " | ||
2108 | "to read user data " | ||
2109 | "struct @ %p\n", | ||
2110 | __FILE__, __LINE__,karg.dataOutBufPtr); | ||
2111 | rc = -EFAULT; | ||
2112 | goto done_free_mem; | ||
2113 | } | ||
2114 | } | ||
2115 | } | ||
2116 | |||
2117 | if (karg.dataInSize > 0) { | ||
2118 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; | ||
2119 | flagsLength |= karg.dataInSize; | ||
2120 | |||
2121 | bufIn.len = karg.dataInSize; | ||
2122 | bufIn.kptr = pci_alloc_consistent(ioc->pcidev, | ||
2123 | bufIn.len, &dma_addr_in); | ||
2124 | |||
2125 | if (bufIn.kptr == NULL) { | ||
2126 | rc = -ENOMEM; | ||
2127 | goto done_free_mem; | ||
2128 | } else { | ||
2129 | /* Set up this SGE | ||
2130 | * Copy to MF and to sglbuf | ||
2131 | */ | ||
2132 | mpt_add_sge(psge, flagsLength, dma_addr_in); | ||
2133 | } | ||
2134 | } | ||
2135 | } else { | ||
2136 | /* Add a NULL SGE | ||
2137 | */ | ||
2138 | mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); | ||
2139 | } | ||
2140 | |||
2141 | ioc->ioctl->wait_done = 0; | ||
2142 | if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { | ||
2143 | |||
2144 | DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); | ||
2145 | |||
2146 | if (mpt_send_handshake_request(mptctl_id, ioc, | ||
2147 | sizeof(SCSITaskMgmt_t), (u32*)mf, | ||
2148 | CAN_SLEEP) != 0) { | ||
2149 | dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" | ||
2150 | " (ioc %p, mf %p) \n", ioc->name, | ||
2151 | ioc, mf)); | ||
2152 | mptctl_free_tm_flags(ioc); | ||
2153 | rc = -ENODATA; | ||
2154 | goto done_free_mem; | ||
2155 | } | ||
2156 | |||
2157 | } else | ||
2158 | mpt_put_msg_frame(mptctl_id, ioc, mf); | ||
2159 | |||
2160 | /* Now wait for the command to complete */ | ||
2161 | timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; | ||
2162 | timeout = wait_event_interruptible_timeout(mptctl_wait, | ||
2163 | ioc->ioctl->wait_done == 1, | ||
2164 | HZ*timeout); | ||
2165 | |||
2166 | if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) { | ||
2167 | /* Now we need to reset the board */ | ||
2168 | |||
2169 | if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) | ||
2170 | mptctl_free_tm_flags(ioc); | ||
2171 | |||
2172 | mptctl_timeout_expired(ioc->ioctl); | ||
2173 | rc = -ENODATA; | ||
2174 | goto done_free_mem; | ||
2175 | } | ||
2176 | |||
2177 | mf = NULL; | ||
2178 | |||
2179 | /* If a valid reply frame, copy to the user. | ||
2180 | * Offset 2: reply length in U32's | ||
2181 | */ | ||
2182 | if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { | ||
2183 | if (karg.maxReplyBytes < ioc->reply_sz) { | ||
2184 | sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); | ||
2185 | } else { | ||
2186 | sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); | ||
2187 | } | ||
2188 | |||
2189 | if (sz > 0) { | ||
2190 | if (copy_to_user(karg.replyFrameBufPtr, | ||
2191 | &ioc->ioctl->ReplyFrame, sz)){ | ||
2192 | printk(KERN_ERR | ||
2193 | "%s@%d::mptctl_do_mpt_command - " | ||
2194 | "Unable to write out reply frame %p\n", | ||
2195 | __FILE__, __LINE__, karg.replyFrameBufPtr); | ||
2196 | rc = -ENODATA; | ||
2197 | goto done_free_mem; | ||
2198 | } | ||
2199 | } | ||
2200 | } | ||
2201 | |||
2202 | /* If valid sense data, copy to user. | ||
2203 | */ | ||
2204 | if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { | ||
2205 | sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); | ||
2206 | if (sz > 0) { | ||
2207 | if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { | ||
2208 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
2209 | "Unable to write sense data to user %p\n", | ||
2210 | __FILE__, __LINE__, | ||
2211 | karg.senseDataPtr); | ||
2212 | rc = -ENODATA; | ||
2213 | goto done_free_mem; | ||
2214 | } | ||
2215 | } | ||
2216 | } | ||
2217 | |||
2218 | /* If the overall status is _GOOD and data in, copy data | ||
2219 | * to user. | ||
2220 | */ | ||
2221 | if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && | ||
2222 | (karg.dataInSize > 0) && (bufIn.kptr)) { | ||
2223 | |||
2224 | if (copy_to_user(karg.dataInBufPtr, | ||
2225 | bufIn.kptr, karg.dataInSize)) { | ||
2226 | printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " | ||
2227 | "Unable to write data to user %p\n", | ||
2228 | __FILE__, __LINE__, | ||
2229 | karg.dataInBufPtr); | ||
2230 | rc = -ENODATA; | ||
2231 | } | ||
2232 | } | ||
2233 | |||
2234 | done_free_mem: | ||
2235 | |||
2236 | ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD | | ||
2237 | MPT_IOCTL_STATUS_SENSE_VALID | | ||
2238 | MPT_IOCTL_STATUS_RF_VALID ); | ||
2239 | |||
2240 | /* Free the allocated memory. | ||
2241 | */ | ||
2242 | if (bufOut.kptr != NULL) { | ||
2243 | pci_free_consistent(ioc->pcidev, | ||
2244 | bufOut.len, (void *) bufOut.kptr, dma_addr_out); | ||
2245 | } | ||
2246 | |||
2247 | if (bufIn.kptr != NULL) { | ||
2248 | pci_free_consistent(ioc->pcidev, | ||
2249 | bufIn.len, (void *) bufIn.kptr, dma_addr_in); | ||
2250 | } | ||
2251 | |||
2252 | /* mf is null if command issued successfully | ||
2253 | * otherwise, failure occured after mf acquired. | ||
2254 | */ | ||
2255 | if (mf) | ||
2256 | mpt_free_msg_frame(ioc, mf); | ||
2257 | |||
2258 | return rc; | ||
2259 | } | ||
2260 | |||
2261 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2262 | /* Prototype Routine for the HP HOST INFO command. | ||
2263 | * | ||
2264 | * Outputs: None. | ||
2265 | * Return: 0 if successful | ||
2266 | * -EFAULT if data unavailable | ||
2267 | * -EBUSY if previous command timout and IOC reset is not complete. | ||
2268 | * -ENODEV if no such device/adapter | ||
2269 | * -ETIME if timer expires | ||
2270 | * -ENOMEM if memory allocation error | ||
2271 | */ | ||
2272 | static int | ||
2273 | mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) | ||
2274 | { | ||
2275 | hp_host_info_t __user *uarg = (void __user *) arg; | ||
2276 | MPT_ADAPTER *ioc; | ||
2277 | struct pci_dev *pdev; | ||
2278 | char *pbuf; | ||
2279 | dma_addr_t buf_dma; | ||
2280 | hp_host_info_t karg; | ||
2281 | CONFIGPARMS cfg; | ||
2282 | ConfigPageHeader_t hdr; | ||
2283 | int iocnum; | ||
2284 | int rc, cim_rev; | ||
2285 | |||
2286 | dctlprintk((": mptctl_hp_hostinfo called.\n")); | ||
2287 | /* Reset long to int. Should affect IA64 and SPARC only | ||
2288 | */ | ||
2289 | if (data_size == sizeof(hp_host_info_t)) | ||
2290 | cim_rev = 1; | ||
2291 | else if (data_size == sizeof(hp_host_info_rev0_t)) | ||
2292 | cim_rev = 0; /* obsolete */ | ||
2293 | else | ||
2294 | return -EFAULT; | ||
2295 | |||
2296 | if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) { | ||
2297 | printk(KERN_ERR "%s@%d::mptctl_hp_host_info - " | ||
2298 | "Unable to read in hp_host_info struct @ %p\n", | ||
2299 | __FILE__, __LINE__, uarg); | ||
2300 | return -EFAULT; | ||
2301 | } | ||
2302 | |||
2303 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
2304 | (ioc == NULL)) { | ||
2305 | dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", | ||
2306 | __FILE__, __LINE__, iocnum)); | ||
2307 | return -ENODEV; | ||
2308 | } | ||
2309 | |||
2310 | /* Fill in the data and return the structure to the calling | ||
2311 | * program | ||
2312 | */ | ||
2313 | pdev = (struct pci_dev *) ioc->pcidev; | ||
2314 | |||
2315 | karg.vendor = pdev->vendor; | ||
2316 | karg.device = pdev->device; | ||
2317 | karg.subsystem_id = pdev->subsystem_device; | ||
2318 | karg.subsystem_vendor = pdev->subsystem_vendor; | ||
2319 | karg.devfn = pdev->devfn; | ||
2320 | karg.bus = pdev->bus->number; | ||
2321 | |||
2322 | /* Save the SCSI host no. if | ||
2323 | * SCSI driver loaded | ||
2324 | */ | ||
2325 | if (ioc->sh != NULL) | ||
2326 | karg.host_no = ioc->sh->host_no; | ||
2327 | else | ||
2328 | karg.host_no = -1; | ||
2329 | |||
2330 | /* Reformat the fw_version into a string | ||
2331 | */ | ||
2332 | karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ? | ||
2333 | ((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0'; | ||
2334 | karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0'; | ||
2335 | karg.fw_version[2] = '.'; | ||
2336 | karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ? | ||
2337 | ((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0'; | ||
2338 | karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0'; | ||
2339 | karg.fw_version[5] = '.'; | ||
2340 | karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ? | ||
2341 | ((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0'; | ||
2342 | karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0'; | ||
2343 | karg.fw_version[8] = '.'; | ||
2344 | karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ? | ||
2345 | ((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0'; | ||
2346 | karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0'; | ||
2347 | karg.fw_version[11] = '\0'; | ||
2348 | |||
2349 | /* Issue a config request to get the device serial number | ||
2350 | */ | ||
2351 | hdr.PageVersion = 0; | ||
2352 | hdr.PageLength = 0; | ||
2353 | hdr.PageNumber = 0; | ||
2354 | hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; | ||
2355 | cfg.hdr = &hdr; | ||
2356 | cfg.physAddr = -1; | ||
2357 | cfg.pageAddr = 0; | ||
2358 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
2359 | cfg.dir = 0; /* read */ | ||
2360 | cfg.timeout = 10; | ||
2361 | |||
2362 | strncpy(karg.serial_number, " ", 24); | ||
2363 | if (mpt_config(ioc, &cfg) == 0) { | ||
2364 | if (cfg.hdr->PageLength > 0) { | ||
2365 | /* Issue the second config page request */ | ||
2366 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
2367 | |||
2368 | pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); | ||
2369 | if (pbuf) { | ||
2370 | cfg.physAddr = buf_dma; | ||
2371 | if (mpt_config(ioc, &cfg) == 0) { | ||
2372 | ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; | ||
2373 | if (strlen(pdata->BoardTracerNumber) > 1) { | ||
2374 | strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); | ||
2375 | karg.serial_number[24-1]='\0'; | ||
2376 | } | ||
2377 | } | ||
2378 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); | ||
2379 | pbuf = NULL; | ||
2380 | } | ||
2381 | } | ||
2382 | } | ||
2383 | rc = mpt_GetIocState(ioc, 1); | ||
2384 | switch (rc) { | ||
2385 | case MPI_IOC_STATE_OPERATIONAL: | ||
2386 | karg.ioc_status = HP_STATUS_OK; | ||
2387 | break; | ||
2388 | |||
2389 | case MPI_IOC_STATE_FAULT: | ||
2390 | karg.ioc_status = HP_STATUS_FAILED; | ||
2391 | break; | ||
2392 | |||
2393 | case MPI_IOC_STATE_RESET: | ||
2394 | case MPI_IOC_STATE_READY: | ||
2395 | default: | ||
2396 | karg.ioc_status = HP_STATUS_OTHER; | ||
2397 | break; | ||
2398 | } | ||
2399 | |||
2400 | karg.base_io_addr = pci_resource_start(pdev, 0); | ||
2401 | |||
2402 | if (ioc->bus_type == FC) | ||
2403 | karg.bus_phys_width = HP_BUS_WIDTH_UNK; | ||
2404 | else | ||
2405 | karg.bus_phys_width = HP_BUS_WIDTH_16; | ||
2406 | |||
2407 | karg.hard_resets = 0; | ||
2408 | karg.soft_resets = 0; | ||
2409 | karg.timeouts = 0; | ||
2410 | if (ioc->sh != NULL) { | ||
2411 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; | ||
2412 | |||
2413 | if (hd && (cim_rev == 1)) { | ||
2414 | karg.hard_resets = hd->hard_resets; | ||
2415 | karg.soft_resets = hd->soft_resets; | ||
2416 | karg.timeouts = hd->timeouts; | ||
2417 | } | ||
2418 | } | ||
2419 | |||
2420 | cfg.pageAddr = 0; | ||
2421 | cfg.action = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; | ||
2422 | cfg.dir = MPI_TB_ISTWI_FLAGS_READ; | ||
2423 | cfg.timeout = 10; | ||
2424 | pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); | ||
2425 | if (pbuf) { | ||
2426 | cfg.physAddr = buf_dma; | ||
2427 | if ((mpt_toolbox(ioc, &cfg)) == 0) { | ||
2428 | karg.rsvd = *(u32 *)pbuf; | ||
2429 | } | ||
2430 | pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); | ||
2431 | pbuf = NULL; | ||
2432 | } | ||
2433 | |||
2434 | /* Copy the data from kernel memory to user memory | ||
2435 | */ | ||
2436 | if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) { | ||
2437 | printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - " | ||
2438 | "Unable to write out hp_host_info @ %p\n", | ||
2439 | __FILE__, __LINE__, uarg); | ||
2440 | return -EFAULT; | ||
2441 | } | ||
2442 | |||
2443 | return 0; | ||
2444 | |||
2445 | } | ||
2446 | |||
2447 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2448 | /* Prototype Routine for the HP TARGET INFO command. | ||
2449 | * | ||
2450 | * Outputs: None. | ||
2451 | * Return: 0 if successful | ||
2452 | * -EFAULT if data unavailable | ||
2453 | * -EBUSY if previous command timout and IOC reset is not complete. | ||
2454 | * -ENODEV if no such device/adapter | ||
2455 | * -ETIME if timer expires | ||
2456 | * -ENOMEM if memory allocation error | ||
2457 | */ | ||
2458 | static int | ||
2459 | mptctl_hp_targetinfo(unsigned long arg) | ||
2460 | { | ||
2461 | hp_target_info_t __user *uarg = (void __user *) arg; | ||
2462 | SCSIDevicePage0_t *pg0_alloc; | ||
2463 | SCSIDevicePage3_t *pg3_alloc; | ||
2464 | MPT_ADAPTER *ioc; | ||
2465 | MPT_SCSI_HOST *hd = NULL; | ||
2466 | hp_target_info_t karg; | ||
2467 | int iocnum; | ||
2468 | int data_sz; | ||
2469 | dma_addr_t page_dma; | ||
2470 | CONFIGPARMS cfg; | ||
2471 | ConfigPageHeader_t hdr; | ||
2472 | int tmp, np, rc = 0; | ||
2473 | |||
2474 | dctlprintk((": mptctl_hp_targetinfo called.\n")); | ||
2475 | if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) { | ||
2476 | printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - " | ||
2477 | "Unable to read in hp_host_targetinfo struct @ %p\n", | ||
2478 | __FILE__, __LINE__, uarg); | ||
2479 | return -EFAULT; | ||
2480 | } | ||
2481 | |||
2482 | if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || | ||
2483 | (ioc == NULL)) { | ||
2484 | dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", | ||
2485 | __FILE__, __LINE__, iocnum)); | ||
2486 | return -ENODEV; | ||
2487 | } | ||
2488 | |||
2489 | /* There is nothing to do for FCP parts. | ||
2490 | */ | ||
2491 | if (ioc->bus_type == FC) | ||
2492 | return 0; | ||
2493 | |||
2494 | if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL)) | ||
2495 | return 0; | ||
2496 | |||
2497 | if (ioc->sh->host_no != karg.hdr.host) | ||
2498 | return -ENODEV; | ||
2499 | |||
2500 | /* Get the data transfer speeds | ||
2501 | */ | ||
2502 | data_sz = ioc->spi_data.sdp0length * 4; | ||
2503 | pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma); | ||
2504 | if (pg0_alloc) { | ||
2505 | hdr.PageVersion = ioc->spi_data.sdp0version; | ||
2506 | hdr.PageLength = data_sz; | ||
2507 | hdr.PageNumber = 0; | ||
2508 | hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | ||
2509 | |||
2510 | cfg.hdr = &hdr; | ||
2511 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
2512 | cfg.dir = 0; | ||
2513 | cfg.timeout = 0; | ||
2514 | cfg.physAddr = page_dma; | ||
2515 | |||
2516 | cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id; | ||
2517 | |||
2518 | if ((rc = mpt_config(ioc, &cfg)) == 0) { | ||
2519 | np = le32_to_cpu(pg0_alloc->NegotiatedParameters); | ||
2520 | karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ? | ||
2521 | HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8; | ||
2522 | |||
2523 | if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) { | ||
2524 | tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8; | ||
2525 | if (tmp < 0x09) | ||
2526 | karg.negotiated_speed = HP_DEV_SPEED_ULTRA320; | ||
2527 | else if (tmp <= 0x09) | ||
2528 | karg.negotiated_speed = HP_DEV_SPEED_ULTRA160; | ||
2529 | else if (tmp <= 0x0A) | ||
2530 | karg.negotiated_speed = HP_DEV_SPEED_ULTRA2; | ||
2531 | else if (tmp <= 0x0C) | ||
2532 | karg.negotiated_speed = HP_DEV_SPEED_ULTRA; | ||
2533 | else if (tmp <= 0x25) | ||
2534 | karg.negotiated_speed = HP_DEV_SPEED_FAST; | ||
2535 | else | ||
2536 | karg.negotiated_speed = HP_DEV_SPEED_ASYNC; | ||
2537 | } else | ||
2538 | karg.negotiated_speed = HP_DEV_SPEED_ASYNC; | ||
2539 | } | ||
2540 | |||
2541 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma); | ||
2542 | } | ||
2543 | |||
2544 | /* Set defaults | ||
2545 | */ | ||
2546 | karg.message_rejects = -1; | ||
2547 | karg.phase_errors = -1; | ||
2548 | karg.parity_errors = -1; | ||
2549 | karg.select_timeouts = -1; | ||
2550 | |||
2551 | /* Get the target error parameters | ||
2552 | */ | ||
2553 | hdr.PageVersion = 0; | ||
2554 | hdr.PageLength = 0; | ||
2555 | hdr.PageNumber = 3; | ||
2556 | hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | ||
2557 | |||
2558 | cfg.hdr = &hdr; | ||
2559 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
2560 | cfg.dir = 0; | ||
2561 | cfg.timeout = 0; | ||
2562 | cfg.physAddr = -1; | ||
2563 | if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) { | ||
2564 | /* Issue the second config page request */ | ||
2565 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
2566 | data_sz = (int) cfg.hdr->PageLength * 4; | ||
2567 | pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent( | ||
2568 | ioc->pcidev, data_sz, &page_dma); | ||
2569 | if (pg3_alloc) { | ||
2570 | cfg.physAddr = page_dma; | ||
2571 | cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id; | ||
2572 | if ((rc = mpt_config(ioc, &cfg)) == 0) { | ||
2573 | karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount); | ||
2574 | karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount); | ||
2575 | karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount); | ||
2576 | } | ||
2577 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma); | ||
2578 | } | ||
2579 | } | ||
2580 | hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; | ||
2581 | if (hd != NULL) | ||
2582 | karg.select_timeouts = hd->sel_timeout[karg.hdr.id]; | ||
2583 | |||
2584 | /* Copy the data from kernel memory to user memory | ||
2585 | */ | ||
2586 | if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) { | ||
2587 | printk(KERN_ERR "%s@%d::mptctl_hp_target_info - " | ||
2588 | "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", | ||
2589 | __FILE__, __LINE__, uarg); | ||
2590 | return -EFAULT; | ||
2591 | } | ||
2592 | |||
2593 | return 0; | ||
2594 | } | ||
2595 | |||
2596 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2597 | |||
2598 | static struct file_operations mptctl_fops = { | ||
2599 | .owner = THIS_MODULE, | ||
2600 | .llseek = no_llseek, | ||
2601 | .unlocked_ioctl = mptctl_ioctl, | ||
2602 | #ifdef CONFIG_COMPAT | ||
2603 | .compat_ioctl = compat_mpctl_ioctl, | ||
2604 | #endif | ||
2605 | }; | ||
2606 | |||
2607 | static struct miscdevice mptctl_miscdev = { | ||
2608 | MPT_MINOR, | ||
2609 | MYNAM, | ||
2610 | &mptctl_fops | ||
2611 | }; | ||
2612 | |||
2613 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2614 | |||
2615 | #ifdef CONFIG_COMPAT | ||
2616 | |||
2617 | #include <linux/ioctl32.h> | ||
2618 | |||
2619 | static int | ||
2620 | compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, | ||
2621 | unsigned long arg) | ||
2622 | { | ||
2623 | struct mpt_fw_xfer32 kfw32; | ||
2624 | struct mpt_fw_xfer kfw; | ||
2625 | MPT_ADAPTER *iocp = NULL; | ||
2626 | int iocnum, iocnumX; | ||
2627 | int nonblock = (filp->f_flags & O_NONBLOCK); | ||
2628 | int ret; | ||
2629 | |||
2630 | dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n")); | ||
2631 | |||
2632 | if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32))) | ||
2633 | return -EFAULT; | ||
2634 | |||
2635 | /* Verify intended MPT adapter */ | ||
2636 | iocnumX = kfw32.iocnum & 0xFF; | ||
2637 | if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || | ||
2638 | (iocp == NULL)) { | ||
2639 | dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", | ||
2640 | __LINE__, iocnumX)); | ||
2641 | return -ENODEV; | ||
2642 | } | ||
2643 | |||
2644 | if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) | ||
2645 | return ret; | ||
2646 | |||
2647 | kfw.iocnum = iocnum; | ||
2648 | kfw.fwlen = kfw32.fwlen; | ||
2649 | kfw.bufp = compat_ptr(kfw32.bufp); | ||
2650 | |||
2651 | ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); | ||
2652 | |||
2653 | up(&iocp->ioctl->sem_ioc); | ||
2654 | |||
2655 | return ret; | ||
2656 | } | ||
2657 | |||
2658 | static int | ||
2659 | compat_mpt_command(struct file *filp, unsigned int cmd, | ||
2660 | unsigned long arg) | ||
2661 | { | ||
2662 | struct mpt_ioctl_command32 karg32; | ||
2663 | struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg; | ||
2664 | struct mpt_ioctl_command karg; | ||
2665 | MPT_ADAPTER *iocp = NULL; | ||
2666 | int iocnum, iocnumX; | ||
2667 | int nonblock = (filp->f_flags & O_NONBLOCK); | ||
2668 | int ret; | ||
2669 | |||
2670 | dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n")); | ||
2671 | |||
2672 | if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) | ||
2673 | return -EFAULT; | ||
2674 | |||
2675 | /* Verify intended MPT adapter */ | ||
2676 | iocnumX = karg32.hdr.iocnum & 0xFF; | ||
2677 | if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || | ||
2678 | (iocp == NULL)) { | ||
2679 | dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", | ||
2680 | __LINE__, iocnumX)); | ||
2681 | return -ENODEV; | ||
2682 | } | ||
2683 | |||
2684 | if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) | ||
2685 | return ret; | ||
2686 | |||
2687 | /* Copy data to karg */ | ||
2688 | karg.hdr.iocnum = karg32.hdr.iocnum; | ||
2689 | karg.hdr.port = karg32.hdr.port; | ||
2690 | karg.timeout = karg32.timeout; | ||
2691 | karg.maxReplyBytes = karg32.maxReplyBytes; | ||
2692 | |||
2693 | karg.dataInSize = karg32.dataInSize; | ||
2694 | karg.dataOutSize = karg32.dataOutSize; | ||
2695 | karg.maxSenseBytes = karg32.maxSenseBytes; | ||
2696 | karg.dataSgeOffset = karg32.dataSgeOffset; | ||
2697 | |||
2698 | karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr; | ||
2699 | karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr; | ||
2700 | karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr; | ||
2701 | karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr; | ||
2702 | |||
2703 | /* Pass new structure to do_mpt_command | ||
2704 | */ | ||
2705 | ret = mptctl_do_mpt_command (karg, &uarg->MF); | ||
2706 | |||
2707 | up(&iocp->ioctl->sem_ioc); | ||
2708 | |||
2709 | return ret; | ||
2710 | } | ||
2711 | |||
2712 | static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
2713 | { | ||
2714 | long ret; | ||
2715 | lock_kernel(); | ||
2716 | switch (cmd) { | ||
2717 | case MPTIOCINFO: | ||
2718 | case MPTIOCINFO1: | ||
2719 | case MPTIOCINFO2: | ||
2720 | case MPTTARGETINFO: | ||
2721 | case MPTEVENTQUERY: | ||
2722 | case MPTEVENTENABLE: | ||
2723 | case MPTEVENTREPORT: | ||
2724 | case MPTHARDRESET: | ||
2725 | case HP_GETHOSTINFO: | ||
2726 | case HP_GETTARGETINFO: | ||
2727 | case MPTTEST: | ||
2728 | ret = __mptctl_ioctl(f, cmd, arg); | ||
2729 | break; | ||
2730 | case MPTCOMMAND32: | ||
2731 | ret = compat_mpt_command(f, cmd, arg); | ||
2732 | break; | ||
2733 | case MPTFWDOWNLOAD32: | ||
2734 | ret = compat_mptfwxfer_ioctl(f, cmd, arg); | ||
2735 | break; | ||
2736 | default: | ||
2737 | ret = -ENOIOCTLCMD; | ||
2738 | break; | ||
2739 | } | ||
2740 | unlock_kernel(); | ||
2741 | return ret; | ||
2742 | } | ||
2743 | |||
2744 | #endif | ||
2745 | |||
2746 | |||
2747 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2748 | /* | ||
2749 | * mptctl_probe - Installs ioctl devices per bus. | ||
2750 | * @pdev: Pointer to pci_dev structure | ||
2751 | * | ||
2752 | * Returns 0 for success, non-zero for failure. | ||
2753 | * | ||
2754 | */ | ||
2755 | |||
2756 | static int | ||
2757 | mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
2758 | { | ||
2759 | int err; | ||
2760 | int sz; | ||
2761 | u8 *mem; | ||
2762 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | ||
2763 | |||
2764 | /* | ||
2765 | * Allocate and inite a MPT_IOCTL structure | ||
2766 | */ | ||
2767 | sz = sizeof (MPT_IOCTL); | ||
2768 | mem = kmalloc(sz, GFP_KERNEL); | ||
2769 | if (mem == NULL) { | ||
2770 | err = -ENOMEM; | ||
2771 | goto out_fail; | ||
2772 | } | ||
2773 | |||
2774 | memset(mem, 0, sz); | ||
2775 | ioc->ioctl = (MPT_IOCTL *) mem; | ||
2776 | ioc->ioctl->ioc = ioc; | ||
2777 | sema_init(&ioc->ioctl->sem_ioc, 1); | ||
2778 | return 0; | ||
2779 | |||
2780 | out_fail: | ||
2781 | |||
2782 | mptctl_remove(pdev); | ||
2783 | return err; | ||
2784 | } | ||
2785 | |||
2786 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2787 | /* | ||
2788 | * mptctl_remove - Removed ioctl devices | ||
2789 | * @pdev: Pointer to pci_dev structure | ||
2790 | * | ||
2791 | * | ||
2792 | */ | ||
2793 | static void | ||
2794 | mptctl_remove(struct pci_dev *pdev) | ||
2795 | { | ||
2796 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | ||
2797 | |||
2798 | kfree ( ioc->ioctl ); | ||
2799 | } | ||
2800 | |||
2801 | static struct mpt_pci_driver mptctl_driver = { | ||
2802 | .probe = mptctl_probe, | ||
2803 | .remove = mptctl_remove, | ||
2804 | }; | ||
2805 | |||
2806 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2807 | static int __init mptctl_init(void) | ||
2808 | { | ||
2809 | int err; | ||
2810 | int where = 1; | ||
2811 | |||
2812 | show_mptmod_ver(my_NAME, my_VERSION); | ||
2813 | |||
2814 | if(mpt_device_driver_register(&mptctl_driver, | ||
2815 | MPTCTL_DRIVER) != 0 ) { | ||
2816 | dprintk((KERN_INFO MYNAM | ||
2817 | ": failed to register dd callbacks\n")); | ||
2818 | } | ||
2819 | |||
2820 | /* Register this device */ | ||
2821 | err = misc_register(&mptctl_miscdev); | ||
2822 | if (err < 0) { | ||
2823 | printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR); | ||
2824 | goto out_fail; | ||
2825 | } | ||
2826 | printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n"); | ||
2827 | printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", | ||
2828 | mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); | ||
2829 | |||
2830 | /* | ||
2831 | * Install our handler | ||
2832 | */ | ||
2833 | ++where; | ||
2834 | if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { | ||
2835 | printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); | ||
2836 | misc_deregister(&mptctl_miscdev); | ||
2837 | err = -EBUSY; | ||
2838 | goto out_fail; | ||
2839 | } | ||
2840 | |||
2841 | if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) { | ||
2842 | dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); | ||
2843 | } else { | ||
2844 | /* FIXME! */ | ||
2845 | } | ||
2846 | |||
2847 | return 0; | ||
2848 | |||
2849 | out_fail: | ||
2850 | |||
2851 | mpt_device_driver_deregister(MPTCTL_DRIVER); | ||
2852 | |||
2853 | return err; | ||
2854 | } | ||
2855 | |||
2856 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2857 | static void mptctl_exit(void) | ||
2858 | { | ||
2859 | misc_deregister(&mptctl_miscdev); | ||
2860 | printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", | ||
2861 | mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); | ||
2862 | |||
2863 | /* De-register reset handler from base module */ | ||
2864 | mpt_reset_deregister(mptctl_id); | ||
2865 | dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); | ||
2866 | |||
2867 | /* De-register callback handler from base module */ | ||
2868 | mpt_deregister(mptctl_id); | ||
2869 | printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); | ||
2870 | |||
2871 | mpt_device_driver_deregister(MPTCTL_DRIVER); | ||
2872 | |||
2873 | } | ||
2874 | |||
2875 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
2876 | |||
2877 | module_init(mptctl_init); | ||
2878 | module_exit(mptctl_exit); | ||