blob: 9bd89cebb5a936999c1b380dc644ae074ff931d4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptctl.c
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04003 * mpt Ioctl driver.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05304 * For use with LSI PCI chip/adapters
5 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05307 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06008 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12/*
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; version 2 of the License.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 NO WARRANTY
23 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
24 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
25 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
26 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
27 solely responsible for determining the appropriateness of using and
28 distributing the Program and assumes all risks associated with its
29 exercise of rights under this Agreement, including but not limited to
30 the risks and costs of program errors, damage to or loss of data,
31 programs or equipment, and unavailability or interruption of operations.
32
33 DISCLAIMER OF LIABILITY
34 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
35 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
37 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
39 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
40 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
41
42 You should have received a copy of the GNU General Public License
43 along with this program; if not, write to the Free Software
44 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
45*/
46/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/kernel.h>
49#include <linux/module.h>
50#include <linux/errno.h>
51#include <linux/init.h>
52#include <linux/slab.h>
53#include <linux/types.h>
54#include <linux/pci.h>
55#include <linux/delay.h> /* for mdelay */
56#include <linux/miscdevice.h>
57#include <linux/smp_lock.h>
58#include <linux/compat.h>
59
60#include <asm/io.h>
61#include <asm/uaccess.h>
62
63#include <scsi/scsi.h>
64#include <scsi/scsi_cmnd.h>
65#include <scsi/scsi_device.h>
66#include <scsi/scsi_host.h>
67#include <scsi/scsi_tcq.h>
68
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +053069#define COPYRIGHT "Copyright (c) 1999-2008 LSI Corporation"
Prakash, Sathyaf36789e2007-08-14 16:22:54 +053070#define MODULEAUTHOR "LSI Corporation"
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#include "mptbase.h"
72#include "mptctl.h"
73
74/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
75#define my_NAME "Fusion MPT misc device (ioctl) driver"
76#define my_VERSION MPT_LINUX_VERSION_COMMON
77#define MYNAM "mptctl"
78
79MODULE_AUTHOR(MODULEAUTHOR);
80MODULE_DESCRIPTION(my_NAME);
81MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070082MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
85
Prakash, Sathyaf606f572007-08-14 16:12:53 +053086static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +053087static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
90
91/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
92
93struct buflist {
94 u8 *kptr;
95 int len;
96};
97
98/*
99 * Function prototypes. Called from OS entry point mptctl_ioctl.
100 * arg contents specific to function.
101 */
102static int mptctl_fw_download(unsigned long arg);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -0600103static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd);
104static int mptctl_gettargetinfo(unsigned long arg);
105static int mptctl_readtest(unsigned long arg);
106static int mptctl_mpt_command(unsigned long arg);
107static int mptctl_eventquery(unsigned long arg);
108static int mptctl_eventenable(unsigned long arg);
109static int mptctl_eventreport(unsigned long arg);
110static int mptctl_replace_fw(unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112static int mptctl_do_reset(unsigned long arg);
113static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
114static int mptctl_hp_targetinfo(unsigned long arg);
115
116static int mptctl_probe(struct pci_dev *, const struct pci_device_id *);
117static void mptctl_remove(struct pci_dev *);
118
119#ifdef CONFIG_COMPAT
120static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg);
121#endif
122/*
123 * Private function calls.
124 */
Moore, Eric Dean d485eb82005-05-11 17:37:26 -0600125static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -0600127static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -0600129static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct buflist *buflist, MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132/*
133 * Reset Handler cleanup function
134 */
135static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
136
Moore, Ericea5a7a82006-02-02 17:20:01 -0700137/*
138 * Event Handler function
139 */
140static int mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Moore, Ericc972c702006-03-14 09:14:06 -0700141static struct fasync_struct *async_queue=NULL;
Moore, Ericea5a7a82006-02-02 17:20:01 -0700142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
144/*
145 * Scatter gather list (SGL) sizes and limits...
146 */
147//#define MAX_SCSI_FRAGS 9
148#define MAX_FRAGS_SPILL1 9
149#define MAX_FRAGS_SPILL2 15
150#define FRAGS_PER_BUCKET (MAX_FRAGS_SPILL2 + 1)
151
152//#define MAX_CHAIN_FRAGS 64
153//#define MAX_CHAIN_FRAGS (15+15+15+16)
154#define MAX_CHAIN_FRAGS (4 * MAX_FRAGS_SPILL2 + 1)
155
156// Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
157// Works out to: 592d bytes! (9+1)*8 + 4*(15+1)*8
158// ^----------------- 80 + 512
159#define MAX_SGL_BYTES ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
160
161/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
162#define MAX_KMALLOC_SZ (128*1024)
163
164#define MPT_IOCTL_DEFAULT_TIMEOUT 10 /* Default timeout value (seconds) */
165
166/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
167/**
168 * mptctl_syscall_down - Down the MPT adapter syscall semaphore.
169 * @ioc: Pointer to MPT adapter
170 * @nonblock: boolean, non-zero if O_NONBLOCK is set
171 *
172 * All of the ioctl commands can potentially sleep, which is illegal
173 * with a spinlock held, thus we perform mutual exclusion here.
174 *
175 * Returns negative errno on error, or zero for success.
176 */
177static inline int
178mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
179{
180 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 if (nonblock) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530183 if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 rc = -EAGAIN;
185 } else {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530186 if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 rc = -ERESTARTSYS;
188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 return rc;
190}
191
192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
193/*
194 * This is the callback for any message we have posted. The message itself
195 * will be returned to the message pool when we return from the IRQ
196 *
197 * This runs in irq context so be short and sweet.
198 */
199static int
200mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
201{
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530202 char *sense_data;
203 int req_index;
204 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530206 if (!req)
207 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530209 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
210 "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function,
211 req, reply));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530213 /*
214 * Handling continuation of the same reply. Processing the first
215 * reply, and eating the other replys that come later.
216 */
217 if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
218 goto out_continuation;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530220 ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530222 if (!reply)
223 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530225 ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
226 sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
227 memcpy(ioc->ioctl_cmds.reply, reply, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530229 if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
230 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
231 "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
232 le16_to_cpu(reply->u.reply.IOCStatus),
233 le32_to_cpu(reply->u.reply.IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530235 if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
236 (req->u.hdr.Function ==
237 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530239 if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
240 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
241 "scsi_status (0x%02x), scsi_state (0x%02x), "
242 "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
243 reply->u.sreply.SCSIStatus,
244 reply->u.sreply.SCSIState,
245 le16_to_cpu(reply->u.sreply.TaskTag),
246 le32_to_cpu(reply->u.sreply.TransferCount)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530248 if (reply->u.sreply.SCSIState &
249 MPI_SCSI_STATE_AUTOSENSE_VALID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 sz = req->u.scsireq.SenseBufferLength;
251 req_index =
252 le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530253 sense_data = ((u8 *)ioc->sense_buf_pool +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 (req_index * MPT_SENSE_BUFFER_ALLOC));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530255 memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
256 ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530259
260 out:
261 /* We are done, issue wake up
262 */
263 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530264 if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530265 mpt_clear_taskmgmt_in_progress_flag(ioc);
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530266 ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
267 complete(&ioc->ioctl_cmds.done);
268 if (ioc->bus_type == SAS)
269 ioc->schedule_target_reset(ioc);
270 } else {
271 ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
272 complete(&ioc->ioctl_cmds.done);
273 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530274 }
275
276 out_continuation:
277 if (reply && (reply->u.reply.MsgFlags &
278 MPI_MSGFLAGS_CONTINUATION_REPLY))
279 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return 1;
281}
282
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530283
284static int
285mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
286{
287 if (!mf)
288 return 0;
289
290 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
291 "TaskMgmt completed (mf=%p, mr=%p)\n",
292 ioc->name, mf, mr));
293
294 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
295
296 if (!mr)
297 goto out;
298
299 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
300 memcpy(ioc->taskmgmt_cmds.reply, mr,
301 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
302 out:
303 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
304 mpt_clear_taskmgmt_in_progress_flag(ioc);
305 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
306 complete(&ioc->taskmgmt_cmds.done);
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530307 if (ioc->bus_type == SAS)
308 ioc->schedule_target_reset(ioc);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530309 return 1;
310 }
311 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530314static int
315mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 MPT_FRAME_HDR *mf;
318 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530319 SCSITaskMgmtReply_t *pScsiTmReply;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 int ii;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530321 int retval;
322 unsigned long timeout;
323 unsigned long time_count;
324 u16 iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530327 mutex_lock(&ioc->taskmgmt_cmds.mutex);
328 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
329 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return -EPERM;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530333 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530335 mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
336 if (mf == NULL) {
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530337 dtmprintk(ioc,
338 printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
339 ioc->name));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530340 mpt_clear_taskmgmt_in_progress_flag(ioc);
341 retval = -ENOMEM;
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530342 goto tm_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
344
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530345 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
346 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 pScsiTm = (SCSITaskMgmt_t *) mf;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530349 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530351 pScsiTm->TaskType = tm_type;
352 if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
353 (ioc->bus_type == FC))
354 pScsiTm->MsgFlags =
355 MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
356 pScsiTm->TargetID = target_id;
357 pScsiTm->Bus = bus_id;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530358 pScsiTm->ChainOffset = 0;
359 pScsiTm->Reserved = 0;
360 pScsiTm->Reserved1 = 0;
361 pScsiTm->TaskMsgContext = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 for (ii= 0; ii < 8; ii++)
363 pScsiTm->LUN[ii] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 for (ii=0; ii < 7; ii++)
365 pScsiTm->Reserved2[ii] = 0;
366
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530367 switch (ioc->bus_type) {
368 case FC:
369 timeout = 40;
370 break;
371 case SAS:
372 timeout = 30;
373 break;
374 case SPI:
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530375 default:
376 timeout = 10;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530377 break;
378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530380 dtmprintk(ioc,
381 printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
382 ioc->name, tm_type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530384 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530385 time_count = jiffies;
386 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
387 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
388 mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530389 else {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530390 retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
391 sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530392 if (retval != 0) {
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530393 dfailprintk(ioc,
394 printk(MYIOC_s_ERR_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530395 "TaskMgmt send_handshake FAILED!"
396 " (ioc %p, mf %p, rc=%d) \n", ioc->name,
397 ioc, mf, retval));
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530398 mpt_free_msg_frame(ioc, mf);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530399 mpt_clear_taskmgmt_in_progress_flag(ioc);
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530400 goto tm_done;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 }
403
404 /* Now wait for the command to complete */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530405 ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530406
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530407 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
408 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
409 "TaskMgmt failed\n", ioc->name));
410 mpt_free_msg_frame(ioc, mf);
411 mpt_clear_taskmgmt_in_progress_flag(ioc);
412 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
413 retval = 0;
414 else
415 retval = -1; /* return failure */
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530416 goto tm_done;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530419 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
420 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
421 "TaskMgmt failed\n", ioc->name));
422 retval = -1; /* return failure */
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530423 goto tm_done;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530424 }
425
426 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
427 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
428 "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
429 "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
430 "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530431 pScsiTmReply->TargetID, tm_type,
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530432 le16_to_cpu(pScsiTmReply->IOCStatus),
433 le32_to_cpu(pScsiTmReply->IOCLogInfo),
434 pScsiTmReply->ResponseCode,
435 le32_to_cpu(pScsiTmReply->TerminationCount)));
436
437 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
438
439 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
440 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
441 iocstatus == MPI_IOCSTATUS_SUCCESS)
442 retval = 0;
443 else {
444 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
445 "TaskMgmt failed\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 retval = -1; /* return failure */
447 }
448
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530449 tm_done:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530450 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
451 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return retval;
453}
454
Kashyap, Desai7d757f12010-03-18 19:13:10 +0530455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
456/* mptctl_timeout_expired
457 *
458 * Expecting an interrupt, however timed out.
459 *
460 */
461static void
462mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
463{
464 unsigned long flags;
465 int ret_val = -1;
466 SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
467 u8 function = mf->u.hdr.Function;
468
469 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
470 ioc->name, __func__));
471
472 if (mpt_fwfault_debug)
473 mpt_halt_firmware(ioc);
474
475 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
476 if (ioc->ioc_reset_in_progress) {
477 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
478 CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
479 mpt_free_msg_frame(ioc, mf);
480 return;
481 }
482 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
483
484
485 CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
486
487 if (ioc->bus_type == SAS) {
488 if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
489 ret_val = mptctl_do_taskmgmt(ioc,
490 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
491 scsi_req->Bus, scsi_req->TargetID);
492 else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
493 ret_val = mptctl_do_taskmgmt(ioc,
494 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
495 scsi_req->Bus, 0);
496 if (!ret_val)
497 return;
498 } else {
499 if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
500 (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
501 ret_val = mptctl_do_taskmgmt(ioc,
502 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
503 scsi_req->Bus, 0);
504 if (!ret_val)
505 return;
506 }
507
508 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
509 ioc->name));
510 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
511 mpt_free_msg_frame(ioc, mf);
512}
513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
516/* mptctl_ioc_reset
517 *
518 * Clean-up functionality. Used only if there has been a
519 * reload of the FW due.
520 *
521 */
522static int
523mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
524{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 switch(reset_phase) {
526 case MPT_IOC_SETUP_RESET:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530527 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
528 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 break;
530 case MPT_IOC_PRE_RESET:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530531 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
532 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
533 break;
534 case MPT_IOC_POST_RESET:
535 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
536 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
537 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
538 ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
539 complete(&ioc->ioctl_cmds.done);
540 }
541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 default:
543 break;
544 }
545
546 return 1;
547}
548
549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericea5a7a82006-02-02 17:20:01 -0700550/* ASYNC Event Notification Support */
551static int
552mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
553{
554 u8 event;
555
556 event = le32_to_cpu(pEvReply->Event) & 0xFF;
557
Prakash, Sathya09120a82007-07-24 15:49:05 +0530558 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700559 ioc->name, __func__));
Moore, Ericea5a7a82006-02-02 17:20:01 -0700560 if(async_queue == NULL)
561 return 1;
562
563 /* Raise SIGIO for persistent events.
564 * TODO - this define is not in MPI spec yet,
565 * but they plan to set it to 0x21
566 */
567 if (event == 0x21 ) {
568 ioc->aen_event_read_flag=1;
Prakash, Sathya09120a82007-07-24 15:49:05 +0530569 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Raised SIGIO to application\n",
570 ioc->name));
571 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
572 "Raised SIGIO to application\n", ioc->name));
Moore, Ericea5a7a82006-02-02 17:20:01 -0700573 kill_fasync(&async_queue, SIGIO, POLL_IN);
574 return 1;
575 }
576
577 /* This flag is set after SIGIO was raised, and
578 * remains set until the application has read
579 * the event log via ioctl=MPTEVENTREPORT
580 */
581 if(ioc->aen_event_read_flag)
582 return 1;
583
584 /* Signal only for the events that are
585 * requested for by the application
586 */
587 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
588 ioc->aen_event_read_flag=1;
Prakash, Sathya09120a82007-07-24 15:49:05 +0530589 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
590 "Raised SIGIO to application\n", ioc->name));
591 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
592 "Raised SIGIO to application\n", ioc->name));
Moore, Ericea5a7a82006-02-02 17:20:01 -0700593 kill_fasync(&async_queue, SIGIO, POLL_IN);
594 }
595 return 1;
596}
597
598static int
599mptctl_fasync(int fd, struct file *filep, int mode)
600{
601 MPT_ADAPTER *ioc;
Jonathan Corbetb7e3e1f2008-06-19 15:41:11 -0600602 int ret;
Moore, Ericea5a7a82006-02-02 17:20:01 -0700603
Jonathan Corbetb7e3e1f2008-06-19 15:41:11 -0600604 lock_kernel();
Moore, Ericea5a7a82006-02-02 17:20:01 -0700605 list_for_each_entry(ioc, &ioc_list, list)
606 ioc->aen_event_read_flag=0;
607
Jonathan Corbetb7e3e1f2008-06-19 15:41:11 -0600608 ret = fasync_helper(fd, filep, mode, &async_queue);
609 unlock_kernel();
610 return ret;
Moore, Ericea5a7a82006-02-02 17:20:01 -0700611}
612
Moore, Ericea5a7a82006-02-02 17:20:01 -0700613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614/*
615 * MPT ioctl handler
616 * cmd - specify the particular IOCTL command to be issued
617 * arg - data specific to the command. Must not be null.
618 */
619static long
620__mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
621{
622 mpt_ioctl_header __user *uhdr = (void __user *) arg;
623 mpt_ioctl_header khdr;
624 int iocnum;
625 unsigned iocnumX;
626 int nonblock = (file->f_flags & O_NONBLOCK);
627 int ret;
628 MPT_ADAPTER *iocp = NULL;
629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
Eric Moore29dd3602007-09-14 18:46:51 -0600631 printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 "Unable to copy mpt_ioctl_header data @ %p\n",
633 __FILE__, __LINE__, uhdr);
634 return -EFAULT;
635 }
636 ret = -ENXIO; /* (-6) No such device or address */
637
638 /* Verify intended MPT adapter - set iocnum and the adapter
639 * pointer (iocp)
640 */
641 iocnumX = khdr.iocnum & 0xFF;
642 if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
Kashyap, Desaie39e1452009-10-07 11:26:54 +0530643 (iocp == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 if (!iocp->active) {
Eric Moore29dd3602007-09-14 18:46:51 -0600647 printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 __FILE__, __LINE__);
649 return -EFAULT;
650 }
651
652 /* Handle those commands that are just returning
653 * information stored in the driver.
654 * These commands should never time out and are unaffected
655 * by TM and FW reloads.
656 */
657 if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
658 return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
659 } else if (cmd == MPTTARGETINFO) {
660 return mptctl_gettargetinfo(arg);
661 } else if (cmd == MPTTEST) {
662 return mptctl_readtest(arg);
663 } else if (cmd == MPTEVENTQUERY) {
664 return mptctl_eventquery(arg);
665 } else if (cmd == MPTEVENTENABLE) {
666 return mptctl_eventenable(arg);
667 } else if (cmd == MPTEVENTREPORT) {
668 return mptctl_eventreport(arg);
669 } else if (cmd == MPTFWREPLACE) {
670 return mptctl_replace_fw(arg);
671 }
672
673 /* All of these commands require an interrupt or
674 * are unknown/illegal.
675 */
676 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
677 return ret;
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (cmd == MPTFWDOWNLOAD)
680 ret = mptctl_fw_download(arg);
681 else if (cmd == MPTCOMMAND)
682 ret = mptctl_mpt_command(arg);
683 else if (cmd == MPTHARDRESET)
684 ret = mptctl_do_reset(arg);
685 else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
686 ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
687 else if (cmd == HP_GETTARGETINFO)
688 ret = mptctl_hp_targetinfo(arg);
689 else
690 ret = -EINVAL;
691
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530692 mutex_unlock(&iocp->ioctl_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 return ret;
695}
696
697static long
698mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
699{
700 long ret;
701 lock_kernel();
702 ret = __mptctl_ioctl(file, cmd, arg);
703 unlock_kernel();
704 return ret;
705}
706
707static int mptctl_do_reset(unsigned long arg)
708{
709 struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
710 struct mpt_ioctl_diag_reset krinfo;
711 MPT_ADAPTER *iocp;
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
Eric Moore29dd3602007-09-14 18:46:51 -0600714 printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 "Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
716 __FILE__, __LINE__, urinfo);
717 return -EFAULT;
718 }
719
720 if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -0600721 printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +0530722 __FILE__, __LINE__, krinfo.hdr.iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return -ENODEV; /* (-6) No such device or address */
724 }
725
Prakash, Sathya09120a82007-07-24 15:49:05 +0530726 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
727 iocp->name));
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -0600730 printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n",
731 iocp->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return -1;
733 }
734
735 return 0;
736}
737
738/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
739/*
740 * MPT FW download function. Cast the arg into the mpt_fw_xfer structure.
741 * This structure contains: iocnum, firmware length (bytes),
742 * pointer to user space memory where the fw image is stored.
743 *
744 * Outputs: None.
745 * Return: 0 if successful
746 * -EFAULT if data unavailable
747 * -ENXIO if no such device
748 * -EAGAIN if resource problem
749 * -ENOMEM if no memory for SGE
750 * -EMLINK if too many chain buffers required
751 * -EBADRQC if adapter does not support FW download
752 * -EBUSY if adapter is busy
753 * -ENOMSG if FW upload returned bad status
754 */
755static int
756mptctl_fw_download(unsigned long arg)
757{
758 struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
759 struct mpt_fw_xfer kfwdl;
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
Eric Moore29dd3602007-09-14 18:46:51 -0600762 printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 "Unable to copy mpt_fw_xfer struct @ %p\n",
764 __FILE__, __LINE__, ufwdl);
765 return -EFAULT;
766 }
767
768 return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
769}
770
771/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
772/*
773 * FW Download engine.
774 * Outputs: None.
775 * Return: 0 if successful
776 * -EFAULT if data unavailable
777 * -ENXIO if no such device
778 * -EAGAIN if resource problem
779 * -ENOMEM if no memory for SGE
780 * -EMLINK if too many chain buffers required
781 * -EBADRQC if adapter does not support FW download
782 * -EBUSY if adapter is busy
783 * -ENOMSG if FW upload returned bad status
784 */
785static int
786mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
787{
788 FWDownload_t *dlmsg;
789 MPT_FRAME_HDR *mf;
790 MPT_ADAPTER *iocp;
791 FWDownloadTCSGE_t *ptsge;
792 MptSge_t *sgl, *sgIn;
793 char *sgOut;
794 struct buflist *buflist;
795 struct buflist *bl;
796 dma_addr_t sgl_dma;
797 int ret;
798 int numfrags = 0;
799 int maxfrags;
800 int n = 0;
801 u32 sgdir;
802 u32 nib;
803 int fw_bytes_copied = 0;
804 int i;
805 int sge_offset = 0;
806 u16 iocstat;
807 pFWDownloadReply_t ReplyMsg = NULL;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530808 unsigned long timeleft;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Moore, Eric946cbf02006-02-02 17:19:50 -0700810 if (mpt_verify_adapter(ioc, &iocp) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -0600811 printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
812 ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return -ENODEV; /* (-6) No such device or address */
Moore, Eric946cbf02006-02-02 17:19:50 -0700814 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Moore, Eric946cbf02006-02-02 17:19:50 -0700816 /* Valid device. Get a message frame and construct the FW download message.
817 */
818 if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
819 return -EAGAIN;
820 }
Prakash, Sathya09120a82007-07-24 15:49:05 +0530821
822 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
823 "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
824 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.bufp = %p\n",
825 iocp->name, ufwbuf));
826 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
827 iocp->name, (int)fwlen));
828 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n",
829 iocp->name, ioc));
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 dlmsg = (FWDownload_t*) mf;
832 ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
833 sgOut = (char *) (ptsge + 1);
834
835 /*
836 * Construct f/w download request
837 */
838 dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
839 dlmsg->Reserved = 0;
840 dlmsg->ChainOffset = 0;
841 dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
842 dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
Moore, Eric946cbf02006-02-02 17:19:50 -0700843 if (iocp->facts.MsgVersion >= MPI_VERSION_01_05)
844 dlmsg->MsgFlags = MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
845 else
846 dlmsg->MsgFlags = 0;
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 /* Set up the Transaction SGE.
850 */
851 ptsge->Reserved = 0;
852 ptsge->ContextSize = 0;
853 ptsge->DetailsLength = 12;
854 ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
855 ptsge->Reserved_0100_Checksum = 0;
856 ptsge->ImageOffset = 0;
857 ptsge->ImageSize = cpu_to_le32(fwlen);
858
859 /* Add the SGL
860 */
861
862 /*
863 * Need to kmalloc area(s) for holding firmware image bytes.
864 * But we need to do it piece meal, using a proper
865 * scatter gather list (with 128kB MAX hunks).
866 *
867 * A practical limit here might be # of sg hunks that fit into
868 * a single IOC request frame; 12 or 8 (see below), so:
869 * For FC9xx: 12 x 128kB == 1.5 mB (max)
870 * For C1030: 8 x 128kB == 1 mB (max)
871 * We could support chaining, but things get ugly(ier:)
872 *
873 * Set the sge_offset to the start of the sgl (bytes).
874 */
875 sgdir = 0x04000000; /* IOC will READ from sys mem */
876 sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);
877 if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,
878 &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
879 return -ENOMEM;
880
881 /*
882 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
883 * for FC9xx f/w image, but calculate max number of sge hunks
884 * we can fit into a request frame, and limit ourselves to that.
885 * (currently no chain support)
886 * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE
887 * Request maxfrags
888 * 128 12
889 * 96 8
890 * 64 4
891 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530892 maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
893 sizeof(FWDownloadTCSGE_t))
894 / iocp->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (numfrags > maxfrags) {
896 ret = -EMLINK;
897 goto fwdl_out;
898 }
899
Prakash, Sathya09120a82007-07-24 15:49:05 +0530900 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
901 iocp->name, sgl, numfrags));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 /*
904 * Parse SG list, copying sgl itself,
905 * plus f/w image hunks from user space as we go...
906 */
907 ret = -EFAULT;
908 sgIn = sgl;
909 bl = buflist;
910 for (i=0; i < numfrags; i++) {
911
912 /* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE
913 * Skip everything but Simple. If simple, copy from
914 * user space into kernel space.
915 * Note: we should not have anything but Simple as
916 * Chain SGE are illegal.
917 */
918 nib = (sgIn->FlagsLength & 0x30000000) >> 28;
919 if (nib == 0 || nib == 3) {
920 ;
921 } else if (sgIn->Address) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530922 iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 n++;
924 if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600925 printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
926 "Unable to copy f/w buffer hunk#%d @ %p\n",
927 iocp->name, __FILE__, __LINE__, n, ufwbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 goto fwdl_out;
929 }
930 fw_bytes_copied += bl->len;
931 }
932 sgIn++;
933 bl++;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530934 sgOut += iocp->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936
Prakash, Sathya09120a82007-07-24 15:49:05 +0530937 DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
939 /*
940 * Finally, perform firmware download.
941 */
Moore, Eric946cbf02006-02-02 17:19:50 -0700942 ReplyMsg = NULL;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530943 SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
944 INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 mpt_put_msg_frame(mptctl_id, iocp, mf);
946
947 /* Now wait for the command to complete */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530948retry_wait:
949 timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
950 if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
951 ret = -ETIME;
952 printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
953 if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
954 mpt_free_msg_frame(iocp, mf);
955 goto fwdl_out;
956 }
957 if (!timeleft)
958 mptctl_timeout_expired(iocp, mf);
959 else
960 goto retry_wait;
961 goto fwdl_out;
962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530964 if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
965 printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
966 mpt_free_msg_frame(iocp, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 ret = -ENODATA;
968 goto fwdl_out;
969 }
970
971 if (sgl)
972 kfree_sgl(sgl, sgl_dma, buflist, iocp);
973
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530974 ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
976 if (iocstat == MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -0600977 printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return 0;
979 } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
Eric Moore29dd3602007-09-14 18:46:51 -0600980 printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
981 iocp->name);
982 printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
983 iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return -EBADRQC;
985 } else if (iocstat == MPI_IOCSTATUS_BUSY) {
Eric Moore29dd3602007-09-14 18:46:51 -0600986 printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
987 printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return -EBUSY;
989 } else {
Eric Moore29dd3602007-09-14 18:46:51 -0600990 printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
991 iocp->name, iocstat);
992 printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return -ENOMSG;
994 }
995 return 0;
996
997fwdl_out:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530998
999 CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
1000 SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 kfree_sgl(sgl, sgl_dma, buflist, iocp);
1002 return ret;
1003}
1004
1005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1006/*
1007 * SGE Allocation routine
1008 *
1009 * Inputs: bytes - number of bytes to be transferred
1010 * sgdir - data direction
1011 * sge_offset - offset (in bytes) from the start of the request
1012 * frame to the first SGE
1013 * ioc - pointer to the mptadapter
1014 * Outputs: frags - number of scatter gather elements
1015 * blp - point to the buflist pointer
1016 * sglbuf_dma - pointer to the (dma) sgl
1017 * Returns: Null if failes
1018 * pointer to the (virtual) sgl if successful.
1019 */
1020static MptSge_t *
1021kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
1022 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
1023{
1024 MptSge_t *sglbuf = NULL; /* pointer to array of SGE */
1025 /* and chain buffers */
1026 struct buflist *buflist = NULL; /* kernel routine */
1027 MptSge_t *sgl;
1028 int numfrags = 0;
1029 int fragcnt = 0;
1030 int alloc_sz = min(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg!
1031 int bytes_allocd = 0;
1032 int this_alloc;
1033 dma_addr_t pa; // phys addr
1034 int i, buflist_ent;
1035 int sg_spill = MAX_FRAGS_SPILL1;
1036 int dir;
1037 /* initialization */
1038 *frags = 0;
1039 *blp = NULL;
1040
1041 /* Allocate and initialize an array of kernel
1042 * structures for the SG elements.
1043 */
1044 i = MAX_SGL_BYTES / 8;
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001045 buflist = kzalloc(i, GFP_USER);
1046 if (!buflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 buflist_ent = 0;
1049
1050 /* Allocate a single block of memory to store the sg elements and
1051 * the chain buffers. The calling routine is responsible for
1052 * copying the data in this array into the correct place in the
1053 * request and chain buffers.
1054 */
1055 sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
1056 if (sglbuf == NULL)
1057 goto free_and_fail;
1058
1059 if (sgdir & 0x04000000)
1060 dir = PCI_DMA_TODEVICE;
1061 else
1062 dir = PCI_DMA_FROMDEVICE;
1063
1064 /* At start:
1065 * sgl = sglbuf = point to beginning of sg buffer
1066 * buflist_ent = 0 = first kernel structure
1067 * sg_spill = number of SGE that can be written before the first
1068 * chain element.
1069 *
1070 */
1071 sgl = sglbuf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301072 sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 while (bytes_allocd < bytes) {
1074 this_alloc = min(alloc_sz, bytes-bytes_allocd);
1075 buflist[buflist_ent].len = this_alloc;
1076 buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
1077 this_alloc,
1078 &pa);
1079 if (buflist[buflist_ent].kptr == NULL) {
1080 alloc_sz = alloc_sz / 2;
1081 if (alloc_sz == 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06001082 printk(MYIOC_s_WARN_FMT "-SG: No can do - "
1083 "not enough memory! :-(\n", ioc->name);
1084 printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
1085 ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 goto free_and_fail;
1087 }
1088 continue;
1089 } else {
1090 dma_addr_t dma_addr;
1091
1092 bytes_allocd += this_alloc;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301093 sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
1094 dma_addr = pci_map_single(ioc->pcidev,
1095 buflist[buflist_ent].kptr, this_alloc, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 sgl->Address = dma_addr;
1097
1098 fragcnt++;
1099 numfrags++;
1100 sgl++;
1101 buflist_ent++;
1102 }
1103
1104 if (bytes_allocd >= bytes)
1105 break;
1106
1107 /* Need to chain? */
1108 if (fragcnt == sg_spill) {
Eric Moore29dd3602007-09-14 18:46:51 -06001109 printk(MYIOC_s_WARN_FMT
1110 "-SG: No can do - " "Chain required! :-(\n", ioc->name);
1111 printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 goto free_and_fail;
1113 }
1114
1115 /* overflow check... */
1116 if (numfrags*8 > MAX_SGL_BYTES){
1117 /* GRRRRR... */
Eric Moore29dd3602007-09-14 18:46:51 -06001118 printk(MYIOC_s_WARN_FMT "-SG: No can do - "
1119 "too many SG frags! :-(\n", ioc->name);
1120 printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
1121 ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 goto free_and_fail;
1123 }
1124 }
1125
1126 /* Last sge fixup: set LE+eol+eob bits */
1127 sgl[-1].FlagsLength |= 0xC1000000;
1128
1129 *frags = numfrags;
1130 *blp = buflist;
1131
Prakash, Sathya09120a82007-07-24 15:49:05 +05301132 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
1133 "%d SG frags generated!\n", ioc->name, numfrags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Prakash, Sathya09120a82007-07-24 15:49:05 +05301135 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
1136 "last (big) alloc_sz=%d\n", ioc->name, alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 return sglbuf;
1139
1140free_and_fail:
1141 if (sglbuf != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 for (i = 0; i < numfrags; i++) {
1143 dma_addr_t dma_addr;
1144 u8 *kptr;
1145 int len;
1146
1147 if ((sglbuf[i].FlagsLength >> 24) == 0x30)
1148 continue;
1149
1150 dma_addr = sglbuf[i].Address;
1151 kptr = buflist[i].kptr;
1152 len = buflist[i].len;
1153
1154 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1155 }
1156 pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
1157 }
1158 kfree(buflist);
1159 return NULL;
1160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/*
1164 * Routine to free the SGL elements.
1165 */
1166static void
1167kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
1168{
1169 MptSge_t *sg = sgl;
1170 struct buflist *bl = buflist;
1171 u32 nib;
1172 int dir;
1173 int n = 0;
1174
1175 if (sg->FlagsLength & 0x04000000)
1176 dir = PCI_DMA_TODEVICE;
1177 else
1178 dir = PCI_DMA_FROMDEVICE;
1179
1180 nib = (sg->FlagsLength & 0xF0000000) >> 28;
1181 while (! (nib & 0x4)) { /* eob */
1182 /* skip ignore/chain. */
1183 if (nib == 0 || nib == 3) {
1184 ;
1185 } else if (sg->Address) {
1186 dma_addr_t dma_addr;
1187 void *kptr;
1188 int len;
1189
1190 dma_addr = sg->Address;
1191 kptr = bl->kptr;
1192 len = bl->len;
1193 pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
1194 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1195 n++;
1196 }
1197 sg++;
1198 bl++;
1199 nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
1200 }
1201
1202 /* we're at eob! */
1203 if (sg->Address) {
1204 dma_addr_t dma_addr;
1205 void *kptr;
1206 int len;
1207
1208 dma_addr = sg->Address;
1209 kptr = bl->kptr;
1210 len = bl->len;
1211 pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
1212 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1213 n++;
1214 }
1215
1216 pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
1217 kfree(buflist);
Prakash, Sathya09120a82007-07-24 15:49:05 +05301218 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n",
1219 ioc->name, n));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220}
1221
1222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1223/*
1224 * mptctl_getiocinfo - Query the host adapter for IOC information.
1225 * @arg: User space argument
1226 *
1227 * Outputs: None.
1228 * Return: 0 if successful
1229 * -EFAULT if data unavailable
1230 * -ENODEV if no such device/adapter
1231 */
1232static int
1233mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
1234{
1235 struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
1236 struct mpt_ioctl_iocinfo *karg;
1237 MPT_ADAPTER *ioc;
1238 struct pci_dev *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 int iocnum;
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001240 unsigned int port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 int cim_rev;
1242 u8 revision;
Eric Moore793955f2007-01-29 09:42:20 -07001243 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -06001244 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* Add of PCI INFO results in unaligned access for
1247 * IA64 and Sparc. Reset long to int. Return no PCI
1248 * data for obsolete format.
1249 */
1250 if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0))
1251 cim_rev = 0;
1252 else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1))
1253 cim_rev = 1;
1254 else if (data_size == sizeof(struct mpt_ioctl_iocinfo))
1255 cim_rev = 2;
1256 else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12))
1257 cim_rev = 0; /* obsolete */
1258 else
1259 return -EFAULT;
1260
1261 karg = kmalloc(data_size, GFP_KERNEL);
1262 if (karg == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001263 printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 __FILE__, __LINE__);
1265 return -ENOMEM;
1266 }
1267
1268 if (copy_from_user(karg, uarg, data_size)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001269 printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 "Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
1271 __FILE__, __LINE__, uarg);
1272 kfree(karg);
1273 return -EFAULT;
1274 }
1275
1276 if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
1277 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001278 printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301279 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 kfree(karg);
1281 return -ENODEV;
1282 }
1283
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001284 /* Verify the data transfer size is correct. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 if (karg->hdr.maxDataSize != data_size) {
Eric Moore29dd3602007-09-14 18:46:51 -06001286 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 "Structure size mismatch. Command not completed.\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001288 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 kfree(karg);
1290 return -EFAULT;
1291 }
1292
Prakash, Sathya09120a82007-07-24 15:49:05 +05301293 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n",
1294 ioc->name));
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 /* Fill in the data and return the structure to the calling
1297 * program
1298 */
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07001299 if (ioc->bus_type == SAS)
1300 karg->adapterType = MPT_IOCTL_INTERFACE_SAS;
1301 else if (ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 karg->adapterType = MPT_IOCTL_INTERFACE_FC;
1303 else
1304 karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
1305
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001306 if (karg->hdr.port > 1)
1307 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 port = karg->hdr.port;
1309
1310 karg->port = port;
1311 pdev = (struct pci_dev *) ioc->pcidev;
1312
1313 karg->pciId = pdev->device;
1314 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1315 karg->hwRev = revision;
1316 karg->subSystemDevice = pdev->subsystem_device;
1317 karg->subSystemVendor = pdev->subsystem_vendor;
1318
1319 if (cim_rev == 1) {
1320 /* Get the PCI bus, device, and function numbers for the IOC
1321 */
1322 karg->pciInfo.u.bits.busNumber = pdev->bus->number;
1323 karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
1324 karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
1325 } else if (cim_rev == 2) {
Moore, Eric86a7dca2006-02-02 17:19:37 -07001326 /* Get the PCI bus, device, function and segment ID numbers
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 for the IOC */
1328 karg->pciInfo.u.bits.busNumber = pdev->bus->number;
1329 karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
1330 karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 karg->pciInfo.segmentID = pci_domain_nr(pdev->bus);
1332 }
1333
1334 /* Get number of devices
1335 */
Eric Moore793955f2007-01-29 09:42:20 -07001336 karg->numDevices = 0;
1337 if (ioc->sh) {
1338 shost_for_each_device(sdev, ioc->sh) {
Eric Moorea69de502007-09-14 18:48:19 -06001339 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301340 if (vdevice == NULL || vdevice->vtarget == NULL)
1341 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001342 if (vdevice->vtarget->tflags &
Eric Moore793955f2007-01-29 09:42:20 -07001343 MPT_TARGET_FLAGS_RAID_COMPONENT)
1344 continue;
1345 karg->numDevices++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
1347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 /* Set the BIOS and FW Version
1350 */
1351 karg->FWVersion = ioc->facts.FWVersion.Word;
1352 karg->BIOSVersion = ioc->biosVersion;
1353
1354 /* Set the Version Strings.
1355 */
1356 strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
1357 karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
1358
1359 karg->busChangeEvent = 0;
1360 karg->hostId = ioc->pfacts[port].PortSCSIID;
1361 karg->rsvd[0] = karg->rsvd[1] = 0;
1362
1363 /* Copy the data from kernel memory to user memory
1364 */
1365 if (copy_to_user((char __user *)arg, karg, data_size)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001366 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 "Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001368 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 kfree(karg);
1370 return -EFAULT;
1371 }
1372
1373 kfree(karg);
1374 return 0;
1375}
1376
1377/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1378/*
1379 * mptctl_gettargetinfo - Query the host adapter for target information.
1380 * @arg: User space argument
1381 *
1382 * Outputs: None.
1383 * Return: 0 if successful
1384 * -EFAULT if data unavailable
1385 * -ENODEV if no such device/adapter
1386 */
1387static int
1388mptctl_gettargetinfo (unsigned long arg)
1389{
1390 struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
1391 struct mpt_ioctl_targetinfo karg;
1392 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001393 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 char *pmem;
1395 int *pdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 int iocnum;
1397 int numDevices = 0;
Eric Moore793955f2007-01-29 09:42:20 -07001398 int lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 int maxWordsLeft;
1400 int numBytes;
Eric Moore793955f2007-01-29 09:42:20 -07001401 u8 port;
1402 struct scsi_device *sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001405 printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 "Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
1407 __FILE__, __LINE__, uarg);
1408 return -EFAULT;
1409 }
1410
1411 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1412 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001413 printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301414 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 return -ENODEV;
1416 }
1417
Prakash, Sathya09120a82007-07-24 15:49:05 +05301418 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
1419 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 /* Get the port number and set the maximum number of bytes
1421 * in the returned structure.
1422 * Ignore the port setting.
1423 */
1424 numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
1425 maxWordsLeft = numBytes/sizeof(int);
1426 port = karg.hdr.port;
1427
1428 if (maxWordsLeft <= 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06001429 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
1430 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 return -ENOMEM;
1432 }
1433
1434 /* Fill in the data and return the structure to the calling
1435 * program
1436 */
1437
1438 /* struct mpt_ioctl_targetinfo does not contain sufficient space
1439 * for the target structures so when the IOCTL is called, there is
1440 * not sufficient stack space for the structure. Allocate memory,
1441 * populate the memory, copy back to the user, then free memory.
1442 * targetInfo format:
1443 * bits 31-24: reserved
1444 * 23-16: LUN
1445 * 15- 8: Bus Number
1446 * 7- 0: Target ID
1447 */
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001448 pmem = kzalloc(numBytes, GFP_KERNEL);
1449 if (!pmem) {
Eric Moore29dd3602007-09-14 18:46:51 -06001450 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
1451 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 return -ENOMEM;
1453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 pdata = (int *) pmem;
1455
1456 /* Get number of devices
1457 */
Eric Moore793955f2007-01-29 09:42:20 -07001458 if (ioc->sh){
1459 shost_for_each_device(sdev, ioc->sh) {
1460 if (!maxWordsLeft)
1461 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001462 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301463 if (vdevice == NULL || vdevice->vtarget == NULL)
1464 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001465 if (vdevice->vtarget->tflags &
Eric Moore793955f2007-01-29 09:42:20 -07001466 MPT_TARGET_FLAGS_RAID_COMPONENT)
1467 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001468 lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
1469 *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
1470 (vdevice->vtarget->id ));
Eric Moore793955f2007-01-29 09:42:20 -07001471 pdata++;
1472 numDevices++;
1473 --maxWordsLeft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
1475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 karg.numDevices = numDevices;
1477
1478 /* Copy part of the data from kernel memory to user memory
1479 */
1480 if (copy_to_user((char __user *)arg, &karg,
1481 sizeof(struct mpt_ioctl_targetinfo))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001482 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001484 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 kfree(pmem);
1486 return -EFAULT;
1487 }
1488
1489 /* Copy the remaining data from kernel memory to user memory
1490 */
1491 if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001492 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001494 ioc->name, __FILE__, __LINE__, pdata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 kfree(pmem);
1496 return -EFAULT;
1497 }
1498
1499 kfree(pmem);
1500
1501 return 0;
1502}
1503
1504/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1505/* MPT IOCTL Test function.
1506 *
1507 * Outputs: None.
1508 * Return: 0 if successful
1509 * -EFAULT if data unavailable
1510 * -ENODEV if no such device/adapter
1511 */
1512static int
1513mptctl_readtest (unsigned long arg)
1514{
1515 struct mpt_ioctl_test __user *uarg = (void __user *) arg;
1516 struct mpt_ioctl_test karg;
1517 MPT_ADAPTER *ioc;
1518 int iocnum;
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001521 printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 "Unable to read in mpt_ioctl_test struct @ %p\n",
1523 __FILE__, __LINE__, uarg);
1524 return -EFAULT;
1525 }
1526
1527 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1528 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001529 printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301530 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 return -ENODEV;
1532 }
1533
Prakash, Sathya09120a82007-07-24 15:49:05 +05301534 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
1535 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 /* Fill in the data and return the structure to the calling
1537 * program
1538 */
1539
1540#ifdef MFCNT
1541 karg.chip_type = ioc->mfcnt;
1542#else
1543 karg.chip_type = ioc->pcidev->device;
1544#endif
1545 strncpy (karg.name, ioc->name, MPT_MAX_NAME);
1546 karg.name[MPT_MAX_NAME-1]='\0';
1547 strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
1548 karg.product[MPT_PRODUCT_LENGTH-1]='\0';
1549
1550 /* Copy the data from kernel memory to user memory
1551 */
1552 if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001553 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 "Unable to write out mpt_ioctl_test struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001555 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 return -EFAULT;
1557 }
1558
1559 return 0;
1560}
1561
1562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1563/*
1564 * mptctl_eventquery - Query the host adapter for the event types
1565 * that are being logged.
1566 * @arg: User space argument
1567 *
1568 * Outputs: None.
1569 * Return: 0 if successful
1570 * -EFAULT if data unavailable
1571 * -ENODEV if no such device/adapter
1572 */
1573static int
1574mptctl_eventquery (unsigned long arg)
1575{
1576 struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
1577 struct mpt_ioctl_eventquery karg;
1578 MPT_ADAPTER *ioc;
1579 int iocnum;
1580
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001582 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 "Unable to read in mpt_ioctl_eventquery struct @ %p\n",
1584 __FILE__, __LINE__, uarg);
1585 return -EFAULT;
1586 }
1587
1588 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1589 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001590 printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301591 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 return -ENODEV;
1593 }
1594
Prakash, Sathya09120a82007-07-24 15:49:05 +05301595 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
1596 ioc->name));
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07001597 karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 karg.eventTypes = ioc->eventTypes;
1599
1600 /* Copy the data from kernel memory to user memory
1601 */
1602 if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001603 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 "Unable to write out mpt_ioctl_eventquery struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001605 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return -EFAULT;
1607 }
1608 return 0;
1609}
1610
1611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1612static int
1613mptctl_eventenable (unsigned long arg)
1614{
1615 struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
1616 struct mpt_ioctl_eventenable karg;
1617 MPT_ADAPTER *ioc;
1618 int iocnum;
1619
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001621 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 "Unable to read in mpt_ioctl_eventenable struct @ %p\n",
1623 __FILE__, __LINE__, uarg);
1624 return -EFAULT;
1625 }
1626
1627 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1628 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001629 printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301630 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return -ENODEV;
1632 }
1633
Prakash, Sathya09120a82007-07-24 15:49:05 +05301634 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
1635 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (ioc->events == NULL) {
1637 /* Have not yet allocated memory - do so now.
1638 */
1639 int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001640 ioc->events = kzalloc(sz, GFP_KERNEL);
1641 if (!ioc->events) {
Eric Moore29dd3602007-09-14 18:46:51 -06001642 printk(MYIOC_s_ERR_FMT
1643 ": ERROR - Insufficient memory to add adapter!\n",
1644 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 return -ENOMEM;
1646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 ioc->alloc_total += sz;
1648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 ioc->eventContext = 0;
1650 }
1651
1652 /* Update the IOC event logging flag.
1653 */
1654 ioc->eventTypes = karg.eventTypes;
1655
1656 return 0;
1657}
1658
1659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1660static int
1661mptctl_eventreport (unsigned long arg)
1662{
1663 struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
1664 struct mpt_ioctl_eventreport karg;
1665 MPT_ADAPTER *ioc;
1666 int iocnum;
1667 int numBytes, maxEvents, max;
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001670 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 "Unable to read in mpt_ioctl_eventreport struct @ %p\n",
1672 __FILE__, __LINE__, uarg);
1673 return -EFAULT;
1674 }
1675
1676 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1677 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001678 printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301679 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 return -ENODEV;
1681 }
Prakash, Sathya09120a82007-07-24 15:49:05 +05301682 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
1683 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685 numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
1686 maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
1687
1688
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07001689 max = MPTCTL_EVENT_LOG_SIZE < maxEvents ? MPTCTL_EVENT_LOG_SIZE : maxEvents;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 /* If fewer than 1 event is requested, there must have
1692 * been some type of error.
1693 */
1694 if ((max < 1) || !ioc->events)
1695 return -ENODATA;
1696
Moore, Ericea5a7a82006-02-02 17:20:01 -07001697 /* reset this flag so SIGIO can restart */
1698 ioc->aen_event_read_flag=0;
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* Copy the data from kernel memory to user memory
1701 */
1702 numBytes = max * sizeof(MPT_IOCTL_EVENTS);
1703 if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001704 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 "Unable to write out mpt_ioctl_eventreport struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001706 ioc->name, __FILE__, __LINE__, ioc->events);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 return -EFAULT;
1708 }
1709
1710 return 0;
1711}
1712
1713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1714static int
1715mptctl_replace_fw (unsigned long arg)
1716{
1717 struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
1718 struct mpt_ioctl_replace_fw karg;
1719 MPT_ADAPTER *ioc;
1720 int iocnum;
1721 int newFwSize;
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001724 printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 "Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
1726 __FILE__, __LINE__, uarg);
1727 return -EFAULT;
1728 }
1729
1730 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1731 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001732 printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301733 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 return -ENODEV;
1735 }
1736
Prakash, Sathya09120a82007-07-24 15:49:05 +05301737 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
1738 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 /* If caching FW, Free the old FW image
1740 */
1741 if (ioc->cached_fw == NULL)
1742 return 0;
1743
1744 mpt_free_fw_memory(ioc);
1745
1746 /* Allocate memory for the new FW image
1747 */
1748 newFwSize = karg.newImageSize;
1749
1750 if (newFwSize & 0x01)
1751 newFwSize += 1;
1752 if (newFwSize & 0x02)
1753 newFwSize += 2;
1754
1755 mpt_alloc_fw_memory(ioc, newFwSize);
1756 if (ioc->cached_fw == NULL)
1757 return -ENOMEM;
1758
1759 /* Copy the data from user memory to kernel space
1760 */
1761 if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001762 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 "Unable to read in mpt_ioctl_replace_fw image "
Eric Moore29dd3602007-09-14 18:46:51 -06001764 "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 mpt_free_fw_memory(ioc);
1766 return -EFAULT;
1767 }
1768
1769 /* Update IOCFactsReply
1770 */
1771 ioc->facts.FWImageSize = newFwSize;
1772 return 0;
1773}
1774
1775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1776/* MPT IOCTL MPTCOMMAND function.
1777 * Cast the arg into the mpt_ioctl_mpt_command structure.
1778 *
1779 * Outputs: None.
1780 * Return: 0 if successful
Joe Perchesfc1323b2008-02-03 17:21:01 +02001781 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 * -EFAULT if data unavailable
1783 * -ENODEV if no such device/adapter
1784 * -ETIME if timer expires
1785 * -ENOMEM if memory allocation error
1786 */
1787static int
1788mptctl_mpt_command (unsigned long arg)
1789{
1790 struct mpt_ioctl_command __user *uarg = (void __user *) arg;
1791 struct mpt_ioctl_command karg;
1792 MPT_ADAPTER *ioc;
1793 int iocnum;
1794 int rc;
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001798 printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 "Unable to read in mpt_ioctl_command struct @ %p\n",
1800 __FILE__, __LINE__, uarg);
1801 return -EFAULT;
1802 }
1803
1804 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1805 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001806 printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301807 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 return -ENODEV;
1809 }
1810
1811 rc = mptctl_do_mpt_command (karg, &uarg->MF);
1812
1813 return rc;
1814}
1815
1816/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1817/* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
1818 *
1819 * Outputs: None.
1820 * Return: 0 if successful
Joe Perchesfc1323b2008-02-03 17:21:01 +02001821 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 * -EFAULT if data unavailable
1823 * -ENODEV if no such device/adapter
1824 * -ETIME if timer expires
1825 * -ENOMEM if memory allocation error
1826 * -EPERM if SCSI I/O and target is untagged
1827 */
1828static int
1829mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
1830{
1831 MPT_ADAPTER *ioc;
1832 MPT_FRAME_HDR *mf = NULL;
1833 MPIHeader_t *hdr;
1834 char *psge;
1835 struct buflist bufIn; /* data In buffer */
1836 struct buflist bufOut; /* data Out buffer */
1837 dma_addr_t dma_addr_in;
1838 dma_addr_t dma_addr_out;
1839 int sgSize = 0; /* Num SG elements */
1840 int iocnum, flagsLength;
1841 int sz, rc = 0;
1842 int msgContext;
1843 u16 req_idx;
1844 ulong timeout;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301845 unsigned long timeleft;
Eric Moore793955f2007-01-29 09:42:20 -07001846 struct scsi_device *sdev;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301847 unsigned long flags;
1848 u8 function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
Eric Mooreab371282007-09-29 10:22:54 -06001850 /* bufIn and bufOut are used for user to kernel space transfers
1851 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 bufIn.kptr = bufOut.kptr = NULL;
Eric Mooreab371282007-09-29 10:22:54 -06001853 bufIn.len = bufOut.len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1856 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001857 printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301858 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 return -ENODEV;
1860 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301861
1862 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
1863 if (ioc->ioc_reset_in_progress) {
1864 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Eric Moore29dd3602007-09-14 18:46:51 -06001865 printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301866 "Busy with diagnostic reset\n", __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return -EBUSY;
1868 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301869 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 /* Verify that the final request frame will not be too large.
1872 */
1873 sz = karg.dataSgeOffset * 4;
1874 if (karg.dataInSize > 0)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301875 sz += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (karg.dataOutSize > 0)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301877 sz += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 if (sz > ioc->req_sz) {
Eric Moore29dd3602007-09-14 18:46:51 -06001880 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 "Request frame too large (%d) maximum (%d)\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001882 ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 return -EFAULT;
1884 }
1885
1886 /* Get a free request frame and save the message context.
1887 */
1888 if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
1889 return -EAGAIN;
1890
1891 hdr = (MPIHeader_t *) mf;
1892 msgContext = le32_to_cpu(hdr->MsgContext);
1893 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1894
1895 /* Copy the request frame
1896 * Reset the saved message context.
1897 * Request frame in user space
1898 */
1899 if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001900 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 "Unable to read MF from mpt_ioctl_command struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001902 ioc->name, __FILE__, __LINE__, mfPtr);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301903 function = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 rc = -EFAULT;
1905 goto done_free_mem;
1906 }
1907 hdr->MsgContext = cpu_to_le32(msgContext);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301908 function = hdr->Function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910
1911 /* Verify that this request is allowed.
1912 */
Prakash, Sathya09120a82007-07-24 15:49:05 +05301913 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
1914 ioc->name, hdr->Function, mf));
1915
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301916 switch (function) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 case MPI_FUNCTION_IOC_FACTS:
1918 case MPI_FUNCTION_PORT_FACTS:
1919 karg.dataOutSize = karg.dataInSize = 0;
1920 break;
1921
1922 case MPI_FUNCTION_CONFIG:
Prakash, Sathya09120a82007-07-24 15:49:05 +05301923 {
1924 Config_t *config_frame;
1925 config_frame = (Config_t *)mf;
1926 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
1927 "number=0x%02x action=0x%02x\n", ioc->name,
1928 config_frame->Header.PageType,
1929 config_frame->ExtPageType,
1930 config_frame->Header.PageNumber,
1931 config_frame->Action));
1932 break;
1933 }
1934
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
1936 case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
1937 case MPI_FUNCTION_FW_UPLOAD:
1938 case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
1939 case MPI_FUNCTION_FW_DOWNLOAD:
1940 case MPI_FUNCTION_FC_PRIMITIVE_SEND:
Moore, Eric096f7a22006-02-02 17:19:30 -07001941 case MPI_FUNCTION_TOOLBOX:
1942 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 break;
1944
1945 case MPI_FUNCTION_SCSI_IO_REQUEST:
1946 if (ioc->sh) {
1947 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
1949 int scsidir = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 int dataSize;
Eric Moore793955f2007-01-29 09:42:20 -07001951 u32 id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Eric Moore793955f2007-01-29 09:42:20 -07001953 id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
1954 if (pScsiReq->TargetID > id) {
Eric Moore29dd3602007-09-14 18:46:51 -06001955 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 "Target ID out of bounds. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06001957 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 rc = -ENODEV;
1959 goto done_free_mem;
1960 }
1961
Eric Moore793955f2007-01-29 09:42:20 -07001962 if (pScsiReq->Bus >= ioc->number_of_buses) {
Eric Moore29dd3602007-09-14 18:46:51 -06001963 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Eric Moore793955f2007-01-29 09:42:20 -07001964 "Target Bus out of bounds. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06001965 ioc->name, __FILE__, __LINE__);
Eric Moore793955f2007-01-29 09:42:20 -07001966 rc = -ENODEV;
1967 goto done_free_mem;
1968 }
1969
Moore, Eric5f07e242006-02-02 17:19:44 -07001970 pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301971 pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
Moore, Eric5f07e242006-02-02 17:19:44 -07001972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 /* verify that app has not requested
1975 * more sense data than driver
1976 * can provide, if so, reset this parameter
1977 * set the sense buffer pointer low address
1978 * update the control field to specify Q type
1979 */
1980 if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
1981 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1982 else
1983 pScsiReq->SenseBufferLength = karg.maxSenseBytes;
1984
1985 pScsiReq->SenseBufferLowAddr =
1986 cpu_to_le32(ioc->sense_buf_low_dma
1987 + (req_idx * MPT_SENSE_BUFFER_ALLOC));
1988
Eric Moore793955f2007-01-29 09:42:20 -07001989 shost_for_each_device(sdev, ioc->sh) {
1990 struct scsi_target *starget = scsi_target(sdev);
1991 VirtTarget *vtarget = starget->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301993 if (vtarget == NULL)
1994 continue;
1995
Eric Moore793955f2007-01-29 09:42:20 -07001996 if ((pScsiReq->TargetID == vtarget->id) &&
1997 (pScsiReq->Bus == vtarget->channel) &&
1998 (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
1999 qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
2000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 /* Have the IOCTL driver set the direction based
2003 * on the dataOutSize (ordering issue with Sparc).
2004 */
2005 if (karg.dataOutSize > 0) {
2006 scsidir = MPI_SCSIIO_CONTROL_WRITE;
2007 dataSize = karg.dataOutSize;
2008 } else {
2009 scsidir = MPI_SCSIIO_CONTROL_READ;
2010 dataSize = karg.dataInSize;
2011 }
2012
2013 pScsiReq->Control = cpu_to_le32(scsidir | qtag);
2014 pScsiReq->DataLength = cpu_to_le32(dataSize);
2015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
2017 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002018 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002020 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 rc = -EFAULT;
2022 goto done_free_mem;
2023 }
2024 break;
2025
Moore, Eric096f7a22006-02-02 17:19:30 -07002026 case MPI_FUNCTION_SMP_PASSTHROUGH:
2027 /* Check mf->PassthruFlags to determine if
2028 * transfer is ImmediateMode or not.
2029 * Immediate mode returns data in the ReplyFrame.
2030 * Else, we are sending request and response data
2031 * in two SGLs at the end of the mf.
2032 */
2033 break;
2034
2035 case MPI_FUNCTION_SATA_PASSTHROUGH:
2036 if (!ioc->sh) {
Eric Moore29dd3602007-09-14 18:46:51 -06002037 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Moore, Eric096f7a22006-02-02 17:19:30 -07002038 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002039 ioc->name, __FILE__, __LINE__);
Moore, Eric096f7a22006-02-02 17:19:30 -07002040 rc = -EFAULT;
2041 goto done_free_mem;
2042 }
2043 break;
2044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 case MPI_FUNCTION_RAID_ACTION:
2046 /* Just add a SGE
2047 */
2048 break;
2049
2050 case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
2051 if (ioc->sh) {
2052 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
2053 int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
2054 int scsidir = MPI_SCSIIO_CONTROL_READ;
2055 int dataSize;
2056
Moore, Eric5f07e242006-02-02 17:19:44 -07002057 pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302058 pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
Moore, Eric5f07e242006-02-02 17:19:44 -07002059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 /* verify that app has not requested
2062 * more sense data than driver
2063 * can provide, if so, reset this parameter
2064 * set the sense buffer pointer low address
2065 * update the control field to specify Q type
2066 */
2067 if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
2068 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2069 else
2070 pScsiReq->SenseBufferLength = karg.maxSenseBytes;
2071
2072 pScsiReq->SenseBufferLowAddr =
2073 cpu_to_le32(ioc->sense_buf_low_dma
2074 + (req_idx * MPT_SENSE_BUFFER_ALLOC));
2075
2076 /* All commands to physical devices are tagged
2077 */
2078
2079 /* Have the IOCTL driver set the direction based
2080 * on the dataOutSize (ordering issue with Sparc).
2081 */
2082 if (karg.dataOutSize > 0) {
2083 scsidir = MPI_SCSIIO_CONTROL_WRITE;
2084 dataSize = karg.dataOutSize;
2085 } else {
2086 scsidir = MPI_SCSIIO_CONTROL_READ;
2087 dataSize = karg.dataInSize;
2088 }
2089
2090 pScsiReq->Control = cpu_to_le32(scsidir | qtag);
2091 pScsiReq->DataLength = cpu_to_le32(dataSize);
2092
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002094 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002096 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 rc = -EFAULT;
2098 goto done_free_mem;
2099 }
2100 break;
2101
2102 case MPI_FUNCTION_SCSI_TASK_MGMT:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302103 {
2104 SCSITaskMgmt_t *pScsiTm;
2105 pScsiTm = (SCSITaskMgmt_t *)mf;
2106 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2107 "\tTaskType=0x%x MsgFlags=0x%x "
2108 "TaskMsgContext=0x%x id=%d channel=%d\n",
2109 ioc->name, pScsiTm->TaskType, le32_to_cpu
2110 (pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
2111 pScsiTm->TargetID, pScsiTm->Bus));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 break;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115 case MPI_FUNCTION_IOC_INIT:
2116 {
2117 IOCInit_t *pInit = (IOCInit_t *) mf;
2118 u32 high_addr, sense_high;
2119
2120 /* Verify that all entries in the IOC INIT match
2121 * existing setup (and in LE format).
2122 */
2123 if (sizeof(dma_addr_t) == sizeof(u64)) {
2124 high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
2125 sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2126 } else {
2127 high_addr = 0;
2128 sense_high= 0;
2129 }
2130
2131 if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
2132 (pInit->MaxBuses != ioc->facts.MaxBuses) ||
2133 (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
2134 (pInit->HostMfaHighAddr != high_addr) ||
2135 (pInit->SenseBufferHighAddr != sense_high)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002136 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002138 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 rc = -EFAULT;
2140 goto done_free_mem;
2141 }
2142 }
2143 break;
2144 default:
2145 /*
2146 * MPI_FUNCTION_PORT_ENABLE
2147 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
2148 * MPI_FUNCTION_TARGET_ASSIST
2149 * MPI_FUNCTION_TARGET_STATUS_SEND
2150 * MPI_FUNCTION_TARGET_MODE_ABORT
2151 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
2152 * MPI_FUNCTION_IO_UNIT_RESET
2153 * MPI_FUNCTION_HANDSHAKE
2154 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
2155 * MPI_FUNCTION_EVENT_NOTIFICATION
2156 * (driver handles event notification)
2157 * MPI_FUNCTION_EVENT_ACK
2158 */
2159
2160 /* What to do with these??? CHECK ME!!!
2161 MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
2162 MPI_FUNCTION_FC_LINK_SRVC_RSP
2163 MPI_FUNCTION_FC_ABORT
2164 MPI_FUNCTION_LAN_SEND
2165 MPI_FUNCTION_LAN_RECEIVE
2166 MPI_FUNCTION_LAN_RESET
2167 */
2168
Eric Moore29dd3602007-09-14 18:46:51 -06002169 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 "Illegal request (function 0x%x) \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002171 ioc->name, __FILE__, __LINE__, hdr->Function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 rc = -EFAULT;
2173 goto done_free_mem;
2174 }
2175
2176 /* Add the SGL ( at most one data in SGE and one data out SGE )
2177 * In the case of two SGE's - the data out (write) will always
2178 * preceede the data in (read) SGE. psgList is used to free the
2179 * allocated memory.
2180 */
2181 psge = (char *) (((int *) mf) + karg.dataSgeOffset);
2182 flagsLength = 0;
2183
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 if (karg.dataOutSize > 0)
2185 sgSize ++;
2186
2187 if (karg.dataInSize > 0)
2188 sgSize ++;
2189
2190 if (sgSize > 0) {
2191
2192 /* Set up the dataOut memory allocation */
2193 if (karg.dataOutSize > 0) {
2194 if (karg.dataInSize > 0) {
2195 flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2196 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302197 MPI_SGE_FLAGS_DIRECTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 << MPI_SGE_FLAGS_SHIFT;
2199 } else {
2200 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
2201 }
2202 flagsLength |= karg.dataOutSize;
2203 bufOut.len = karg.dataOutSize;
2204 bufOut.kptr = pci_alloc_consistent(
2205 ioc->pcidev, bufOut.len, &dma_addr_out);
2206
2207 if (bufOut.kptr == NULL) {
2208 rc = -ENOMEM;
2209 goto done_free_mem;
2210 } else {
2211 /* Set up this SGE.
2212 * Copy to MF and to sglbuf
2213 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302214 ioc->add_sge(psge, flagsLength, dma_addr_out);
2215 psge += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217 /* Copy user data to kernel space.
2218 */
2219 if (copy_from_user(bufOut.kptr,
2220 karg.dataOutBufPtr,
2221 bufOut.len)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002222 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 "%s@%d::mptctl_do_mpt_command - Unable "
2224 "to read user data "
2225 "struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002226 ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 rc = -EFAULT;
2228 goto done_free_mem;
2229 }
2230 }
2231 }
2232
2233 if (karg.dataInSize > 0) {
2234 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
2235 flagsLength |= karg.dataInSize;
2236
2237 bufIn.len = karg.dataInSize;
2238 bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
2239 bufIn.len, &dma_addr_in);
2240
2241 if (bufIn.kptr == NULL) {
2242 rc = -ENOMEM;
2243 goto done_free_mem;
2244 } else {
2245 /* Set up this SGE
2246 * Copy to MF and to sglbuf
2247 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302248 ioc->add_sge(psge, flagsLength, dma_addr_in);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 }
2250 }
2251 } else {
2252 /* Add a NULL SGE
2253 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302254 ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 }
2256
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302257 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
2258 INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
2260
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302261 mutex_lock(&ioc->taskmgmt_cmds.mutex);
2262 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
2263 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2264 goto done_free_mem;
2265 }
2266
Prakash, Sathya09120a82007-07-24 15:49:05 +05302267 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302269 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
2270 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
2271 mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
2272 else {
2273 rc =mpt_send_handshake_request(mptctl_id, ioc,
2274 sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
2275 if (rc != 0) {
2276 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302277 "send_handshake FAILED! (ioc %p, mf %p)\n",
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302278 ioc->name, ioc, mf));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302279 mpt_clear_taskmgmt_in_progress_flag(ioc);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302280 rc = -ENODATA;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302281 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302282 goto done_free_mem;
2283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
2285
2286 } else
2287 mpt_put_msg_frame(mptctl_id, ioc, mf);
2288
2289 /* Now wait for the command to complete */
2290 timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302291retry_wait:
2292 timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2293 HZ*timeout);
2294 if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2295 rc = -ETIME;
2296 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
2297 ioc->name, __func__));
2298 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2299 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2300 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2301 goto done_free_mem;
2302 }
2303 if (!timeleft) {
2304 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2305 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2306 mptctl_timeout_expired(ioc, mf);
2307 mf = NULL;
2308 } else
2309 goto retry_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 goto done_free_mem;
2311 }
2312
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302313 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2314 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2315
2316
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 mf = NULL;
2318
2319 /* If a valid reply frame, copy to the user.
2320 * Offset 2: reply length in U32's
2321 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302322 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 if (karg.maxReplyBytes < ioc->reply_sz) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302324 sz = min(karg.maxReplyBytes,
2325 4*ioc->ioctl_cmds.reply[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 } else {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302327 sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 if (sz > 0) {
2330 if (copy_to_user(karg.replyFrameBufPtr,
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302331 ioc->ioctl_cmds.reply, sz)){
Eric Moore29dd3602007-09-14 18:46:51 -06002332 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 "%s@%d::mptctl_do_mpt_command - "
2334 "Unable to write out reply frame %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002335 ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 rc = -ENODATA;
2337 goto done_free_mem;
2338 }
2339 }
2340 }
2341
2342 /* If valid sense data, copy to user.
2343 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302344 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
2346 if (sz > 0) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302347 if (copy_to_user(karg.senseDataPtr,
2348 ioc->ioctl_cmds.sense, sz)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002349 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 "Unable to write sense data to user %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002351 ioc->name, __FILE__, __LINE__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 karg.senseDataPtr);
2353 rc = -ENODATA;
2354 goto done_free_mem;
2355 }
2356 }
2357 }
2358
2359 /* If the overall status is _GOOD and data in, copy data
2360 * to user.
2361 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302362 if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 (karg.dataInSize > 0) && (bufIn.kptr)) {
2364
2365 if (copy_to_user(karg.dataInBufPtr,
2366 bufIn.kptr, karg.dataInSize)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002367 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 "Unable to write data to user %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002369 ioc->name, __FILE__, __LINE__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 karg.dataInBufPtr);
2371 rc = -ENODATA;
2372 }
2373 }
2374
2375done_free_mem:
2376
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302377 CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2378 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
2380 /* Free the allocated memory.
2381 */
2382 if (bufOut.kptr != NULL) {
2383 pci_free_consistent(ioc->pcidev,
2384 bufOut.len, (void *) bufOut.kptr, dma_addr_out);
2385 }
2386
2387 if (bufIn.kptr != NULL) {
2388 pci_free_consistent(ioc->pcidev,
2389 bufIn.len, (void *) bufIn.kptr, dma_addr_in);
2390 }
2391
2392 /* mf is null if command issued successfully
2393 * otherwise, failure occured after mf acquired.
2394 */
2395 if (mf)
2396 mpt_free_msg_frame(ioc, mf);
2397
2398 return rc;
2399}
2400
2401/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Mooreba856d32006-07-11 17:34:01 -06002402/* Prototype Routine for the HOST INFO command.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 *
2404 * Outputs: None.
2405 * Return: 0 if successful
2406 * -EFAULT if data unavailable
Joe Perchesfc1323b2008-02-03 17:21:01 +02002407 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 * -ENODEV if no such device/adapter
2409 * -ETIME if timer expires
2410 * -ENOMEM if memory allocation error
2411 */
2412static int
2413mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
2414{
2415 hp_host_info_t __user *uarg = (void __user *) arg;
2416 MPT_ADAPTER *ioc;
2417 struct pci_dev *pdev;
Moore, Eric592f9c22006-02-02 17:19:47 -07002418 char *pbuf=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 dma_addr_t buf_dma;
2420 hp_host_info_t karg;
2421 CONFIGPARMS cfg;
2422 ConfigPageHeader_t hdr;
2423 int iocnum;
2424 int rc, cim_rev;
Moore, Eric592f9c22006-02-02 17:19:47 -07002425 ToolboxIstwiReadWriteRequest_t *IstwiRWRequest;
2426 MPT_FRAME_HDR *mf = NULL;
2427 MPIHeader_t *mpi_hdr;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302428 unsigned long timeleft;
2429 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 /* Reset long to int. Should affect IA64 and SPARC only
2432 */
2433 if (data_size == sizeof(hp_host_info_t))
2434 cim_rev = 1;
2435 else if (data_size == sizeof(hp_host_info_rev0_t))
2436 cim_rev = 0; /* obsolete */
2437 else
2438 return -EFAULT;
2439
2440 if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002441 printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 "Unable to read in hp_host_info struct @ %p\n",
2443 __FILE__, __LINE__, uarg);
2444 return -EFAULT;
2445 }
2446
2447 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
2448 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002449 printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302450 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 return -ENODEV;
2452 }
Prakash, Sathya09120a82007-07-24 15:49:05 +05302453 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
2454 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 /* Fill in the data and return the structure to the calling
2457 * program
2458 */
2459 pdev = (struct pci_dev *) ioc->pcidev;
2460
2461 karg.vendor = pdev->vendor;
2462 karg.device = pdev->device;
2463 karg.subsystem_id = pdev->subsystem_device;
2464 karg.subsystem_vendor = pdev->subsystem_vendor;
2465 karg.devfn = pdev->devfn;
2466 karg.bus = pdev->bus->number;
2467
2468 /* Save the SCSI host no. if
2469 * SCSI driver loaded
2470 */
2471 if (ioc->sh != NULL)
2472 karg.host_no = ioc->sh->host_no;
2473 else
2474 karg.host_no = -1;
2475
2476 /* Reformat the fw_version into a string
2477 */
2478 karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ?
2479 ((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0';
2480 karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0';
2481 karg.fw_version[2] = '.';
2482 karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ?
2483 ((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0';
2484 karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0';
2485 karg.fw_version[5] = '.';
2486 karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ?
2487 ((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0';
2488 karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0';
2489 karg.fw_version[8] = '.';
2490 karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ?
2491 ((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0';
2492 karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
2493 karg.fw_version[11] = '\0';
2494
2495 /* Issue a config request to get the device serial number
2496 */
2497 hdr.PageVersion = 0;
2498 hdr.PageLength = 0;
2499 hdr.PageNumber = 0;
2500 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002501 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 cfg.physAddr = -1;
2503 cfg.pageAddr = 0;
2504 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2505 cfg.dir = 0; /* read */
2506 cfg.timeout = 10;
2507
2508 strncpy(karg.serial_number, " ", 24);
2509 if (mpt_config(ioc, &cfg) == 0) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002510 if (cfg.cfghdr.hdr->PageLength > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 /* Issue the second config page request */
2512 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2513
2514 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
2515 if (pbuf) {
2516 cfg.physAddr = buf_dma;
2517 if (mpt_config(ioc, &cfg) == 0) {
2518 ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
2519 if (strlen(pdata->BoardTracerNumber) > 1) {
2520 strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
2521 karg.serial_number[24-1]='\0';
2522 }
2523 }
2524 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
2525 pbuf = NULL;
2526 }
2527 }
2528 }
2529 rc = mpt_GetIocState(ioc, 1);
2530 switch (rc) {
2531 case MPI_IOC_STATE_OPERATIONAL:
2532 karg.ioc_status = HP_STATUS_OK;
2533 break;
2534
2535 case MPI_IOC_STATE_FAULT:
2536 karg.ioc_status = HP_STATUS_FAILED;
2537 break;
2538
2539 case MPI_IOC_STATE_RESET:
2540 case MPI_IOC_STATE_READY:
2541 default:
2542 karg.ioc_status = HP_STATUS_OTHER;
2543 break;
2544 }
2545
2546 karg.base_io_addr = pci_resource_start(pdev, 0);
2547
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07002548 if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 karg.bus_phys_width = HP_BUS_WIDTH_UNK;
2550 else
2551 karg.bus_phys_width = HP_BUS_WIDTH_16;
2552
2553 karg.hard_resets = 0;
2554 karg.soft_resets = 0;
2555 karg.timeouts = 0;
2556 if (ioc->sh != NULL) {
Eric Mooree7eae9f2007-09-29 10:15:59 -06002557 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 if (hd && (cim_rev == 1)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302560 karg.hard_resets = ioc->hard_resets;
2561 karg.soft_resets = ioc->soft_resets;
2562 karg.timeouts = ioc->timeouts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 }
2564 }
2565
Moore, Eric592f9c22006-02-02 17:19:47 -07002566 /*
2567 * Gather ISTWI(Industry Standard Two Wire Interface) Data
2568 */
2569 if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302570 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
2571 "%s, no msg frames!!\n", ioc->name, __func__));
Moore, Eric592f9c22006-02-02 17:19:47 -07002572 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 }
2574
Moore, Eric592f9c22006-02-02 17:19:47 -07002575 IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
2576 mpi_hdr = (MPIHeader_t *) mf;
2577 memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
2578 IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
2579 IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
2580 IstwiRWRequest->MsgContext = mpi_hdr->MsgContext;
2581 IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
2582 IstwiRWRequest->NumAddressBytes = 0x01;
2583 IstwiRWRequest->DataLength = cpu_to_le16(0x04);
2584 if (pdev->devfn & 1)
2585 IstwiRWRequest->DeviceAddr = 0xB2;
2586 else
2587 IstwiRWRequest->DeviceAddr = 0xB0;
2588
2589 pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
2590 if (!pbuf)
2591 goto out;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302592 ioc->add_sge((char *)&IstwiRWRequest->SGL,
Moore, Eric592f9c22006-02-02 17:19:47 -07002593 (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
2594
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302595 retval = 0;
2596 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
2597 IstwiRWRequest->MsgContext);
2598 INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
Moore, Eric592f9c22006-02-02 17:19:47 -07002599 mpt_put_msg_frame(mptctl_id, ioc, mf);
2600
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302601retry_wait:
2602 timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2603 HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
2604 if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2605 retval = -ETIME;
2606 printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
2607 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2608 mpt_free_msg_frame(ioc, mf);
2609 goto out;
2610 }
2611 if (!timeleft)
2612 mptctl_timeout_expired(ioc, mf);
2613 else
2614 goto retry_wait;
Moore, Eric592f9c22006-02-02 17:19:47 -07002615 goto out;
2616 }
2617
Prakash, Sathya09120a82007-07-24 15:49:05 +05302618 /*
Moore, Eric592f9c22006-02-02 17:19:47 -07002619 *ISTWI Data Definition
2620 * pbuf[0] = FW_VERSION = 0x4
2621 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
2622 * the config, you should be seeing one out of these three values
2623 * pbuf[2] = Drive Installed Map = bit pattern depend on which
2624 * bays have drives in them
2625 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
2626 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302627 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
Moore, Eric592f9c22006-02-02 17:19:47 -07002628 karg.rsvd = *(u32 *)pbuf;
2629
2630 out:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302631 CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2632 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
2633
Moore, Eric592f9c22006-02-02 17:19:47 -07002634 if (pbuf)
2635 pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 /* Copy the data from kernel memory to user memory
2638 */
2639 if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002640 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 "Unable to write out hp_host_info @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002642 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 return -EFAULT;
2644 }
2645
2646 return 0;
2647
2648}
2649
2650/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Mooreba856d32006-07-11 17:34:01 -06002651/* Prototype Routine for the TARGET INFO command.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 *
2653 * Outputs: None.
2654 * Return: 0 if successful
2655 * -EFAULT if data unavailable
Joe Perchesfc1323b2008-02-03 17:21:01 +02002656 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 * -ENODEV if no such device/adapter
2658 * -ETIME if timer expires
2659 * -ENOMEM if memory allocation error
2660 */
2661static int
2662mptctl_hp_targetinfo(unsigned long arg)
2663{
2664 hp_target_info_t __user *uarg = (void __user *) arg;
2665 SCSIDevicePage0_t *pg0_alloc;
2666 SCSIDevicePage3_t *pg3_alloc;
2667 MPT_ADAPTER *ioc;
2668 MPT_SCSI_HOST *hd = NULL;
2669 hp_target_info_t karg;
2670 int iocnum;
2671 int data_sz;
2672 dma_addr_t page_dma;
2673 CONFIGPARMS cfg;
2674 ConfigPageHeader_t hdr;
2675 int tmp, np, rc = 0;
2676
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002678 printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 "Unable to read in hp_host_targetinfo struct @ %p\n",
2680 __FILE__, __LINE__, uarg);
2681 return -EFAULT;
2682 }
2683
2684 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
2685 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002686 printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302687 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 return -ENODEV;
2689 }
Eric Moore29dd3602007-09-14 18:46:51 -06002690 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302691 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693 /* There is nothing to do for FCP parts.
2694 */
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07002695 if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 return 0;
2697
2698 if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
2699 return 0;
2700
2701 if (ioc->sh->host_no != karg.hdr.host)
2702 return -ENODEV;
2703
2704 /* Get the data transfer speeds
2705 */
2706 data_sz = ioc->spi_data.sdp0length * 4;
2707 pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
2708 if (pg0_alloc) {
2709 hdr.PageVersion = ioc->spi_data.sdp0version;
2710 hdr.PageLength = data_sz;
2711 hdr.PageNumber = 0;
2712 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
2713
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002714 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2716 cfg.dir = 0;
2717 cfg.timeout = 0;
2718 cfg.physAddr = page_dma;
2719
2720 cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
2721
2722 if ((rc = mpt_config(ioc, &cfg)) == 0) {
2723 np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
2724 karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
2725 HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
2726
2727 if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
2728 tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
2729 if (tmp < 0x09)
2730 karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
2731 else if (tmp <= 0x09)
2732 karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
2733 else if (tmp <= 0x0A)
2734 karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
2735 else if (tmp <= 0x0C)
2736 karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
2737 else if (tmp <= 0x25)
2738 karg.negotiated_speed = HP_DEV_SPEED_FAST;
2739 else
2740 karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
2741 } else
2742 karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
2743 }
2744
2745 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma);
2746 }
2747
2748 /* Set defaults
2749 */
2750 karg.message_rejects = -1;
2751 karg.phase_errors = -1;
2752 karg.parity_errors = -1;
2753 karg.select_timeouts = -1;
2754
2755 /* Get the target error parameters
2756 */
2757 hdr.PageVersion = 0;
2758 hdr.PageLength = 0;
2759 hdr.PageNumber = 3;
2760 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
2761
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002762 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2764 cfg.dir = 0;
2765 cfg.timeout = 0;
2766 cfg.physAddr = -1;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002767 if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 /* Issue the second config page request */
2769 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002770 data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
2772 ioc->pcidev, data_sz, &page_dma);
2773 if (pg3_alloc) {
2774 cfg.physAddr = page_dma;
2775 cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
2776 if ((rc = mpt_config(ioc, &cfg)) == 0) {
2777 karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
2778 karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
2779 karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
2780 }
2781 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
2782 }
2783 }
Eric Mooree7eae9f2007-09-29 10:15:59 -06002784 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 if (hd != NULL)
2786 karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
2787
2788 /* Copy the data from kernel memory to user memory
2789 */
2790 if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002791 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002793 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 return -EFAULT;
2795 }
2796
2797 return 0;
2798}
2799
2800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2801
Arjan van de Venfa027c22007-02-12 00:55:33 -08002802static const struct file_operations mptctl_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 .owner = THIS_MODULE,
2804 .llseek = no_llseek,
Moore, Ericea5a7a82006-02-02 17:20:01 -07002805 .fasync = mptctl_fasync,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 .unlocked_ioctl = mptctl_ioctl,
2807#ifdef CONFIG_COMPAT
2808 .compat_ioctl = compat_mpctl_ioctl,
2809#endif
2810};
2811
2812static struct miscdevice mptctl_miscdev = {
2813 MPT_MINOR,
2814 MYNAM,
2815 &mptctl_fops
2816};
2817
2818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2819
2820#ifdef CONFIG_COMPAT
2821
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822static int
2823compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
2824 unsigned long arg)
2825{
2826 struct mpt_fw_xfer32 kfw32;
2827 struct mpt_fw_xfer kfw;
2828 MPT_ADAPTER *iocp = NULL;
2829 int iocnum, iocnumX;
2830 int nonblock = (filp->f_flags & O_NONBLOCK);
2831 int ret;
2832
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
2834 if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
2835 return -EFAULT;
2836
2837 /* Verify intended MPT adapter */
2838 iocnumX = kfw32.iocnum & 0xFF;
2839 if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
2840 (iocp == NULL)) {
Prakash, Sathya09120a82007-07-24 15:49:05 +05302841 printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002842 __LINE__, iocnumX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 return -ENODEV;
2844 }
2845
2846 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
2847 return ret;
2848
Prakash, Sathya09120a82007-07-24 15:49:05 +05302849 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
2850 iocp->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 kfw.iocnum = iocnum;
2852 kfw.fwlen = kfw32.fwlen;
2853 kfw.bufp = compat_ptr(kfw32.bufp);
2854
2855 ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
2856
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302857 mutex_unlock(&iocp->ioctl_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 return ret;
2860}
2861
2862static int
2863compat_mpt_command(struct file *filp, unsigned int cmd,
2864 unsigned long arg)
2865{
2866 struct mpt_ioctl_command32 karg32;
2867 struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
2868 struct mpt_ioctl_command karg;
2869 MPT_ADAPTER *iocp = NULL;
2870 int iocnum, iocnumX;
2871 int nonblock = (filp->f_flags & O_NONBLOCK);
2872 int ret;
2873
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
2875 return -EFAULT;
2876
2877 /* Verify intended MPT adapter */
2878 iocnumX = karg32.hdr.iocnum & 0xFF;
2879 if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
2880 (iocp == NULL)) {
Prakash, Sathya09120a82007-07-24 15:49:05 +05302881 printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002882 __LINE__, iocnumX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 return -ENODEV;
2884 }
2885
2886 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
2887 return ret;
2888
Prakash, Sathya09120a82007-07-24 15:49:05 +05302889 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
2890 iocp->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 /* Copy data to karg */
2892 karg.hdr.iocnum = karg32.hdr.iocnum;
2893 karg.hdr.port = karg32.hdr.port;
2894 karg.timeout = karg32.timeout;
2895 karg.maxReplyBytes = karg32.maxReplyBytes;
2896
2897 karg.dataInSize = karg32.dataInSize;
2898 karg.dataOutSize = karg32.dataOutSize;
2899 karg.maxSenseBytes = karg32.maxSenseBytes;
2900 karg.dataSgeOffset = karg32.dataSgeOffset;
2901
2902 karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr;
2903 karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr;
2904 karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr;
2905 karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr;
2906
2907 /* Pass new structure to do_mpt_command
2908 */
2909 ret = mptctl_do_mpt_command (karg, &uarg->MF);
2910
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302911 mutex_unlock(&iocp->ioctl_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913 return ret;
2914}
2915
2916static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
2917{
2918 long ret;
2919 lock_kernel();
2920 switch (cmd) {
2921 case MPTIOCINFO:
2922 case MPTIOCINFO1:
2923 case MPTIOCINFO2:
2924 case MPTTARGETINFO:
2925 case MPTEVENTQUERY:
2926 case MPTEVENTENABLE:
2927 case MPTEVENTREPORT:
2928 case MPTHARDRESET:
2929 case HP_GETHOSTINFO:
2930 case HP_GETTARGETINFO:
2931 case MPTTEST:
2932 ret = __mptctl_ioctl(f, cmd, arg);
2933 break;
2934 case MPTCOMMAND32:
2935 ret = compat_mpt_command(f, cmd, arg);
2936 break;
2937 case MPTFWDOWNLOAD32:
2938 ret = compat_mptfwxfer_ioctl(f, cmd, arg);
2939 break;
2940 default:
2941 ret = -ENOIOCTLCMD;
2942 break;
2943 }
2944 unlock_kernel();
2945 return ret;
2946}
2947
2948#endif
2949
2950
2951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2952/*
2953 * mptctl_probe - Installs ioctl devices per bus.
2954 * @pdev: Pointer to pci_dev structure
2955 *
2956 * Returns 0 for success, non-zero for failure.
2957 *
2958 */
2959
2960static int
2961mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2962{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2964
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302965 mutex_init(&ioc->ioctl_cmds.mutex);
2966 init_completion(&ioc->ioctl_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968}
2969
2970/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2971/*
2972 * mptctl_remove - Removed ioctl devices
2973 * @pdev: Pointer to pci_dev structure
2974 *
2975 *
2976 */
2977static void
2978mptctl_remove(struct pci_dev *pdev)
2979{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980}
2981
2982static struct mpt_pci_driver mptctl_driver = {
2983 .probe = mptctl_probe,
2984 .remove = mptctl_remove,
2985};
2986
2987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2988static int __init mptctl_init(void)
2989{
2990 int err;
2991 int where = 1;
2992
2993 show_mptmod_ver(my_NAME, my_VERSION);
2994
Prakash, Sathya09120a82007-07-24 15:49:05 +05302995 mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
2997 /* Register this device */
2998 err = misc_register(&mptctl_miscdev);
2999 if (err < 0) {
3000 printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
3001 goto out_fail;
3002 }
3003 printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
3004 printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
3005 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
3006
3007 /*
3008 * Install our handler
3009 */
3010 ++where;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303011 mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
3012 if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
3014 misc_deregister(&mptctl_miscdev);
3015 err = -EBUSY;
3016 goto out_fail;
3017 }
3018
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05303019 mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003020 if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
3021 printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
3022 mpt_deregister(mptctl_id);
3023 misc_deregister(&mptctl_miscdev);
3024 err = -EBUSY;
3025 goto out_fail;
3026 }
3027
Prakash, Sathya09120a82007-07-24 15:49:05 +05303028 mpt_reset_register(mptctl_id, mptctl_ioc_reset);
3029 mpt_event_register(mptctl_id, mptctl_event_process);
Moore, Ericea5a7a82006-02-02 17:20:01 -07003030
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return 0;
3032
3033out_fail:
3034
3035 mpt_device_driver_deregister(MPTCTL_DRIVER);
3036
3037 return err;
3038}
3039
3040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3041static void mptctl_exit(void)
3042{
3043 misc_deregister(&mptctl_miscdev);
3044 printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
3045 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
3046
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003047 /* De-register event handler from base module */
3048 mpt_event_deregister(mptctl_id);
3049
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 /* De-register reset handler from base module */
3051 mpt_reset_deregister(mptctl_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052
3053 /* De-register callback handler from base module */
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003054 mpt_deregister(mptctl_taskmgmt_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 mpt_deregister(mptctl_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
3057 mpt_device_driver_deregister(MPTCTL_DRIVER);
3058
3059}
3060
3061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3062
3063module_init(mptctl_init);
3064module_exit(mptctl_exit);