File: /usr/src/linux/drivers/message/fusion/mptctl.c

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 huge debt of gratitude is owed to David S. Miller (DaveM)
13      *      for fixing much of the stupid and broken stuff in the early
14      *      driver while porting to sparc64 platform.  THANK YOU!
15      *
16      *      A big THANKS to Eddie C. Dost for fixing the ioctl path
17      *      and most importantly f/w download on sparc64 platform!
18      *      (plus Eddie's other helpful hints and insights)
19      *
20      *      Thanks to Arnaldo Carvalho de Melo for finding and patching
21      *      a potential memory leak in mpt_ioctl_do_fw_download(),
22      *      and for some kmalloc insight:-)
23      *
24      *      (see also mptbase.c)
25      *
26      *  Copyright (c) 1999-2001 LSI Logic Corporation
27      *  Originally By: Steven J. Ralston, Noah Romer
28      *  (mailto:Steve.Ralston@lsil.com)
29      *
30      *  $Id: mptctl.c,v 1.25.4.1 2001/08/24 20:07:06 sralston Exp $
31      */
32     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
33     /*
34         This program is free software; you can redistribute it and/or modify
35         it under the terms of the GNU General Public License as published by
36         the Free Software Foundation; version 2 of the License.
37     
38         This program is distributed in the hope that it will be useful,
39         but WITHOUT ANY WARRANTY; without even the implied warranty of
40         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41         GNU General Public License for more details.
42     
43         NO WARRANTY
44         THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
45         CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
46         LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
47         MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
48         solely responsible for determining the appropriateness of using and
49         distributing the Program and assumes all risks associated with its
50         exercise of rights under this Agreement, including but not limited to
51         the risks and costs of program errors, damage to or loss of data,
52         programs or equipment, and unavailability or interruption of operations.
53     
54         DISCLAIMER OF LIABILITY
55         NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
56         DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57         DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
58         ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
59         TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
60         USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
61         HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
62     
63         You should have received a copy of the GNU General Public License
64         along with this program; if not, write to the Free Software
65         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
66     */
67     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
68     
69     #include <linux/version.h>
70     #include <linux/kernel.h>
71     #include <linux/module.h>
72     #include <linux/errno.h>
73     #include <linux/init.h>
74     #include <linux/slab.h>
75     #include <linux/types.h>
76     #include <linux/pci.h>
77     #include <linux/miscdevice.h>
78     
79     #include <asm/io.h>
80     #include <asm/uaccess.h>
81     
82     #include <linux/proc_fs.h>
83     
84     #define COPYRIGHT	"Copyright (c) 1999-2001 LSI Logic Corporation"
85     #define MODULEAUTHOR	"Steven J. Ralston, Noah Romer"
86     #include "mptbase.h"
87     
88     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
89     #define my_NAME		"Fusion MPT misc device (ioctl) driver"
90     #define my_VERSION	MPT_LINUX_VERSION_COMMON
91     #define MYNAM		"mptctl"
92     
93     EXPORT_NO_SYMBOLS;
94     MODULE_AUTHOR(MODULEAUTHOR);
95     MODULE_DESCRIPTION(my_NAME);
96     
97     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
98     
99     static int mptctl_id = -1;
100     static int rwperf_reset = 0;
101     static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
102     
103     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
104     
105     static int mpt_ioctl_rwperf(unsigned long arg);
106     static int mpt_ioctl_rwperf_status(unsigned long arg);
107     static int mpt_ioctl_rwperf_reset(unsigned long arg);
108     static int mpt_ioctl_fw_download(unsigned long arg);
109     static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
110     static int mpt_ioctl_scsi_cmd(unsigned long arg);
111     
112     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
113     /*
114      * Scatter gather list (SGL) sizes and limits...
115      */
116     //#define MAX_SCSI_FRAGS	9
117     #define MAX_FRAGS_SPILL1	9
118     #define MAX_FRAGS_SPILL2	15
119     #define FRAGS_PER_BUCKET	(MAX_FRAGS_SPILL2 + 1)
120     
121     //#define MAX_CHAIN_FRAGS	64
122     //#define MAX_CHAIN_FRAGS	(15+15+15+16)
123     #define MAX_CHAIN_FRAGS		(4 * MAX_FRAGS_SPILL2 + 1)
124     
125     //  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
126     //  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8
127     //                  ^----------------- 80 + 512
128     #define MAX_SGL_BYTES		((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
129     
130     /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
131     #define MAX_KMALLOC_SZ		(128*1024)
132     
133     struct buflist {
134     	u8	*kptr;
135     	int	 len;
136     };
137     
138     #define myMAX_TARGETS	(1<<4)
139     #define myMAX_LUNS	(1<<3)
140     #define myMAX_T_MASK	(myMAX_TARGETS-1)
141     #define myMAX_L_MASK	(myMAX_LUNS-1)
142     static u8  DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
143     static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
144     
145     static u32 fwReplyBuffer[16];
146     static pMPIDefaultReply_t ReplyMsg = NULL;
147     
148     /* some private forw protos */
149     static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags,
150     		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
151     static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
152     		struct buflist *buflist, MPT_ADAPTER *ioc);
153     
154     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
155     /**
156      *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
157      *	@ioc: Pointer to MPT adapter
158      *	@nonblock: boolean, non-zero if O_NONBLOCK is set
159      *
160      *	All of the mptctl commands can potentially sleep, which is illegal
161      *	with a spinlock held, thus we perform mutual exclusion here.
162      *
163      *	Returns negative errno on error, or zero for success.
164      */
165     static inline int
166     mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
167     {
168     	dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
169     
170     	if (nonblock) {
171     		if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
172     			return -EAGAIN;
173     	} else {
174     		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
175     			return -ERESTARTSYS;
176     	}
177     	return 0;
178     }
179     
180     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
181     /*
182      *  This is the callback for any message we have posted. The message itself
183      *  will be returned to the message pool when we return from the IRQ
184      *
185      *  This runs in irq context so be short and sweet.
186      */
187     static int
188     mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
189     {
190     	u8 targ;
191     
192     	//dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n"));
193     
194     	if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
195     		targ = req->u.scsireq.TargetID & myMAX_T_MASK;
196     		DevIosCount[targ][0]--;
197     	} else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) {
198     		// NOTE: Expects/requires non-Turbo reply!
199     		dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n"));
200     		memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
201     		ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
202     	}
203     
204     	return 1;
205     }
206     
207     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
208     /*
209      *  struct file_operations functionality. 
210      *  Members:
211      *	llseek, write, read, ioctl, open, release
212      */
213     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
214     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
215     static loff_t
216     mptctl_llseek(struct file *file, loff_t offset, int origin)
217     {
218     	return -ESPIPE;
219     }
220     #define no_llseek mptctl_llseek
221     #endif
222     
223     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
224     static ssize_t
225     mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
226     {
227     	printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n");
228     	return 0;
229     }
230     
231     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
232     static ssize_t
233     mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
234     {
235     	return 0;
236     }
237     
238     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
239     /*
240      *  MPT ioctl handler
241      */
242     static int
243     mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
244     {
245     	struct mpt_ioctl_sanity	*usanity = (struct mpt_ioctl_sanity *) arg;
246     	struct mpt_ioctl_sanity	 ksanity;
247     	int iocnum;
248     	unsigned iocnumX;
249     	int nonblock = (file->f_flags & O_NONBLOCK);
250     	int ret;
251     	MPT_ADAPTER *iocp = NULL;
252     
253     	dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n"));
254     
255     	if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) {
256     		printk(KERN_ERR "%s::mpt_ioctl() @%d - "
257     				"Unable to copy mpt_ioctl_sanity data @ %p\n",
258     				__FILE__, __LINE__, (void*)usanity);
259     		return -EFAULT;
260     	}
261     	ret = -ENXIO;				/* (-6) No such device or address */
262     
263     	/* Verify intended MPT adapter */
264     	iocnumX = ksanity.iocnum & 0xFF;
265     	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
266     	    (iocp == NULL)) {
267     		printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
268     				__FILE__, __LINE__, iocnumX);
269     		return -ENODEV;
270     	}
271     
272     	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
273     		return ret;
274     
275     	dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
276     
277     	switch(cmd) {
278     	case MPTRWPERF:
279     		ret = mpt_ioctl_rwperf(arg);
280     		break;
281     	case MPTRWPERF_CHK:
282     		ret = mpt_ioctl_rwperf_status(arg);
283     		break;
284     	case MPTRWPERF_RESET:
285     		ret = mpt_ioctl_rwperf_reset(arg);
286     		break;
287     	case MPTFWDOWNLOAD:
288     		ret = mpt_ioctl_fw_download(arg);
289     		break;
290     	case MPTSCSICMD:
291     		ret = mpt_ioctl_scsi_cmd(arg);
292     		break;
293     	default:
294     		ret = -EINVAL;
295     	}
296     
297     	up(&mptctl_syscall_sem_ioc[iocp->id]);
298     
299     	return ret;
300     }
301     
302     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
303     static int mptctl_open(struct inode *inode, struct file *file)
304     {
305     	/*
306     	 * Should support multiple management users
307     	 */
308     	return 0;
309     }
310     
311     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
312     static int mptctl_release(struct inode *inode, struct file *file)
313     {
314     	return 0;
315     }
316     
317     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
318     static int
319     mpt_ioctl_fw_download(unsigned long arg)
320     {
321     	struct mpt_fw_xfer	*ufwdl = (struct mpt_fw_xfer *) arg;
322     	struct mpt_fw_xfer	 kfwdl;
323     
324     	dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
325     	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
326     		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
327     				"Unable to copy mpt_fw_xfer struct @ %p\n",
328     				__FILE__, __LINE__, (void*)ufwdl);
329     		return -EFAULT;
330     	}
331     
332     	return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
333     }
334     
335     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
336     /*
337      * MPT FW Download
338      */
339     static int
340     mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
341     {
342     	FWDownload_t		*dlmsg;
343     	MPT_FRAME_HDR		*mf;
344     	MPT_ADAPTER		*iocp;
345     //	char			*fwbuf;
346     //	dma_addr_t		 fwbuf_dma;
347     	FWDownloadTCSGE_t	*fwVoodoo;
348     //	SGEAllUnion_t		*fwSgl;
349     	int			 ret;
350     
351     	SGESimple32_t	*sgl;
352     	SGESimple32_t	*sgOut, *sgIn;
353     	dma_addr_t	 sgl_dma;
354     	struct buflist	*buflist = NULL;
355     	struct buflist	*bl = NULL;
356     	int		 numfrags = 0;
357     	int		 maxfrags;
358     	int		 n = 0;
359     	u32		 sgdir;
360     	u32		 nib;
361     	int		 fw_bytes_copied = 0;
362     	u16		 iocstat;
363     	int		 i;
364     
365     	dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
366     
367     	dprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
368     	dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
369     	dprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
370     
371     	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
372     		printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
373     				__FILE__, __LINE__, ioc);
374     		return -ENXIO; /* (-6) No such device or address */
375     	}
376     
377     	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
378     		return -EAGAIN;
379     	dlmsg = (FWDownload_t*) mf;
380     	fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL;
381     	sgOut = (SGESimple32_t *) (fwVoodoo + 1);
382     
383     	/*
384     	 * Construct f/w download request
385     	 */
386     	dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
387     	dlmsg->Reserved = 0;
388     	dlmsg->ChainOffset = 0;
389     	dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
390     	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
391     	dlmsg->MsgFlags = 0;
392     
393     	fwVoodoo->Reserved = 0;
394     	fwVoodoo->ContextSize = 0;
395     	fwVoodoo->DetailsLength = 12;
396     	fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
397     	fwVoodoo->Reserved1 = 0;
398     	fwVoodoo->ImageOffset = 0;
399     	fwVoodoo->ImageSize = cpu_to_le32(fwlen);
400     
401     	/*
402     	 * Need to kmalloc area(s) for holding firmware image bytes.
403     	 * But we need to do it piece meal, using a proper
404     	 * scatter gather list (with 128kB MAX hunks).
405     	 * 
406     	 * A practical limit here might be # of sg hunks that fit into
407     	 * a single IOC request frame; 12 or 8 (see below), so:
408     	 * For FC9xx: 12 x 128kB == 1.5 mB (max)
409     	 * For C1030:  8 x 128kB == 1   mB (max)
410     	 * We could support chaining, but things get ugly(ier:)
411     	 */
412     	sgdir = 0x04000000;		/* IOC will READ from sys mem */
413     	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
414     		return -ENOMEM;
415     
416     	/*
417     	 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
418     	 * for FC9xx f/w image, but calculate max number of sge hunks
419     	 * we can fit into a request frame, and limit ourselves to that.
420     	 * (currently no chain support)
421     	 * For FC9xx: (128-12-16)/8 = 12.5 = 12
422     	 * For C1030:  (96-12-16)/8 =  8.5 =  8
423     	 */
424     	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
425     	if (numfrags > maxfrags) {
426     		ret = -EMLINK;
427     		goto fwdl_out;
428     	}
429     
430     	dprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
431     
432     	/*
433     	 * Parse SG list, copying sgl itself,
434     	 * plus f/w image hunks from user space as we go...
435     	 */
436     	ret = -EFAULT;
437     	sgIn = sgl;
438     	bl = buflist;
439     	for (i=0; i < numfrags; i++) {
440     		nib = (le32_to_cpu(sgIn->FlagsLength) & 0xF0000000) >> 28;
441     		/* skip ignore/chain. */
442     		if (nib == 0 || nib == 3) {
443     			;
444     		} else if (sgIn->Address) {
445     			*sgOut = *sgIn;
446     			n++;
447     			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
448     				printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
449     						"Unable to copy f/w buffer hunk#%d @ %p\n",
450     						__FILE__, __LINE__, n, (void*)ufwbuf);
451     				goto fwdl_out;
452     			}
453     			fw_bytes_copied += bl->len;
454     		}
455     		sgIn++;
456     		bl++;
457     		sgOut++;
458     	}
459     
460     #ifdef MPT_DEBUG
461     	{
462     		u32 *m = (u32 *)mf;
463     		printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
464     		for (i=0; i < 7+numfrags*2; i++)
465     			printk(" %08x", le32_to_cpu(m[i]));
466     		printk("\n");
467     	}
468     #endif
469     
470     	/*
471     	 * Finally, perform firmware download.
472     	 */
473     	ReplyMsg = NULL;
474     	mpt_put_msg_frame(mptctl_id, ioc, mf);
475     
476     	/*
477     	 *  Wait until the reply has been received
478     	 */
479     	{
480     		int	 foo = 0;
481     
482     		while (ReplyMsg == NULL) {
483     			if (!(foo%1000000)) {
484     				dprintk((KERN_INFO "DbG::_do_fwdl: "
485     					   "In ReplyMsg loop - iteration %d\n",
486     					   foo)); //tc
487     			}
488     			ret = -ETIME;
489     			if (++foo > 60000000)
490     				goto fwdl_out;
491     			mb();
492     			schedule();
493     			barrier();
494     		}
495     	}
496     
497     	if (sgl)
498             	kfree_sgl(sgl, sgl_dma, buflist, iocp);
499     
500     	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
501     	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
502     		printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
503     		return 0;
504     	} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
505     		printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",
506     				iocp->name);
507     		printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
508     		return -EBADRQC;
509     	} else if (iocstat == MPI_IOCSTATUS_BUSY) {
510     		printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);
511     		printk(KERN_WARNING MYNAM ": (try again later?)\n");
512     		return -EBUSY;
513     	} else {
514     		printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",
515     				    iocp->name, iocstat);
516     		printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
517     		return -ENOMSG;
518     	}
519     	return 0;
520     
521     fwdl_out:
522             kfree_sgl(sgl, sgl_dma, buflist, iocp);
523     	return ret;
524     }
525     
526     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
527     /*
528      *  NEW rwperf (read/write performance) stuff starts here...
529      */
530     
531     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
532     static SGESimple32_t *
533     kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
534     		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
535     {
536     	SGESimple32_t	*sglbuf = NULL;
537     	struct buflist	*buflist = NULL;
538     	int		 numfrags = 0;
539     	int		 fragcnt = 0;
540     	int		 alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
541     	int		 bytes_allocd = 0;
542     	int		 this_alloc;
543     	SGESimple32_t	*sgl;
544     	u32		 pa;					// phys addr
545     	SGEChain32_t	*last_chain = NULL;
546     	SGEChain32_t	*old_chain = NULL;
547     	int		 chaincnt = 0;
548     	int		 i, buflist_ent;
549     	int		 sg_spill = MAX_FRAGS_SPILL1;
550     	int		 dir;
551     
552     	*frags = 0;
553     	*blp = NULL;
554     	i = MAX_SGL_BYTES / 8;
555     	buflist = kmalloc(i, GFP_USER);
556     	if (buflist == NULL)
557     		return NULL;
558     	memset(buflist, 0, i);
559     	buflist_ent = 0;
560     
561     	sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
562     	if (sglbuf == NULL)
563     		goto free_and_fail;
564     
565     	if (sgdir & 0x04000000)
566     		dir = PCI_DMA_TODEVICE;
567     	else
568     		dir = PCI_DMA_FROMDEVICE;
569     
570     	sgl = sglbuf;
571     	while (bytes_allocd < bytes) {
572     		this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
573     		buflist[buflist_ent].len = this_alloc;
574     		buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
575     								 this_alloc,
576     								 &pa);
577     		if (buflist[buflist_ent].kptr == NULL) {
578     			alloc_sz = alloc_sz / 2;
579     			if (alloc_sz == 0) {
580     				printk(KERN_WARNING MYNAM "-SG: No can do - "
581     						    "not enough memory!   :-(\n");
582     				printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
583     						    numfrags);
584     				goto free_and_fail;
585     			}
586     			continue;
587     		} else {
588     			dma_addr_t dma_addr;
589     
590     			bytes_allocd += this_alloc;
591     
592     			/* Write one SIMPLE sge */
593     			sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
594     			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
595     			sgl->Address = cpu_to_le32(dma_addr);
596     
597     			fragcnt++;
598     			numfrags++;
599     			sgl++;
600     			buflist_ent++;
601     		}
602     
603     		if (bytes_allocd >= bytes)
604     			break;
605     
606     		/* Need to chain? */
607     		if (fragcnt == sg_spill) {
608     			dma_addr_t chain_link;
609     
610     			if (last_chain != NULL)
611     				last_chain->NextChainOffset = 0x1E;
612     
613     			fragcnt = 0;
614     			sg_spill = MAX_FRAGS_SPILL2;
615     
616     			/* fixup previous SIMPLE sge */
617     			sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
618     
619     			chain_link = (*sglbuf_dma) +
620     				((u8 *)(sgl+1) - (u8 *)sglbuf);
621     
622     			/* Write one CHAIN sge */
623     			sgl->FlagsLength = cpu_to_le32(0x30000080);
624     			sgl->Address = cpu_to_le32(chain_link);
625     
626     			old_chain = last_chain;
627     			last_chain = (SGEChain32_t*)sgl;
628     			chaincnt++;
629     			numfrags++;
630     			sgl++;
631     		}
632     
633     		/* overflow check... */
634     		if (numfrags*8 > MAX_SGL_BYTES) {
635     			/* GRRRRR... */
636     			printk(KERN_WARNING MYNAM "-SG: No can do - "
637     					    "too many SG frags!   :-(\n");
638     			printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
639     					    numfrags);
640     			goto free_and_fail;
641     		}
642     	}
643     
644     	/* Last sge fixup: set LE+eol+eob bits */
645     	sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
646     
647     	/* Chain fixup needed? */
648     	if (last_chain != NULL && fragcnt < 16)
649     		last_chain->Length = cpu_to_le16(fragcnt * 8);
650     
651     	*frags = numfrags;
652     	*blp = buflist;
653     
654     	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
655     			   "%d SG frags generated!  (%d CHAIN%s)\n",
656     			   numfrags, chaincnt, chaincnt>1?"s":""));
657     
658     	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
659     			   "last (big) alloc_sz=%d\n",
660     			   alloc_sz));
661     
662     	return sglbuf;
663     
664     free_and_fail:
665     	if (sglbuf != NULL) {
666     		int i;
667     
668     		for (i = 0; i < numfrags; i++) {
669     			dma_addr_t dma_addr;
670     			u8 *kptr;
671     			int len;
672     
673     			if ((le32_to_cpu(sglbuf[i].FlagsLength) >> 24) == 0x30)
674     				continue;
675     
676     			dma_addr = le32_to_cpu(sglbuf[i].Address);
677     			kptr = buflist[i].kptr;
678     			len = buflist[i].len;
679     
680     			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
681     		}
682     		pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
683     	}
684     	kfree(buflist);
685     	return NULL;
686     }
687     
688     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
689     static void
690     kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
691     {
692     	SGESimple32_t	*sg = sgl;
693     	struct buflist	*bl = buflist;
694     	u32		 nib;
695     	int		 dir;
696     	int		 n = 0;
697     
698     	if (le32_to_cpu(sg->FlagsLength) & 0x04000000)
699     		dir = PCI_DMA_TODEVICE;
700     	else
701     		dir = PCI_DMA_FROMDEVICE;
702     
703     	nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
704     	while (! (nib & 0x4)) { /* eob */
705     		/* skip ignore/chain. */
706     		if (nib == 0 || nib == 3) {
707     			;
708     		} else if (sg->Address) {
709     			dma_addr_t dma_addr;
710     			void *kptr;
711     			int len;
712     
713     			dma_addr = le32_to_cpu(sg->Address);
714     			kptr = bl->kptr;
715     			len = bl->len;
716     			pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
717     			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
718     			n++;
719     		}
720     		sg++;
721     		bl++;
722     		nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
723     	}
724     
725     	/* we're at eob! */
726     	if (sg->Address) {
727     		dma_addr_t dma_addr;
728     		void *kptr;
729     		int len;
730     
731     		dma_addr = le32_to_cpu(sg->Address);
732     		kptr = bl->kptr;
733     		len = bl->len;
734     		pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
735     		pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
736     		n++;
737     	}
738     
739     	pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
740     	kfree(buflist);
741     	dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
742     }
743     
744     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
745     static int
746     mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
747     		      char *caller, MPT_ADAPTER **iocpp)
748     {
749     	char	*myname = "_rwperf_init()";
750     	int	 ioc;
751     
752     	/* get copy of structure passed from user space */
753     	if (copy_from_user(dest, (void*)src, sizeof(*dest))) {
754     		printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n",
755     				myname, __LINE__, (void*)src);
756     		return -EFAULT;				/* (-14) Bad address */
757     	} else {
758     		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}"
759     				   ": %d %d %d %d %d\n",
760     				   dest->iocnum, dest->target,
761     				   (int)dest->qdepth, dest->iters, dest->nblks ));
762     		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}"
763     				   ": %d %d %d %d %d\n",
764     				   dest->cache_sz, dest->skip, dest->range,
765     				   dest->rdwr, dest->seqran ));
766     
767     		/* Get the MPT adapter id. */
768     		if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) {
769     			printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n",
770     					myname, __LINE__, dest->iocnum);
771     			return -ENXIO;			/* (-6) No such device or address */
772     		} else {
773     			dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n",
774     					caller, dest->iocnum, dest->target));
775     		}
776     	}
777     
778     	return ioc;
779     }
780     
781     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
782     
783     /*  Treat first N blocks of disk as sacred!  */
784     #define SACRED_BLOCKS	100
785     
786     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
787     static int
788     mpt_ioctl_rwperf(unsigned long arg)
789     {
790     	struct mpt_raw_r_w	 kPerfInfo;
791     				/* NOTE: local copy, on stack==KERNEL_SPACE! */
792     	u8		 target, targetM;
793     	u8		 lun, lunM;
794     	u8		 scsiop;
795     	int		 qdepth;
796     	int		 iters;
797     	int		 cache_sz;
798     	u32		 xferbytes;
799     	u32		 scsidir;
800     	u32		 qtag;
801     	u32		 scsictl;
802     	u32		 sgdir;
803     	u32		 blkno;
804     	u32		 sbphys;
805     	SGESimple32_t	*sgl;
806     	dma_addr_t	 sgl_dma;
807     	struct buflist	*buflist;
808     	SGESimple32_t	*sgOut, *sgIn;
809     	int		 numfrags;
810     	u32		*msg;
811     	int		 i;
812     	int		 ioc;
813     	MPT_FRAME_HDR	*mf;
814     	MPT_ADAPTER	*iocp;
815     	int		 sgfragcpycnt;
816     	int		 blklo, blkhi;
817     	u8		 nextchainoffset;
818     	u8		*SenseBuf;
819     	dma_addr_t	 SenseBufDMA;
820     	char		*myname = "_rwperf()";
821     
822         dprintk((KERN_INFO "%s - starting...\n", myname));
823     
824         /* Validate target device */
825         if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
826             return ioc;
827     
828         /* Allocate DMA'able memory for the sense buffer. */
829         SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA);
830     
831         /* set perf parameters from input */
832         target = kPerfInfo.target & 0x0FF;
833         targetM = target & myMAX_T_MASK;
834         lun = kPerfInfo.lun & 0x1F;			// LUN=31 max
835         lunM = lun & myMAX_L_MASK;
836         qdepth = kPerfInfo.qdepth;
837         iters = kPerfInfo.iters;
838         xferbytes = ((u32)kPerfInfo.nblks)<<9;
839     
840         DevInUse[targetM][lunM] = 1;
841         DevIosCount[targetM][lunM] = 0;
842     
843         cache_sz = kPerfInfo.cache_sz * 1024;	// CacheSz in kB!
844     
845         /* ToDo: */
846         /* get capacity (?) */
847     
848     
849         // pre-build, one time, everything we can for speed in the loops below...
850     
851         scsiop = 0x28;				// default to SCSI READ!
852         scsidir = MPI_SCSIIO_CONTROL_READ;		// DATA IN  (host<--ioc<--dev)
853     						// 02000000
854         qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;		// 00000000
855     
856         if (xferbytes == 0) {
857             // Do 0-byte READ!!!
858             //  IMPORTANT!  Need to set no SCSI DIR for this!
859             scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
860         }
861     
862         scsictl = scsidir | qtag;
863     
864         /*
865          *  Set sgdir for DMA transfer.
866          */
867     //    sgdir   = 0x04000000;		// SCSI WRITE
868         sgdir = 0x00000000;			// SCSI READ
869     
870         if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
871             return -ENOMEM;
872     
873         sgfragcpycnt = MIN(10,numfrags);
874         nextchainoffset = 0;
875         if (numfrags > 10)
876             nextchainoffset = 0x1E;
877     
878         sbphys = SenseBufDMA;
879     
880         rwperf_reset = 0;
881     
882     //    do {	// target-loop
883     
884             blkno = SACRED_BLOCKS;		// Treat first N blocks as sacred!
885     					// FIXME!  Skip option
886             blklo = blkno;
887             blkhi = blkno;
888     
889             do {    // inner-loop
890     
891                 while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
892                     mb();
893                     schedule();
894                     barrier();
895                 }
896                 msg = (u32*)mf;
897     
898                 /* Start piecing the SCSIIORequest together */
899                 msg[0] = 0x00000000 | nextchainoffset<<16 | target;
900                 msg[1] = 0x0000FF0A;				// 255 sense bytes, 10-byte CDB!
901                 msg[3] = lun << 8;
902                 msg[4] = 0;
903                 msg[5] = scsictl;
904     
905                 // 16 bytes of CDB @ msg[6,7,8,9] are below...
906     
907                 msg[6] = (   ((blkno & 0xFF000000) >> 8)
908                            | ((blkno & 0x00FF0000) << 8)
909                            | scsiop );
910                 msg[7] = (   (((u32)kPerfInfo.nblks & 0x0000FF00) << 16)
911                            | ((blkno & 0x000000FF) << 8)
912                            | ((blkno & 0x0000FF00) >> 8) );
913                 msg[8] = (kPerfInfo.nblks & 0x00FF);
914                 msg[9] = 0;
915     
916                 msg[10] = xferbytes;
917     
918     //            msg[11] = 0xD0000100;
919     //            msg[12] = sbphys;
920     //            msg[13] = 0;
921                 msg[11] = sbphys;
922     
923                 // Copy the SGL...
924                 if (xferbytes) {
925                     sgOut = (SGESimple32_t*)&msg[12];
926                     sgIn  = sgl;
927                     for (i=0; i < sgfragcpycnt; i++)
928                         *sgOut++ = *sgIn++;
929                 }
930     
931                 // fubar!  QueueDepth issue!!!
932                 while (    !rwperf_reset
933                         && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) )
934                 {
935                     mb();
936                     schedule();
937                     barrier();
938                 }
939     
940     //            blkno += kPerfInfo.nblks;
941     // EXP Stuff!
942     // Try optimizing to certain cache size for the target!
943     // by keeping blkno within cache range if at all possible
944     #if 0
945                 if (    cache_sz
946                      && ((2 * kPerfInfo.nblks) <= (cache_sz>>9))
947                      && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
948                     blkno = SACRED_BLOCKS;
949                 else
950                     blkno += kPerfInfo.nblks;
951     #endif
952     // Ok, cheat!
953                 if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
954                        blkno = SACRED_BLOCKS;
955                 else
956                     blkno += kPerfInfo.nblks;
957     
958                 if (blkno > blkhi)
959                     blkhi = blkno;
960     
961                 DevIosCount[targetM][lunM]++;
962     
963                 /*
964                  *  Finally, post the request
965                  */
966                 mpt_put_msg_frame(mptctl_id, ioc, mf);
967     
968     
969                 /* let linux breath! */
970                 mb();
971                 schedule();
972                 barrier();
973     
974                 //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
975     
976             } while ((--iters > 0) && !rwperf_reset);
977     
978             dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
979             dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
980     
981     //        //  TEMPORARY!
982     //        target = 0;
983     
984     //    } while (target);
985     
986     
987         if (DevIosCount[targetM][lunM]) {
988             dprintk((KERN_INFO "  DbG: DevIosCount[%d][%d]=%d\n",
989                     targetM, lunM, DevIosCount[targetM][lunM]));
990         }
991     
992         while (DevIosCount[targetM][lunM]) {
993             //dprintk((KERN_DEBUG "  DbG: Waiting... DevIosCount[%d][%d]=%d\n",
994             //        targetM, lunM, DevIosCount[targetM][lunM]));
995             mb();
996             schedule();
997             barrier();
998         }
999         DevInUse[targetM][lunM] = 0;
1000     
1001         pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
1002     
1003         if (sgl)
1004             kfree_sgl(sgl, sgl_dma, buflist, iocp);
1005     
1006         dprintk((KERN_INFO "  *** done ***\n"));
1007     
1008         return 0;
1009     }
1010     
1011     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1012     static int
1013     mpt_ioctl_rwperf_status(unsigned long arg)
1014     {
1015     	struct mpt_raw_r_w	 kPerfInfo;
1016     				/* NOTE: local copy, on stack==KERNEL_SPACE! */
1017     	MPT_ADAPTER	*iocp;
1018     	int		 ioc;
1019     //	u8		 targ;
1020     //	u8		 lun;
1021     	int		 T, L;
1022     	char		*myname = "_rwperf_status()";
1023     
1024     
1025     	dprintk((KERN_INFO "%s - starting...\n", myname));
1026     
1027     	/* Get a pointer to the MPT adapter. */
1028     	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
1029     		return ioc;
1030     
1031     	/* set perf parameters from input */
1032     //	targ = kPerfInfo.target & 0xFF;
1033     //	lun = kPerfInfo.lun & 0x1F;
1034     
1035     	for (T=0; T < myMAX_TARGETS; T++)
1036     		for (L=0; L < myMAX_LUNS; L++)
1037     			if (DevIosCount[T][L]) {
1038     				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x"
1039     						 ", IosCnt=%d\n",
1040     						 myname, ioc, T, L, DevIosCount[T][L] );
1041     			}
1042     
1043     	return 0;
1044     }
1045     
1046     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1047     static int
1048     mpt_ioctl_rwperf_reset(unsigned long arg)
1049     {
1050     	struct mpt_raw_r_w	 kPerfInfo;
1051     				/* NOTE: local copy, on stack==KERNEL_SPACE! */
1052     	MPT_ADAPTER	*iocp;
1053     	int		 ioc;
1054     //	u8		 targ;
1055     //	u8		 lun;
1056     	int		 T, L;
1057     	int		 i;
1058     	char		*myname = "_rwperf_reset()";
1059     
1060     	dprintk((KERN_INFO "%s - starting...\n", myname));
1061     
1062     	/* Get MPT adapter id. */
1063     	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
1064     		return ioc;
1065     
1066     	/* set perf parameters from input */
1067     //	targ = kPerfInfo.target & 0xFF;
1068     //	lun = kPerfInfo.lun & 0x1F;
1069     
1070     	rwperf_reset = 1;
1071     	for (i=0; i < 1000000; i++) {
1072     		mb();
1073     		schedule();
1074     		barrier();
1075     	}
1076     	rwperf_reset = 0;
1077     
1078     	for (T=0; T < myMAX_TARGETS; T++)
1079     		for (L=0; L < myMAX_LUNS; L++)
1080     			if (DevIosCount[T][L]) {
1081     				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, "
1082     						 "IosCnt RESET! (from %d to 0)\n",
1083     						 myname, ioc, T, L, DevIosCount[T][L] );
1084     				DevIosCount[T][L] = 0;
1085     				DevInUse[T][L] = 0;
1086     			}
1087     
1088     	return 0;
1089     }
1090     
1091     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1092     static int
1093     mpt_ioctl_scsi_cmd(unsigned long arg)
1094     {
1095     	return -ENOSYS;
1096     }
1097     
1098     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1099     
1100     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
1101     #define	owner_THIS_MODULE  owner:		THIS_MODULE,
1102     #else
1103     #define	owner_THIS_MODULE
1104     #endif
1105     
1106     static struct file_operations mptctl_fops = {
1107     	owner_THIS_MODULE
1108     	llseek:		no_llseek,
1109     	read:		mptctl_read,
1110     	write:		mptctl_write,
1111     	ioctl:		mpt_ioctl,
1112     	open:		mptctl_open,
1113     	release:	mptctl_release,
1114     };
1115     
1116     static struct miscdevice mptctl_miscdev = {
1117     	MPT_MINOR,
1118     	MYNAM,
1119     	&mptctl_fops
1120     };
1121     
1122     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123     
1124     #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
1125     
1126     /* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
1127     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
1128     extern int register_ioctl32_conversion(unsigned int cmd,
1129     				       int (*handler)(unsigned int,
1130     						      unsigned int,
1131     						      unsigned long,
1132     						      struct file *));
1133     int unregister_ioctl32_conversion(unsigned int cmd);
1134     
1135     struct mpt_fw_xfer32 {
1136     	unsigned int iocnum;
1137     	unsigned int fwlen;
1138     	u32 bufp;
1139     };
1140     
1141     #define MPTFWDOWNLOAD32     _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
1142     
1143     extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
1144     
1145     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1146     static int
1147     sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
1148     			unsigned long arg, struct file *filp)
1149     {
1150     	struct mpt_fw_xfer32 kfw32;
1151     	struct mpt_fw_xfer kfw;
1152     	MPT_ADAPTER *iocp = NULL;
1153     	int iocnum, iocnumX;
1154     	int nonblock = (filp->f_flags & O_NONBLOCK);
1155     	int ret;
1156     
1157     	dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
1158     
1159     	if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
1160     		return -EFAULT;
1161     
1162     	/* Verify intended MPT adapter */
1163     	iocnumX = kfw32.iocnum & 0xFF;
1164     	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
1165     	    (iocp == NULL)) {
1166     		printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
1167     				__LINE__, iocnumX);
1168     		return -ENODEV;
1169     	}
1170     
1171     	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
1172     		return ret;
1173     
1174     	kfw.iocnum = iocnum;
1175     	kfw.fwlen = kfw32.fwlen;
1176     	kfw.bufp = (void *)(unsigned long)kfw32.bufp;
1177     
1178     	ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
1179     
1180     	up(&mptctl_syscall_sem_ioc[iocp->id]);
1181     
1182     	return ret;
1183     }
1184     
1185     #endif		/*} linux >= 2.3.x */
1186     #endif		/*} sparc */
1187     
1188     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1189     int __init mptctl_init(void)
1190     {
1191     	int err;
1192     	int i;
1193     	int where = 1;
1194     
1195     	show_mptmod_ver(my_NAME, my_VERSION);
1196     
1197     	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
1198     		sema_init(&mptctl_syscall_sem_ioc[i], 1);
1199     	}
1200     
1201     #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
1202     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
1203     	err = register_ioctl32_conversion(MPTRWPERF, NULL);
1204     	if (++where && err) goto out_fail;
1205     	err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
1206     	if (++where && err) goto out_fail;
1207     	err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
1208     	if (++where && err) goto out_fail;
1209     	err = register_ioctl32_conversion(MPTFWDOWNLOAD32, sparc32_mptfwxfer_ioctl);
1210     	if (++where && err) goto out_fail;
1211     #endif		/*} linux >= 2.3.x */
1212     #endif		/*} sparc */
1213     
1214     	if (misc_register(&mptctl_miscdev) == -1) {
1215     		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
1216     		err = -EBUSY;
1217     		goto out_fail;
1218     	}
1219     	printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
1220     	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
1221     			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
1222     
1223     	/*
1224     	 *  Install our handler
1225     	 */
1226     	++where;
1227     	if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) <= 0) {
1228     		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
1229     		misc_deregister(&mptctl_miscdev);
1230     		err = -EBUSY;
1231     		goto out_fail;
1232     	}
1233     
1234     	return 0;
1235     
1236     out_fail:
1237     
1238     #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
1239     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
1240     	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
1241     			" (%d:err=%d)\n", where, err);
1242     	unregister_ioctl32_conversion(MPTRWPERF);
1243     	unregister_ioctl32_conversion(MPTRWPERF_CHK);
1244     	unregister_ioctl32_conversion(MPTRWPERF_RESET);
1245     	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
1246     #endif		/*} linux >= 2.3.x */
1247     #endif		/*} sparc */
1248     
1249     	return err;
1250     }
1251     
1252     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1253     void mptctl_exit(void)
1254     {
1255     
1256     #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
1257     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
1258     	unregister_ioctl32_conversion(MPTRWPERF);
1259     	unregister_ioctl32_conversion(MPTRWPERF_CHK);
1260     	unregister_ioctl32_conversion(MPTRWPERF_RESET);
1261     	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
1262     #endif		/*} linux >= 2.3.x */
1263     #endif		/*} sparc */
1264     
1265     	misc_deregister(&mptctl_miscdev);
1266     	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
1267     			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
1268     	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
1269     
1270     	mpt_deregister(mptctl_id);
1271     }
1272     
1273     /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1274     
1275     module_init(mptctl_init);
1276     module_exit(mptctl_exit);
1277