blob: 40046f595f1c5b718011c93729372c0d7556c3a6 [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, Ericea5a7a822006-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, Ericea5a7a822006-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, Ericea5a7a822006-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, Ericea5a7a822006-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, Ericea5a7a822006-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, Ericea5a7a822006-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, Ericea5a7a822006-02-02 17:20:01 -0700603
Jonathan Corbetb7e3e1f2008-06-19 15:41:11 -0600604 lock_kernel();
Moore, Ericea5a7a822006-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, Ericea5a7a822006-02-02 17:20:01 -0700611}
612
Moore, Ericea5a7a822006-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 }
Kei Tokunaga97009a22010-06-22 19:01:51 +0900957 if (!timeleft) {
958 printk(MYIOC_s_WARN_FMT
959 "FW download timeout, doorbell=0x%08x\n",
960 iocp->name, mpt_GetIocState(iocp, 0));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530961 mptctl_timeout_expired(iocp, mf);
Kei Tokunaga97009a22010-06-22 19:01:51 +0900962 } else
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530963 goto retry_wait;
964 goto fwdl_out;
965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530967 if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
968 printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
969 mpt_free_msg_frame(iocp, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 ret = -ENODATA;
971 goto fwdl_out;
972 }
973
974 if (sgl)
975 kfree_sgl(sgl, sgl_dma, buflist, iocp);
976
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530977 ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
979 if (iocstat == MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -0600980 printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return 0;
982 } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
Eric Moore29dd3602007-09-14 18:46:51 -0600983 printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
984 iocp->name);
985 printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
986 iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return -EBADRQC;
988 } else if (iocstat == MPI_IOCSTATUS_BUSY) {
Eric Moore29dd3602007-09-14 18:46:51 -0600989 printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
990 printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return -EBUSY;
992 } else {
Eric Moore29dd3602007-09-14 18:46:51 -0600993 printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
994 iocp->name, iocstat);
995 printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return -ENOMSG;
997 }
998 return 0;
999
1000fwdl_out:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301001
1002 CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
1003 SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 kfree_sgl(sgl, sgl_dma, buflist, iocp);
1005 return ret;
1006}
1007
1008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1009/*
1010 * SGE Allocation routine
1011 *
1012 * Inputs: bytes - number of bytes to be transferred
1013 * sgdir - data direction
1014 * sge_offset - offset (in bytes) from the start of the request
1015 * frame to the first SGE
1016 * ioc - pointer to the mptadapter
1017 * Outputs: frags - number of scatter gather elements
1018 * blp - point to the buflist pointer
1019 * sglbuf_dma - pointer to the (dma) sgl
1020 * Returns: Null if failes
1021 * pointer to the (virtual) sgl if successful.
1022 */
1023static MptSge_t *
1024kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
1025 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
1026{
1027 MptSge_t *sglbuf = NULL; /* pointer to array of SGE */
1028 /* and chain buffers */
1029 struct buflist *buflist = NULL; /* kernel routine */
1030 MptSge_t *sgl;
1031 int numfrags = 0;
1032 int fragcnt = 0;
1033 int alloc_sz = min(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg!
1034 int bytes_allocd = 0;
1035 int this_alloc;
1036 dma_addr_t pa; // phys addr
1037 int i, buflist_ent;
1038 int sg_spill = MAX_FRAGS_SPILL1;
1039 int dir;
1040 /* initialization */
1041 *frags = 0;
1042 *blp = NULL;
1043
1044 /* Allocate and initialize an array of kernel
1045 * structures for the SG elements.
1046 */
1047 i = MAX_SGL_BYTES / 8;
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001048 buflist = kzalloc(i, GFP_USER);
1049 if (!buflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 buflist_ent = 0;
1052
1053 /* Allocate a single block of memory to store the sg elements and
1054 * the chain buffers. The calling routine is responsible for
1055 * copying the data in this array into the correct place in the
1056 * request and chain buffers.
1057 */
1058 sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
1059 if (sglbuf == NULL)
1060 goto free_and_fail;
1061
1062 if (sgdir & 0x04000000)
1063 dir = PCI_DMA_TODEVICE;
1064 else
1065 dir = PCI_DMA_FROMDEVICE;
1066
1067 /* At start:
1068 * sgl = sglbuf = point to beginning of sg buffer
1069 * buflist_ent = 0 = first kernel structure
1070 * sg_spill = number of SGE that can be written before the first
1071 * chain element.
1072 *
1073 */
1074 sgl = sglbuf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301075 sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 while (bytes_allocd < bytes) {
1077 this_alloc = min(alloc_sz, bytes-bytes_allocd);
1078 buflist[buflist_ent].len = this_alloc;
1079 buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
1080 this_alloc,
1081 &pa);
1082 if (buflist[buflist_ent].kptr == NULL) {
1083 alloc_sz = alloc_sz / 2;
1084 if (alloc_sz == 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06001085 printk(MYIOC_s_WARN_FMT "-SG: No can do - "
1086 "not enough memory! :-(\n", ioc->name);
1087 printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
1088 ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 goto free_and_fail;
1090 }
1091 continue;
1092 } else {
1093 dma_addr_t dma_addr;
1094
1095 bytes_allocd += this_alloc;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301096 sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
1097 dma_addr = pci_map_single(ioc->pcidev,
1098 buflist[buflist_ent].kptr, this_alloc, dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 sgl->Address = dma_addr;
1100
1101 fragcnt++;
1102 numfrags++;
1103 sgl++;
1104 buflist_ent++;
1105 }
1106
1107 if (bytes_allocd >= bytes)
1108 break;
1109
1110 /* Need to chain? */
1111 if (fragcnt == sg_spill) {
Eric Moore29dd3602007-09-14 18:46:51 -06001112 printk(MYIOC_s_WARN_FMT
1113 "-SG: No can do - " "Chain required! :-(\n", ioc->name);
1114 printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 goto free_and_fail;
1116 }
1117
1118 /* overflow check... */
1119 if (numfrags*8 > MAX_SGL_BYTES){
1120 /* GRRRRR... */
Eric Moore29dd3602007-09-14 18:46:51 -06001121 printk(MYIOC_s_WARN_FMT "-SG: No can do - "
1122 "too many SG frags! :-(\n", ioc->name);
1123 printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
1124 ioc->name, numfrags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 goto free_and_fail;
1126 }
1127 }
1128
1129 /* Last sge fixup: set LE+eol+eob bits */
1130 sgl[-1].FlagsLength |= 0xC1000000;
1131
1132 *frags = numfrags;
1133 *blp = buflist;
1134
Prakash, Sathya09120a82007-07-24 15:49:05 +05301135 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
1136 "%d SG frags generated!\n", ioc->name, numfrags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Prakash, Sathya09120a82007-07-24 15:49:05 +05301138 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
1139 "last (big) alloc_sz=%d\n", ioc->name, alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 return sglbuf;
1142
1143free_and_fail:
1144 if (sglbuf != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 for (i = 0; i < numfrags; i++) {
1146 dma_addr_t dma_addr;
1147 u8 *kptr;
1148 int len;
1149
1150 if ((sglbuf[i].FlagsLength >> 24) == 0x30)
1151 continue;
1152
1153 dma_addr = sglbuf[i].Address;
1154 kptr = buflist[i].kptr;
1155 len = buflist[i].len;
1156
1157 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1158 }
1159 pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
1160 }
1161 kfree(buflist);
1162 return NULL;
1163}
1164
1165/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1166/*
1167 * Routine to free the SGL elements.
1168 */
1169static void
1170kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
1171{
1172 MptSge_t *sg = sgl;
1173 struct buflist *bl = buflist;
1174 u32 nib;
1175 int dir;
1176 int n = 0;
1177
1178 if (sg->FlagsLength & 0x04000000)
1179 dir = PCI_DMA_TODEVICE;
1180 else
1181 dir = PCI_DMA_FROMDEVICE;
1182
1183 nib = (sg->FlagsLength & 0xF0000000) >> 28;
1184 while (! (nib & 0x4)) { /* eob */
1185 /* skip ignore/chain. */
1186 if (nib == 0 || nib == 3) {
1187 ;
1188 } else if (sg->Address) {
1189 dma_addr_t dma_addr;
1190 void *kptr;
1191 int len;
1192
1193 dma_addr = sg->Address;
1194 kptr = bl->kptr;
1195 len = bl->len;
1196 pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
1197 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1198 n++;
1199 }
1200 sg++;
1201 bl++;
1202 nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
1203 }
1204
1205 /* we're at eob! */
1206 if (sg->Address) {
1207 dma_addr_t dma_addr;
1208 void *kptr;
1209 int len;
1210
1211 dma_addr = sg->Address;
1212 kptr = bl->kptr;
1213 len = bl->len;
1214 pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
1215 pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
1216 n++;
1217 }
1218
1219 pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
1220 kfree(buflist);
Prakash, Sathya09120a82007-07-24 15:49:05 +05301221 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n",
1222 ioc->name, n));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223}
1224
1225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1226/*
1227 * mptctl_getiocinfo - Query the host adapter for IOC information.
1228 * @arg: User space argument
1229 *
1230 * Outputs: None.
1231 * Return: 0 if successful
1232 * -EFAULT if data unavailable
1233 * -ENODEV if no such device/adapter
1234 */
1235static int
1236mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
1237{
1238 struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
1239 struct mpt_ioctl_iocinfo *karg;
1240 MPT_ADAPTER *ioc;
1241 struct pci_dev *pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 int iocnum;
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001243 unsigned int port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 int cim_rev;
1245 u8 revision;
Eric Moore793955f2007-01-29 09:42:20 -07001246 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -06001247 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 /* Add of PCI INFO results in unaligned access for
1250 * IA64 and Sparc. Reset long to int. Return no PCI
1251 * data for obsolete format.
1252 */
1253 if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0))
1254 cim_rev = 0;
1255 else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1))
1256 cim_rev = 1;
1257 else if (data_size == sizeof(struct mpt_ioctl_iocinfo))
1258 cim_rev = 2;
1259 else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12))
1260 cim_rev = 0; /* obsolete */
1261 else
1262 return -EFAULT;
1263
1264 karg = kmalloc(data_size, GFP_KERNEL);
1265 if (karg == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001266 printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 __FILE__, __LINE__);
1268 return -ENOMEM;
1269 }
1270
1271 if (copy_from_user(karg, uarg, data_size)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001272 printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 "Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
1274 __FILE__, __LINE__, uarg);
1275 kfree(karg);
1276 return -EFAULT;
1277 }
1278
1279 if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
1280 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001281 printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301282 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 kfree(karg);
1284 return -ENODEV;
1285 }
1286
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001287 /* Verify the data transfer size is correct. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 if (karg->hdr.maxDataSize != data_size) {
Eric Moore29dd3602007-09-14 18:46:51 -06001289 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 "Structure size mismatch. Command not completed.\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001291 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 kfree(karg);
1293 return -EFAULT;
1294 }
1295
Prakash, Sathya09120a82007-07-24 15:49:05 +05301296 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n",
1297 ioc->name));
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 /* Fill in the data and return the structure to the calling
1300 * program
1301 */
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07001302 if (ioc->bus_type == SAS)
1303 karg->adapterType = MPT_IOCTL_INTERFACE_SAS;
1304 else if (ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 karg->adapterType = MPT_IOCTL_INTERFACE_FC;
1306 else
1307 karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
1308
Moore, Eric Dean b6fe4dd2005-04-22 18:01:34 -04001309 if (karg->hdr.port > 1)
1310 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 port = karg->hdr.port;
1312
1313 karg->port = port;
1314 pdev = (struct pci_dev *) ioc->pcidev;
1315
1316 karg->pciId = pdev->device;
1317 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1318 karg->hwRev = revision;
1319 karg->subSystemDevice = pdev->subsystem_device;
1320 karg->subSystemVendor = pdev->subsystem_vendor;
1321
1322 if (cim_rev == 1) {
1323 /* Get the PCI bus, device, and function numbers for the IOC
1324 */
1325 karg->pciInfo.u.bits.busNumber = pdev->bus->number;
1326 karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
1327 karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
1328 } else if (cim_rev == 2) {
Moore, Eric86a7dca2006-02-02 17:19:37 -07001329 /* Get the PCI bus, device, function and segment ID numbers
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 for the IOC */
1331 karg->pciInfo.u.bits.busNumber = pdev->bus->number;
1332 karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
1333 karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 karg->pciInfo.segmentID = pci_domain_nr(pdev->bus);
1335 }
1336
1337 /* Get number of devices
1338 */
Eric Moore793955f2007-01-29 09:42:20 -07001339 karg->numDevices = 0;
1340 if (ioc->sh) {
1341 shost_for_each_device(sdev, ioc->sh) {
Eric Moorea69de502007-09-14 18:48:19 -06001342 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301343 if (vdevice == NULL || vdevice->vtarget == NULL)
1344 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001345 if (vdevice->vtarget->tflags &
Eric Moore793955f2007-01-29 09:42:20 -07001346 MPT_TARGET_FLAGS_RAID_COMPONENT)
1347 continue;
1348 karg->numDevices++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
1350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
1352 /* Set the BIOS and FW Version
1353 */
1354 karg->FWVersion = ioc->facts.FWVersion.Word;
1355 karg->BIOSVersion = ioc->biosVersion;
1356
1357 /* Set the Version Strings.
1358 */
1359 strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
1360 karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
1361
1362 karg->busChangeEvent = 0;
1363 karg->hostId = ioc->pfacts[port].PortSCSIID;
1364 karg->rsvd[0] = karg->rsvd[1] = 0;
1365
1366 /* Copy the data from kernel memory to user memory
1367 */
1368 if (copy_to_user((char __user *)arg, karg, data_size)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001369 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 "Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001371 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 kfree(karg);
1373 return -EFAULT;
1374 }
1375
1376 kfree(karg);
1377 return 0;
1378}
1379
1380/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1381/*
1382 * mptctl_gettargetinfo - Query the host adapter for target information.
1383 * @arg: User space argument
1384 *
1385 * Outputs: None.
1386 * Return: 0 if successful
1387 * -EFAULT if data unavailable
1388 * -ENODEV if no such device/adapter
1389 */
1390static int
1391mptctl_gettargetinfo (unsigned long arg)
1392{
1393 struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
1394 struct mpt_ioctl_targetinfo karg;
1395 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001396 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 char *pmem;
1398 int *pdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 int iocnum;
1400 int numDevices = 0;
Eric Moore793955f2007-01-29 09:42:20 -07001401 int lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 int maxWordsLeft;
1403 int numBytes;
Eric Moore793955f2007-01-29 09:42:20 -07001404 u8 port;
1405 struct scsi_device *sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001408 printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 "Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
1410 __FILE__, __LINE__, uarg);
1411 return -EFAULT;
1412 }
1413
1414 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1415 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001416 printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301417 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 return -ENODEV;
1419 }
1420
Prakash, Sathya09120a82007-07-24 15:49:05 +05301421 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
1422 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 /* Get the port number and set the maximum number of bytes
1424 * in the returned structure.
1425 * Ignore the port setting.
1426 */
1427 numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
1428 maxWordsLeft = numBytes/sizeof(int);
1429 port = karg.hdr.port;
1430
1431 if (maxWordsLeft <= 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06001432 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
1433 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 return -ENOMEM;
1435 }
1436
1437 /* Fill in the data and return the structure to the calling
1438 * program
1439 */
1440
1441 /* struct mpt_ioctl_targetinfo does not contain sufficient space
1442 * for the target structures so when the IOCTL is called, there is
1443 * not sufficient stack space for the structure. Allocate memory,
1444 * populate the memory, copy back to the user, then free memory.
1445 * targetInfo format:
1446 * bits 31-24: reserved
1447 * 23-16: LUN
1448 * 15- 8: Bus Number
1449 * 7- 0: Target ID
1450 */
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001451 pmem = kzalloc(numBytes, GFP_KERNEL);
1452 if (!pmem) {
Eric Moore29dd3602007-09-14 18:46:51 -06001453 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
1454 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 return -ENOMEM;
1456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 pdata = (int *) pmem;
1458
1459 /* Get number of devices
1460 */
Eric Moore793955f2007-01-29 09:42:20 -07001461 if (ioc->sh){
1462 shost_for_each_device(sdev, ioc->sh) {
1463 if (!maxWordsLeft)
1464 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001465 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301466 if (vdevice == NULL || vdevice->vtarget == NULL)
1467 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001468 if (vdevice->vtarget->tflags &
Eric Moore793955f2007-01-29 09:42:20 -07001469 MPT_TARGET_FLAGS_RAID_COMPONENT)
1470 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001471 lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
1472 *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
1473 (vdevice->vtarget->id ));
Eric Moore793955f2007-01-29 09:42:20 -07001474 pdata++;
1475 numDevices++;
1476 --maxWordsLeft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 karg.numDevices = numDevices;
1480
1481 /* Copy part of the data from kernel memory to user memory
1482 */
1483 if (copy_to_user((char __user *)arg, &karg,
1484 sizeof(struct mpt_ioctl_targetinfo))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001485 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001487 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 kfree(pmem);
1489 return -EFAULT;
1490 }
1491
1492 /* Copy the remaining data from kernel memory to user memory
1493 */
1494 if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001495 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001497 ioc->name, __FILE__, __LINE__, pdata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 kfree(pmem);
1499 return -EFAULT;
1500 }
1501
1502 kfree(pmem);
1503
1504 return 0;
1505}
1506
1507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1508/* MPT IOCTL Test function.
1509 *
1510 * Outputs: None.
1511 * Return: 0 if successful
1512 * -EFAULT if data unavailable
1513 * -ENODEV if no such device/adapter
1514 */
1515static int
1516mptctl_readtest (unsigned long arg)
1517{
1518 struct mpt_ioctl_test __user *uarg = (void __user *) arg;
1519 struct mpt_ioctl_test karg;
1520 MPT_ADAPTER *ioc;
1521 int iocnum;
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001524 printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 "Unable to read in mpt_ioctl_test struct @ %p\n",
1526 __FILE__, __LINE__, uarg);
1527 return -EFAULT;
1528 }
1529
1530 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1531 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001532 printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301533 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 return -ENODEV;
1535 }
1536
Prakash, Sathya09120a82007-07-24 15:49:05 +05301537 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
1538 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 /* Fill in the data and return the structure to the calling
1540 * program
1541 */
1542
1543#ifdef MFCNT
1544 karg.chip_type = ioc->mfcnt;
1545#else
1546 karg.chip_type = ioc->pcidev->device;
1547#endif
1548 strncpy (karg.name, ioc->name, MPT_MAX_NAME);
1549 karg.name[MPT_MAX_NAME-1]='\0';
1550 strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
1551 karg.product[MPT_PRODUCT_LENGTH-1]='\0';
1552
1553 /* Copy the data from kernel memory to user memory
1554 */
1555 if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001556 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 "Unable to write out mpt_ioctl_test struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001558 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return -EFAULT;
1560 }
1561
1562 return 0;
1563}
1564
1565/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1566/*
1567 * mptctl_eventquery - Query the host adapter for the event types
1568 * that are being logged.
1569 * @arg: User space argument
1570 *
1571 * Outputs: None.
1572 * Return: 0 if successful
1573 * -EFAULT if data unavailable
1574 * -ENODEV if no such device/adapter
1575 */
1576static int
1577mptctl_eventquery (unsigned long arg)
1578{
1579 struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
1580 struct mpt_ioctl_eventquery karg;
1581 MPT_ADAPTER *ioc;
1582 int iocnum;
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001585 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 "Unable to read in mpt_ioctl_eventquery struct @ %p\n",
1587 __FILE__, __LINE__, uarg);
1588 return -EFAULT;
1589 }
1590
1591 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1592 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001593 printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301594 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 return -ENODEV;
1596 }
1597
Prakash, Sathya09120a82007-07-24 15:49:05 +05301598 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
1599 ioc->name));
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07001600 karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 karg.eventTypes = ioc->eventTypes;
1602
1603 /* Copy the data from kernel memory to user memory
1604 */
1605 if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001606 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 "Unable to write out mpt_ioctl_eventquery struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001608 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 return -EFAULT;
1610 }
1611 return 0;
1612}
1613
1614/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1615static int
1616mptctl_eventenable (unsigned long arg)
1617{
1618 struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
1619 struct mpt_ioctl_eventenable karg;
1620 MPT_ADAPTER *ioc;
1621 int iocnum;
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001624 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 "Unable to read in mpt_ioctl_eventenable struct @ %p\n",
1626 __FILE__, __LINE__, uarg);
1627 return -EFAULT;
1628 }
1629
1630 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1631 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001632 printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301633 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 return -ENODEV;
1635 }
1636
Prakash, Sathya09120a82007-07-24 15:49:05 +05301637 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
1638 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 if (ioc->events == NULL) {
1640 /* Have not yet allocated memory - do so now.
1641 */
1642 int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
Mariusz Kozlowskid7383a22007-08-10 14:50:50 -07001643 ioc->events = kzalloc(sz, GFP_KERNEL);
1644 if (!ioc->events) {
Eric Moore29dd3602007-09-14 18:46:51 -06001645 printk(MYIOC_s_ERR_FMT
1646 ": ERROR - Insufficient memory to add adapter!\n",
1647 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return -ENOMEM;
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 ioc->alloc_total += sz;
1651
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 ioc->eventContext = 0;
1653 }
1654
1655 /* Update the IOC event logging flag.
1656 */
1657 ioc->eventTypes = karg.eventTypes;
1658
1659 return 0;
1660}
1661
1662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1663static int
1664mptctl_eventreport (unsigned long arg)
1665{
1666 struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
1667 struct mpt_ioctl_eventreport karg;
1668 MPT_ADAPTER *ioc;
1669 int iocnum;
1670 int numBytes, maxEvents, max;
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001673 printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 "Unable to read in mpt_ioctl_eventreport struct @ %p\n",
1675 __FILE__, __LINE__, uarg);
1676 return -EFAULT;
1677 }
1678
1679 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1680 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001681 printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301682 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 return -ENODEV;
1684 }
Prakash, Sathya09120a82007-07-24 15:49:05 +05301685 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
1686 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
1689 maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
1690
1691
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07001692 max = MPTCTL_EVENT_LOG_SIZE < maxEvents ? MPTCTL_EVENT_LOG_SIZE : maxEvents;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 /* If fewer than 1 event is requested, there must have
1695 * been some type of error.
1696 */
1697 if ((max < 1) || !ioc->events)
1698 return -ENODATA;
1699
Moore, Ericea5a7a822006-02-02 17:20:01 -07001700 /* reset this flag so SIGIO can restart */
1701 ioc->aen_event_read_flag=0;
1702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 /* Copy the data from kernel memory to user memory
1704 */
1705 numBytes = max * sizeof(MPT_IOCTL_EVENTS);
1706 if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001707 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 "Unable to write out mpt_ioctl_eventreport struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001709 ioc->name, __FILE__, __LINE__, ioc->events);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 return -EFAULT;
1711 }
1712
1713 return 0;
1714}
1715
1716/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1717static int
1718mptctl_replace_fw (unsigned long arg)
1719{
1720 struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
1721 struct mpt_ioctl_replace_fw karg;
1722 MPT_ADAPTER *ioc;
1723 int iocnum;
1724 int newFwSize;
1725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001727 printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 "Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
1729 __FILE__, __LINE__, uarg);
1730 return -EFAULT;
1731 }
1732
1733 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1734 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001735 printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301736 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 return -ENODEV;
1738 }
1739
Prakash, Sathya09120a82007-07-24 15:49:05 +05301740 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
1741 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 /* If caching FW, Free the old FW image
1743 */
1744 if (ioc->cached_fw == NULL)
1745 return 0;
1746
1747 mpt_free_fw_memory(ioc);
1748
1749 /* Allocate memory for the new FW image
1750 */
1751 newFwSize = karg.newImageSize;
1752
1753 if (newFwSize & 0x01)
1754 newFwSize += 1;
1755 if (newFwSize & 0x02)
1756 newFwSize += 2;
1757
1758 mpt_alloc_fw_memory(ioc, newFwSize);
1759 if (ioc->cached_fw == NULL)
1760 return -ENOMEM;
1761
1762 /* Copy the data from user memory to kernel space
1763 */
1764 if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001765 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 "Unable to read in mpt_ioctl_replace_fw image "
Eric Moore29dd3602007-09-14 18:46:51 -06001767 "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 mpt_free_fw_memory(ioc);
1769 return -EFAULT;
1770 }
1771
1772 /* Update IOCFactsReply
1773 */
1774 ioc->facts.FWImageSize = newFwSize;
1775 return 0;
1776}
1777
1778/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1779/* MPT IOCTL MPTCOMMAND function.
1780 * Cast the arg into the mpt_ioctl_mpt_command structure.
1781 *
1782 * Outputs: None.
1783 * Return: 0 if successful
Joe Perchesfc1323b2008-02-03 17:21:01 +02001784 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 * -EFAULT if data unavailable
1786 * -ENODEV if no such device/adapter
1787 * -ETIME if timer expires
1788 * -ENOMEM if memory allocation error
1789 */
1790static int
1791mptctl_mpt_command (unsigned long arg)
1792{
1793 struct mpt_ioctl_command __user *uarg = (void __user *) arg;
1794 struct mpt_ioctl_command karg;
1795 MPT_ADAPTER *ioc;
1796 int iocnum;
1797 int rc;
1798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800 if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
Eric Moore29dd3602007-09-14 18:46:51 -06001801 printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 "Unable to read in mpt_ioctl_command struct @ %p\n",
1803 __FILE__, __LINE__, uarg);
1804 return -EFAULT;
1805 }
1806
1807 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1808 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001809 printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301810 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 return -ENODEV;
1812 }
1813
1814 rc = mptctl_do_mpt_command (karg, &uarg->MF);
1815
1816 return rc;
1817}
1818
1819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1820/* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
1821 *
1822 * Outputs: None.
1823 * Return: 0 if successful
Joe Perchesfc1323b2008-02-03 17:21:01 +02001824 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 * -EFAULT if data unavailable
1826 * -ENODEV if no such device/adapter
1827 * -ETIME if timer expires
1828 * -ENOMEM if memory allocation error
1829 * -EPERM if SCSI I/O and target is untagged
1830 */
1831static int
1832mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
1833{
1834 MPT_ADAPTER *ioc;
1835 MPT_FRAME_HDR *mf = NULL;
1836 MPIHeader_t *hdr;
1837 char *psge;
1838 struct buflist bufIn; /* data In buffer */
1839 struct buflist bufOut; /* data Out buffer */
1840 dma_addr_t dma_addr_in;
1841 dma_addr_t dma_addr_out;
1842 int sgSize = 0; /* Num SG elements */
1843 int iocnum, flagsLength;
1844 int sz, rc = 0;
1845 int msgContext;
1846 u16 req_idx;
1847 ulong timeout;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301848 unsigned long timeleft;
Eric Moore793955f2007-01-29 09:42:20 -07001849 struct scsi_device *sdev;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301850 unsigned long flags;
1851 u8 function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Eric Mooreab371282007-09-29 10:22:54 -06001853 /* bufIn and bufOut are used for user to kernel space transfers
1854 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 bufIn.kptr = bufOut.kptr = NULL;
Eric Mooreab371282007-09-29 10:22:54 -06001856 bufIn.len = bufOut.len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
1859 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001860 printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05301861 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 return -ENODEV;
1863 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301864
1865 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
1866 if (ioc->ioc_reset_in_progress) {
1867 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Eric Moore29dd3602007-09-14 18:46:51 -06001868 printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301869 "Busy with diagnostic reset\n", __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 return -EBUSY;
1871 }
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301872 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 /* Verify that the final request frame will not be too large.
1875 */
1876 sz = karg.dataSgeOffset * 4;
1877 if (karg.dataInSize > 0)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301878 sz += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 if (karg.dataOutSize > 0)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301880 sz += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 if (sz > ioc->req_sz) {
Eric Moore29dd3602007-09-14 18:46:51 -06001883 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 "Request frame too large (%d) maximum (%d)\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001885 ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return -EFAULT;
1887 }
1888
1889 /* Get a free request frame and save the message context.
1890 */
1891 if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
1892 return -EAGAIN;
1893
1894 hdr = (MPIHeader_t *) mf;
1895 msgContext = le32_to_cpu(hdr->MsgContext);
1896 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1897
1898 /* Copy the request frame
1899 * Reset the saved message context.
1900 * Request frame in user space
1901 */
1902 if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001903 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 "Unable to read MF from mpt_ioctl_command struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001905 ioc->name, __FILE__, __LINE__, mfPtr);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301906 function = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 rc = -EFAULT;
1908 goto done_free_mem;
1909 }
1910 hdr->MsgContext = cpu_to_le32(msgContext);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301911 function = hdr->Function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913
1914 /* Verify that this request is allowed.
1915 */
Prakash, Sathya09120a82007-07-24 15:49:05 +05301916 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
1917 ioc->name, hdr->Function, mf));
1918
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301919 switch (function) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 case MPI_FUNCTION_IOC_FACTS:
1921 case MPI_FUNCTION_PORT_FACTS:
1922 karg.dataOutSize = karg.dataInSize = 0;
1923 break;
1924
1925 case MPI_FUNCTION_CONFIG:
Prakash, Sathya09120a82007-07-24 15:49:05 +05301926 {
1927 Config_t *config_frame;
1928 config_frame = (Config_t *)mf;
1929 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
1930 "number=0x%02x action=0x%02x\n", ioc->name,
1931 config_frame->Header.PageType,
1932 config_frame->ExtPageType,
1933 config_frame->Header.PageNumber,
1934 config_frame->Action));
1935 break;
1936 }
1937
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
1939 case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
1940 case MPI_FUNCTION_FW_UPLOAD:
1941 case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
1942 case MPI_FUNCTION_FW_DOWNLOAD:
1943 case MPI_FUNCTION_FC_PRIMITIVE_SEND:
Moore, Eric096f7a22006-02-02 17:19:30 -07001944 case MPI_FUNCTION_TOOLBOX:
1945 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 break;
1947
1948 case MPI_FUNCTION_SCSI_IO_REQUEST:
1949 if (ioc->sh) {
1950 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
1952 int scsidir = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 int dataSize;
Eric Moore793955f2007-01-29 09:42:20 -07001954 u32 id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Eric Moore793955f2007-01-29 09:42:20 -07001956 id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
1957 if (pScsiReq->TargetID > id) {
Eric Moore29dd3602007-09-14 18:46:51 -06001958 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 "Target ID out of bounds. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06001960 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 rc = -ENODEV;
1962 goto done_free_mem;
1963 }
1964
Eric Moore793955f2007-01-29 09:42:20 -07001965 if (pScsiReq->Bus >= ioc->number_of_buses) {
Eric Moore29dd3602007-09-14 18:46:51 -06001966 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Eric Moore793955f2007-01-29 09:42:20 -07001967 "Target Bus out of bounds. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06001968 ioc->name, __FILE__, __LINE__);
Eric Moore793955f2007-01-29 09:42:20 -07001969 rc = -ENODEV;
1970 goto done_free_mem;
1971 }
1972
Moore, Eric5f07e242006-02-02 17:19:44 -07001973 pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301974 pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
Moore, Eric5f07e242006-02-02 17:19:44 -07001975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 /* verify that app has not requested
1978 * more sense data than driver
1979 * can provide, if so, reset this parameter
1980 * set the sense buffer pointer low address
1981 * update the control field to specify Q type
1982 */
1983 if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
1984 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1985 else
1986 pScsiReq->SenseBufferLength = karg.maxSenseBytes;
1987
1988 pScsiReq->SenseBufferLowAddr =
1989 cpu_to_le32(ioc->sense_buf_low_dma
1990 + (req_idx * MPT_SENSE_BUFFER_ALLOC));
1991
Eric Moore793955f2007-01-29 09:42:20 -07001992 shost_for_each_device(sdev, ioc->sh) {
1993 struct scsi_target *starget = scsi_target(sdev);
1994 VirtTarget *vtarget = starget->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05301996 if (vtarget == NULL)
1997 continue;
1998
Eric Moore793955f2007-01-29 09:42:20 -07001999 if ((pScsiReq->TargetID == vtarget->id) &&
2000 (pScsiReq->Bus == vtarget->channel) &&
2001 (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
2002 qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
2003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
2005 /* Have the IOCTL driver set the direction based
2006 * on the dataOutSize (ordering issue with Sparc).
2007 */
2008 if (karg.dataOutSize > 0) {
2009 scsidir = MPI_SCSIIO_CONTROL_WRITE;
2010 dataSize = karg.dataOutSize;
2011 } else {
2012 scsidir = MPI_SCSIIO_CONTROL_READ;
2013 dataSize = karg.dataInSize;
2014 }
2015
2016 pScsiReq->Control = cpu_to_le32(scsidir | qtag);
2017 pScsiReq->DataLength = cpu_to_le32(dataSize);
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
2020 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002021 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002023 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 rc = -EFAULT;
2025 goto done_free_mem;
2026 }
2027 break;
2028
Moore, Eric096f7a22006-02-02 17:19:30 -07002029 case MPI_FUNCTION_SMP_PASSTHROUGH:
2030 /* Check mf->PassthruFlags to determine if
2031 * transfer is ImmediateMode or not.
2032 * Immediate mode returns data in the ReplyFrame.
2033 * Else, we are sending request and response data
2034 * in two SGLs at the end of the mf.
2035 */
2036 break;
2037
2038 case MPI_FUNCTION_SATA_PASSTHROUGH:
2039 if (!ioc->sh) {
Eric Moore29dd3602007-09-14 18:46:51 -06002040 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Moore, Eric096f7a22006-02-02 17:19:30 -07002041 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002042 ioc->name, __FILE__, __LINE__);
Moore, Eric096f7a22006-02-02 17:19:30 -07002043 rc = -EFAULT;
2044 goto done_free_mem;
2045 }
2046 break;
2047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 case MPI_FUNCTION_RAID_ACTION:
2049 /* Just add a SGE
2050 */
2051 break;
2052
2053 case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
2054 if (ioc->sh) {
2055 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
2056 int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
2057 int scsidir = MPI_SCSIIO_CONTROL_READ;
2058 int dataSize;
2059
Moore, Eric5f07e242006-02-02 17:19:44 -07002060 pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302061 pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
Moore, Eric5f07e242006-02-02 17:19:44 -07002062
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
2064 /* verify that app has not requested
2065 * more sense data than driver
2066 * can provide, if so, reset this parameter
2067 * set the sense buffer pointer low address
2068 * update the control field to specify Q type
2069 */
2070 if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
2071 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2072 else
2073 pScsiReq->SenseBufferLength = karg.maxSenseBytes;
2074
2075 pScsiReq->SenseBufferLowAddr =
2076 cpu_to_le32(ioc->sense_buf_low_dma
2077 + (req_idx * MPT_SENSE_BUFFER_ALLOC));
2078
2079 /* All commands to physical devices are tagged
2080 */
2081
2082 /* Have the IOCTL driver set the direction based
2083 * on the dataOutSize (ordering issue with Sparc).
2084 */
2085 if (karg.dataOutSize > 0) {
2086 scsidir = MPI_SCSIIO_CONTROL_WRITE;
2087 dataSize = karg.dataOutSize;
2088 } else {
2089 scsidir = MPI_SCSIIO_CONTROL_READ;
2090 dataSize = karg.dataInSize;
2091 }
2092
2093 pScsiReq->Control = cpu_to_le32(scsidir | qtag);
2094 pScsiReq->DataLength = cpu_to_le32(dataSize);
2095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002097 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 "SCSI driver is not loaded. \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002099 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 rc = -EFAULT;
2101 goto done_free_mem;
2102 }
2103 break;
2104
2105 case MPI_FUNCTION_SCSI_TASK_MGMT:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302106 {
2107 SCSITaskMgmt_t *pScsiTm;
2108 pScsiTm = (SCSITaskMgmt_t *)mf;
2109 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2110 "\tTaskType=0x%x MsgFlags=0x%x "
2111 "TaskMsgContext=0x%x id=%d channel=%d\n",
2112 ioc->name, pScsiTm->TaskType, le32_to_cpu
2113 (pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
2114 pScsiTm->TargetID, pScsiTm->Bus));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 break;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
2118 case MPI_FUNCTION_IOC_INIT:
2119 {
2120 IOCInit_t *pInit = (IOCInit_t *) mf;
2121 u32 high_addr, sense_high;
2122
2123 /* Verify that all entries in the IOC INIT match
2124 * existing setup (and in LE format).
2125 */
2126 if (sizeof(dma_addr_t) == sizeof(u64)) {
2127 high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
2128 sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2129 } else {
2130 high_addr = 0;
2131 sense_high= 0;
2132 }
2133
2134 if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
2135 (pInit->MaxBuses != ioc->facts.MaxBuses) ||
2136 (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
2137 (pInit->HostMfaHighAddr != high_addr) ||
2138 (pInit->SenseBufferHighAddr != sense_high)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002139 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002141 ioc->name, __FILE__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 rc = -EFAULT;
2143 goto done_free_mem;
2144 }
2145 }
2146 break;
2147 default:
2148 /*
2149 * MPI_FUNCTION_PORT_ENABLE
2150 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
2151 * MPI_FUNCTION_TARGET_ASSIST
2152 * MPI_FUNCTION_TARGET_STATUS_SEND
2153 * MPI_FUNCTION_TARGET_MODE_ABORT
2154 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
2155 * MPI_FUNCTION_IO_UNIT_RESET
2156 * MPI_FUNCTION_HANDSHAKE
2157 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
2158 * MPI_FUNCTION_EVENT_NOTIFICATION
2159 * (driver handles event notification)
2160 * MPI_FUNCTION_EVENT_ACK
2161 */
2162
2163 /* What to do with these??? CHECK ME!!!
2164 MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
2165 MPI_FUNCTION_FC_LINK_SRVC_RSP
2166 MPI_FUNCTION_FC_ABORT
2167 MPI_FUNCTION_LAN_SEND
2168 MPI_FUNCTION_LAN_RECEIVE
2169 MPI_FUNCTION_LAN_RESET
2170 */
2171
Eric Moore29dd3602007-09-14 18:46:51 -06002172 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 "Illegal request (function 0x%x) \n",
Eric Moore29dd3602007-09-14 18:46:51 -06002174 ioc->name, __FILE__, __LINE__, hdr->Function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 rc = -EFAULT;
2176 goto done_free_mem;
2177 }
2178
2179 /* Add the SGL ( at most one data in SGE and one data out SGE )
2180 * In the case of two SGE's - the data out (write) will always
2181 * preceede the data in (read) SGE. psgList is used to free the
2182 * allocated memory.
2183 */
2184 psge = (char *) (((int *) mf) + karg.dataSgeOffset);
2185 flagsLength = 0;
2186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 if (karg.dataOutSize > 0)
2188 sgSize ++;
2189
2190 if (karg.dataInSize > 0)
2191 sgSize ++;
2192
2193 if (sgSize > 0) {
2194
2195 /* Set up the dataOut memory allocation */
2196 if (karg.dataOutSize > 0) {
2197 if (karg.dataInSize > 0) {
2198 flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2199 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302200 MPI_SGE_FLAGS_DIRECTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 << MPI_SGE_FLAGS_SHIFT;
2202 } else {
2203 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
2204 }
2205 flagsLength |= karg.dataOutSize;
2206 bufOut.len = karg.dataOutSize;
2207 bufOut.kptr = pci_alloc_consistent(
2208 ioc->pcidev, bufOut.len, &dma_addr_out);
2209
2210 if (bufOut.kptr == NULL) {
2211 rc = -ENOMEM;
2212 goto done_free_mem;
2213 } else {
2214 /* Set up this SGE.
2215 * Copy to MF and to sglbuf
2216 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302217 ioc->add_sge(psge, flagsLength, dma_addr_out);
2218 psge += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 /* Copy user data to kernel space.
2221 */
2222 if (copy_from_user(bufOut.kptr,
2223 karg.dataOutBufPtr,
2224 bufOut.len)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002225 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 "%s@%d::mptctl_do_mpt_command - Unable "
2227 "to read user data "
2228 "struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002229 ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 rc = -EFAULT;
2231 goto done_free_mem;
2232 }
2233 }
2234 }
2235
2236 if (karg.dataInSize > 0) {
2237 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
2238 flagsLength |= karg.dataInSize;
2239
2240 bufIn.len = karg.dataInSize;
2241 bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
2242 bufIn.len, &dma_addr_in);
2243
2244 if (bufIn.kptr == NULL) {
2245 rc = -ENOMEM;
2246 goto done_free_mem;
2247 } else {
2248 /* Set up this SGE
2249 * Copy to MF and to sglbuf
2250 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302251 ioc->add_sge(psge, flagsLength, dma_addr_in);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
2253 }
2254 } else {
2255 /* Add a NULL SGE
2256 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302257 ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 }
2259
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302260 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
2261 INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
2263
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302264 mutex_lock(&ioc->taskmgmt_cmds.mutex);
2265 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
2266 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2267 goto done_free_mem;
2268 }
2269
Prakash, Sathya09120a82007-07-24 15:49:05 +05302270 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302272 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
2273 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
2274 mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
2275 else {
2276 rc =mpt_send_handshake_request(mptctl_id, ioc,
2277 sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
2278 if (rc != 0) {
2279 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302280 "send_handshake FAILED! (ioc %p, mf %p)\n",
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302281 ioc->name, ioc, mf));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302282 mpt_clear_taskmgmt_in_progress_flag(ioc);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302283 rc = -ENODATA;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302284 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05302285 goto done_free_mem;
2286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
2288
2289 } else
2290 mpt_put_msg_frame(mptctl_id, ioc, mf);
2291
2292 /* Now wait for the command to complete */
2293 timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302294retry_wait:
2295 timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2296 HZ*timeout);
2297 if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2298 rc = -ETIME;
2299 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
2300 ioc->name, __func__));
2301 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2302 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2303 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2304 goto done_free_mem;
2305 }
2306 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09002307 printk(MYIOC_s_WARN_FMT
2308 "mpt cmd timeout, doorbell=0x%08x"
2309 " function=0x%x\n",
2310 ioc->name, mpt_GetIocState(ioc, 0), function);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302311 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2312 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2313 mptctl_timeout_expired(ioc, mf);
2314 mf = NULL;
2315 } else
2316 goto retry_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 goto done_free_mem;
2318 }
2319
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302320 if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
2321 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
2322
2323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 mf = NULL;
2325
2326 /* If a valid reply frame, copy to the user.
2327 * Offset 2: reply length in U32's
2328 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302329 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 if (karg.maxReplyBytes < ioc->reply_sz) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302331 sz = min(karg.maxReplyBytes,
2332 4*ioc->ioctl_cmds.reply[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 } else {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302334 sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 if (sz > 0) {
2337 if (copy_to_user(karg.replyFrameBufPtr,
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302338 ioc->ioctl_cmds.reply, sz)){
Eric Moore29dd3602007-09-14 18:46:51 -06002339 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 "%s@%d::mptctl_do_mpt_command - "
2341 "Unable to write out reply frame %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002342 ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 rc = -ENODATA;
2344 goto done_free_mem;
2345 }
2346 }
2347 }
2348
2349 /* If valid sense data, copy to user.
2350 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302351 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
2353 if (sz > 0) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302354 if (copy_to_user(karg.senseDataPtr,
2355 ioc->ioctl_cmds.sense, sz)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002356 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 "Unable to write sense data to user %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002358 ioc->name, __FILE__, __LINE__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 karg.senseDataPtr);
2360 rc = -ENODATA;
2361 goto done_free_mem;
2362 }
2363 }
2364 }
2365
2366 /* If the overall status is _GOOD and data in, copy data
2367 * to user.
2368 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302369 if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 (karg.dataInSize > 0) && (bufIn.kptr)) {
2371
2372 if (copy_to_user(karg.dataInBufPtr,
2373 bufIn.kptr, karg.dataInSize)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002374 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 "Unable to write data to user %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002376 ioc->name, __FILE__, __LINE__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 karg.dataInBufPtr);
2378 rc = -ENODATA;
2379 }
2380 }
2381
2382done_free_mem:
2383
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302384 CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2385 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
2387 /* Free the allocated memory.
2388 */
2389 if (bufOut.kptr != NULL) {
2390 pci_free_consistent(ioc->pcidev,
2391 bufOut.len, (void *) bufOut.kptr, dma_addr_out);
2392 }
2393
2394 if (bufIn.kptr != NULL) {
2395 pci_free_consistent(ioc->pcidev,
2396 bufIn.len, (void *) bufIn.kptr, dma_addr_in);
2397 }
2398
2399 /* mf is null if command issued successfully
2400 * otherwise, failure occured after mf acquired.
2401 */
2402 if (mf)
2403 mpt_free_msg_frame(ioc, mf);
2404
2405 return rc;
2406}
2407
2408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Mooreba856d32006-07-11 17:34:01 -06002409/* Prototype Routine for the HOST INFO command.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 *
2411 * Outputs: None.
2412 * Return: 0 if successful
2413 * -EFAULT if data unavailable
Joe Perchesfc1323b2008-02-03 17:21:01 +02002414 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 * -ENODEV if no such device/adapter
2416 * -ETIME if timer expires
2417 * -ENOMEM if memory allocation error
2418 */
2419static int
2420mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
2421{
2422 hp_host_info_t __user *uarg = (void __user *) arg;
2423 MPT_ADAPTER *ioc;
2424 struct pci_dev *pdev;
Moore, Eric592f9c22006-02-02 17:19:47 -07002425 char *pbuf=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 dma_addr_t buf_dma;
2427 hp_host_info_t karg;
2428 CONFIGPARMS cfg;
2429 ConfigPageHeader_t hdr;
2430 int iocnum;
2431 int rc, cim_rev;
Moore, Eric592f9c22006-02-02 17:19:47 -07002432 ToolboxIstwiReadWriteRequest_t *IstwiRWRequest;
2433 MPT_FRAME_HDR *mf = NULL;
2434 MPIHeader_t *mpi_hdr;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302435 unsigned long timeleft;
2436 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 /* Reset long to int. Should affect IA64 and SPARC only
2439 */
2440 if (data_size == sizeof(hp_host_info_t))
2441 cim_rev = 1;
2442 else if (data_size == sizeof(hp_host_info_rev0_t))
2443 cim_rev = 0; /* obsolete */
2444 else
2445 return -EFAULT;
2446
2447 if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002448 printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 "Unable to read in hp_host_info struct @ %p\n",
2450 __FILE__, __LINE__, uarg);
2451 return -EFAULT;
2452 }
2453
2454 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
2455 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002456 printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302457 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 return -ENODEV;
2459 }
Prakash, Sathya09120a82007-07-24 15:49:05 +05302460 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
2461 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 /* Fill in the data and return the structure to the calling
2464 * program
2465 */
2466 pdev = (struct pci_dev *) ioc->pcidev;
2467
2468 karg.vendor = pdev->vendor;
2469 karg.device = pdev->device;
2470 karg.subsystem_id = pdev->subsystem_device;
2471 karg.subsystem_vendor = pdev->subsystem_vendor;
2472 karg.devfn = pdev->devfn;
2473 karg.bus = pdev->bus->number;
2474
2475 /* Save the SCSI host no. if
2476 * SCSI driver loaded
2477 */
2478 if (ioc->sh != NULL)
2479 karg.host_no = ioc->sh->host_no;
2480 else
2481 karg.host_no = -1;
2482
2483 /* Reformat the fw_version into a string
2484 */
2485 karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ?
2486 ((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0';
2487 karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0';
2488 karg.fw_version[2] = '.';
2489 karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ?
2490 ((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0';
2491 karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0';
2492 karg.fw_version[5] = '.';
2493 karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ?
2494 ((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0';
2495 karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0';
2496 karg.fw_version[8] = '.';
2497 karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ?
2498 ((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0';
2499 karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
2500 karg.fw_version[11] = '\0';
2501
2502 /* Issue a config request to get the device serial number
2503 */
2504 hdr.PageVersion = 0;
2505 hdr.PageLength = 0;
2506 hdr.PageNumber = 0;
2507 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002508 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 cfg.physAddr = -1;
2510 cfg.pageAddr = 0;
2511 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2512 cfg.dir = 0; /* read */
2513 cfg.timeout = 10;
2514
2515 strncpy(karg.serial_number, " ", 24);
2516 if (mpt_config(ioc, &cfg) == 0) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002517 if (cfg.cfghdr.hdr->PageLength > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 /* Issue the second config page request */
2519 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2520
2521 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
2522 if (pbuf) {
2523 cfg.physAddr = buf_dma;
2524 if (mpt_config(ioc, &cfg) == 0) {
2525 ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
2526 if (strlen(pdata->BoardTracerNumber) > 1) {
2527 strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
2528 karg.serial_number[24-1]='\0';
2529 }
2530 }
2531 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
2532 pbuf = NULL;
2533 }
2534 }
2535 }
2536 rc = mpt_GetIocState(ioc, 1);
2537 switch (rc) {
2538 case MPI_IOC_STATE_OPERATIONAL:
2539 karg.ioc_status = HP_STATUS_OK;
2540 break;
2541
2542 case MPI_IOC_STATE_FAULT:
2543 karg.ioc_status = HP_STATUS_FAILED;
2544 break;
2545
2546 case MPI_IOC_STATE_RESET:
2547 case MPI_IOC_STATE_READY:
2548 default:
2549 karg.ioc_status = HP_STATUS_OTHER;
2550 break;
2551 }
2552
2553 karg.base_io_addr = pci_resource_start(pdev, 0);
2554
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07002555 if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 karg.bus_phys_width = HP_BUS_WIDTH_UNK;
2557 else
2558 karg.bus_phys_width = HP_BUS_WIDTH_16;
2559
2560 karg.hard_resets = 0;
2561 karg.soft_resets = 0;
2562 karg.timeouts = 0;
2563 if (ioc->sh != NULL) {
Eric Mooree7eae9f2007-09-29 10:15:59 -06002564 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
2566 if (hd && (cim_rev == 1)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302567 karg.hard_resets = ioc->hard_resets;
2568 karg.soft_resets = ioc->soft_resets;
2569 karg.timeouts = ioc->timeouts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 }
2571 }
2572
Moore, Eric592f9c22006-02-02 17:19:47 -07002573 /*
2574 * Gather ISTWI(Industry Standard Two Wire Interface) Data
2575 */
2576 if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302577 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
2578 "%s, no msg frames!!\n", ioc->name, __func__));
Moore, Eric592f9c22006-02-02 17:19:47 -07002579 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 }
2581
Moore, Eric592f9c22006-02-02 17:19:47 -07002582 IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
2583 mpi_hdr = (MPIHeader_t *) mf;
2584 memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
2585 IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
2586 IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
2587 IstwiRWRequest->MsgContext = mpi_hdr->MsgContext;
2588 IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
2589 IstwiRWRequest->NumAddressBytes = 0x01;
2590 IstwiRWRequest->DataLength = cpu_to_le16(0x04);
2591 if (pdev->devfn & 1)
2592 IstwiRWRequest->DeviceAddr = 0xB2;
2593 else
2594 IstwiRWRequest->DeviceAddr = 0xB0;
2595
2596 pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
2597 if (!pbuf)
2598 goto out;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302599 ioc->add_sge((char *)&IstwiRWRequest->SGL,
Moore, Eric592f9c22006-02-02 17:19:47 -07002600 (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
2601
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302602 retval = 0;
2603 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
2604 IstwiRWRequest->MsgContext);
2605 INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
Moore, Eric592f9c22006-02-02 17:19:47 -07002606 mpt_put_msg_frame(mptctl_id, ioc, mf);
2607
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302608retry_wait:
2609 timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
2610 HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
2611 if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2612 retval = -ETIME;
2613 printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
2614 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2615 mpt_free_msg_frame(ioc, mf);
2616 goto out;
2617 }
Kei Tokunaga97009a22010-06-22 19:01:51 +09002618 if (!timeleft) {
2619 printk(MYIOC_s_WARN_FMT
2620 "HOST INFO command timeout, doorbell=0x%08x\n",
2621 ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302622 mptctl_timeout_expired(ioc, mf);
Kei Tokunaga97009a22010-06-22 19:01:51 +09002623 } else
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302624 goto retry_wait;
Moore, Eric592f9c22006-02-02 17:19:47 -07002625 goto out;
2626 }
2627
Prakash, Sathya09120a82007-07-24 15:49:05 +05302628 /*
Moore, Eric592f9c22006-02-02 17:19:47 -07002629 *ISTWI Data Definition
2630 * pbuf[0] = FW_VERSION = 0x4
2631 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
2632 * the config, you should be seeing one out of these three values
2633 * pbuf[2] = Drive Installed Map = bit pattern depend on which
2634 * bays have drives in them
2635 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
2636 */
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302637 if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
Moore, Eric592f9c22006-02-02 17:19:47 -07002638 karg.rsvd = *(u32 *)pbuf;
2639
2640 out:
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302641 CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
2642 SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
2643
Moore, Eric592f9c22006-02-02 17:19:47 -07002644 if (pbuf)
2645 pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /* Copy the data from kernel memory to user memory
2648 */
2649 if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002650 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 "Unable to write out hp_host_info @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002652 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return -EFAULT;
2654 }
2655
2656 return 0;
2657
2658}
2659
2660/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Mooreba856d32006-07-11 17:34:01 -06002661/* Prototype Routine for the TARGET INFO command.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 *
2663 * Outputs: None.
2664 * Return: 0 if successful
2665 * -EFAULT if data unavailable
Joe Perchesfc1323b2008-02-03 17:21:01 +02002666 * -EBUSY if previous command timeout and IOC reset is not complete.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 * -ENODEV if no such device/adapter
2668 * -ETIME if timer expires
2669 * -ENOMEM if memory allocation error
2670 */
2671static int
2672mptctl_hp_targetinfo(unsigned long arg)
2673{
2674 hp_target_info_t __user *uarg = (void __user *) arg;
2675 SCSIDevicePage0_t *pg0_alloc;
2676 SCSIDevicePage3_t *pg3_alloc;
2677 MPT_ADAPTER *ioc;
2678 MPT_SCSI_HOST *hd = NULL;
2679 hp_target_info_t karg;
2680 int iocnum;
2681 int data_sz;
2682 dma_addr_t page_dma;
2683 CONFIGPARMS cfg;
2684 ConfigPageHeader_t hdr;
2685 int tmp, np, rc = 0;
2686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002688 printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 "Unable to read in hp_host_targetinfo struct @ %p\n",
2690 __FILE__, __LINE__, uarg);
2691 return -EFAULT;
2692 }
2693
2694 if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
2695 (ioc == NULL)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002696 printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302697 __FILE__, __LINE__, iocnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return -ENODEV;
2699 }
Eric Moore29dd3602007-09-14 18:46:51 -06002700 dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
Prakash, Sathya09120a82007-07-24 15:49:05 +05302701 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
2703 /* There is nothing to do for FCP parts.
2704 */
Moore, Eric9cc1cfb2006-02-02 17:19:33 -07002705 if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 return 0;
2707
2708 if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
2709 return 0;
2710
2711 if (ioc->sh->host_no != karg.hdr.host)
2712 return -ENODEV;
2713
2714 /* Get the data transfer speeds
2715 */
2716 data_sz = ioc->spi_data.sdp0length * 4;
2717 pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
2718 if (pg0_alloc) {
2719 hdr.PageVersion = ioc->spi_data.sdp0version;
2720 hdr.PageLength = data_sz;
2721 hdr.PageNumber = 0;
2722 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
2723
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002724 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2726 cfg.dir = 0;
2727 cfg.timeout = 0;
2728 cfg.physAddr = page_dma;
2729
2730 cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
2731
2732 if ((rc = mpt_config(ioc, &cfg)) == 0) {
2733 np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
2734 karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
2735 HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
2736
2737 if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
2738 tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
2739 if (tmp < 0x09)
2740 karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
2741 else if (tmp <= 0x09)
2742 karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
2743 else if (tmp <= 0x0A)
2744 karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
2745 else if (tmp <= 0x0C)
2746 karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
2747 else if (tmp <= 0x25)
2748 karg.negotiated_speed = HP_DEV_SPEED_FAST;
2749 else
2750 karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
2751 } else
2752 karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
2753 }
2754
2755 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma);
2756 }
2757
2758 /* Set defaults
2759 */
2760 karg.message_rejects = -1;
2761 karg.phase_errors = -1;
2762 karg.parity_errors = -1;
2763 karg.select_timeouts = -1;
2764
2765 /* Get the target error parameters
2766 */
2767 hdr.PageVersion = 0;
2768 hdr.PageLength = 0;
2769 hdr.PageNumber = 3;
2770 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
2771
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002772 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2774 cfg.dir = 0;
2775 cfg.timeout = 0;
2776 cfg.physAddr = -1;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002777 if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 /* Issue the second config page request */
2779 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02002780 data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
2782 ioc->pcidev, data_sz, &page_dma);
2783 if (pg3_alloc) {
2784 cfg.physAddr = page_dma;
2785 cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
2786 if ((rc = mpt_config(ioc, &cfg)) == 0) {
2787 karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
2788 karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
2789 karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
2790 }
2791 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
2792 }
2793 }
Eric Mooree7eae9f2007-09-29 10:15:59 -06002794 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 if (hd != NULL)
2796 karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
2797
2798 /* Copy the data from kernel memory to user memory
2799 */
2800 if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
Eric Moore29dd3602007-09-14 18:46:51 -06002801 printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002803 ioc->name, __FILE__, __LINE__, uarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 return -EFAULT;
2805 }
2806
2807 return 0;
2808}
2809
2810/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2811
Arjan van de Venfa027c22007-02-12 00:55:33 -08002812static const struct file_operations mptctl_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 .owner = THIS_MODULE,
2814 .llseek = no_llseek,
Moore, Ericea5a7a822006-02-02 17:20:01 -07002815 .fasync = mptctl_fasync,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 .unlocked_ioctl = mptctl_ioctl,
2817#ifdef CONFIG_COMPAT
2818 .compat_ioctl = compat_mpctl_ioctl,
2819#endif
2820};
2821
2822static struct miscdevice mptctl_miscdev = {
2823 MPT_MINOR,
2824 MYNAM,
2825 &mptctl_fops
2826};
2827
2828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2829
2830#ifdef CONFIG_COMPAT
2831
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832static int
2833compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
2834 unsigned long arg)
2835{
2836 struct mpt_fw_xfer32 kfw32;
2837 struct mpt_fw_xfer kfw;
2838 MPT_ADAPTER *iocp = NULL;
2839 int iocnum, iocnumX;
2840 int nonblock = (filp->f_flags & O_NONBLOCK);
2841 int ret;
2842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
2845 return -EFAULT;
2846
2847 /* Verify intended MPT adapter */
2848 iocnumX = kfw32.iocnum & 0xFF;
2849 if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
2850 (iocp == NULL)) {
Prakash, Sathya09120a82007-07-24 15:49:05 +05302851 printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002852 __LINE__, iocnumX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 return -ENODEV;
2854 }
2855
2856 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
2857 return ret;
2858
Prakash, Sathya09120a82007-07-24 15:49:05 +05302859 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
2860 iocp->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 kfw.iocnum = iocnum;
2862 kfw.fwlen = kfw32.fwlen;
2863 kfw.bufp = compat_ptr(kfw32.bufp);
2864
2865 ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
2866
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302867 mutex_unlock(&iocp->ioctl_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869 return ret;
2870}
2871
2872static int
2873compat_mpt_command(struct file *filp, unsigned int cmd,
2874 unsigned long arg)
2875{
2876 struct mpt_ioctl_command32 karg32;
2877 struct mpt_ioctl_command32 __user *uarg = (struct mpt_ioctl_command32 __user *) arg;
2878 struct mpt_ioctl_command karg;
2879 MPT_ADAPTER *iocp = NULL;
2880 int iocnum, iocnumX;
2881 int nonblock = (filp->f_flags & O_NONBLOCK);
2882 int ret;
2883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
2885 return -EFAULT;
2886
2887 /* Verify intended MPT adapter */
2888 iocnumX = karg32.hdr.iocnum & 0xFF;
2889 if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
2890 (iocp == NULL)) {
Prakash, Sathya09120a82007-07-24 15:49:05 +05302891 printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002892 __LINE__, iocnumX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return -ENODEV;
2894 }
2895
2896 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
2897 return ret;
2898
Prakash, Sathya09120a82007-07-24 15:49:05 +05302899 dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
2900 iocp->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 /* Copy data to karg */
2902 karg.hdr.iocnum = karg32.hdr.iocnum;
2903 karg.hdr.port = karg32.hdr.port;
2904 karg.timeout = karg32.timeout;
2905 karg.maxReplyBytes = karg32.maxReplyBytes;
2906
2907 karg.dataInSize = karg32.dataInSize;
2908 karg.dataOutSize = karg32.dataOutSize;
2909 karg.maxSenseBytes = karg32.maxSenseBytes;
2910 karg.dataSgeOffset = karg32.dataSgeOffset;
2911
2912 karg.replyFrameBufPtr = (char __user *)(unsigned long)karg32.replyFrameBufPtr;
2913 karg.dataInBufPtr = (char __user *)(unsigned long)karg32.dataInBufPtr;
2914 karg.dataOutBufPtr = (char __user *)(unsigned long)karg32.dataOutBufPtr;
2915 karg.senseDataPtr = (char __user *)(unsigned long)karg32.senseDataPtr;
2916
2917 /* Pass new structure to do_mpt_command
2918 */
2919 ret = mptctl_do_mpt_command (karg, &uarg->MF);
2920
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302921 mutex_unlock(&iocp->ioctl_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 return ret;
2924}
2925
2926static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
2927{
2928 long ret;
2929 lock_kernel();
2930 switch (cmd) {
2931 case MPTIOCINFO:
2932 case MPTIOCINFO1:
2933 case MPTIOCINFO2:
2934 case MPTTARGETINFO:
2935 case MPTEVENTQUERY:
2936 case MPTEVENTENABLE:
2937 case MPTEVENTREPORT:
2938 case MPTHARDRESET:
2939 case HP_GETHOSTINFO:
2940 case HP_GETTARGETINFO:
2941 case MPTTEST:
2942 ret = __mptctl_ioctl(f, cmd, arg);
2943 break;
2944 case MPTCOMMAND32:
2945 ret = compat_mpt_command(f, cmd, arg);
2946 break;
2947 case MPTFWDOWNLOAD32:
2948 ret = compat_mptfwxfer_ioctl(f, cmd, arg);
2949 break;
2950 default:
2951 ret = -ENOIOCTLCMD;
2952 break;
2953 }
2954 unlock_kernel();
2955 return ret;
2956}
2957
2958#endif
2959
2960
2961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2962/*
2963 * mptctl_probe - Installs ioctl devices per bus.
2964 * @pdev: Pointer to pci_dev structure
2965 *
2966 * Returns 0 for success, non-zero for failure.
2967 *
2968 */
2969
2970static int
2971mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2972{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2974
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05302975 mutex_init(&ioc->ioctl_cmds.mutex);
2976 init_completion(&ioc->ioctl_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978}
2979
2980/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2981/*
2982 * mptctl_remove - Removed ioctl devices
2983 * @pdev: Pointer to pci_dev structure
2984 *
2985 *
2986 */
2987static void
2988mptctl_remove(struct pci_dev *pdev)
2989{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990}
2991
2992static struct mpt_pci_driver mptctl_driver = {
2993 .probe = mptctl_probe,
2994 .remove = mptctl_remove,
2995};
2996
2997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2998static int __init mptctl_init(void)
2999{
3000 int err;
3001 int where = 1;
3002
3003 show_mptmod_ver(my_NAME, my_VERSION);
3004
Prakash, Sathya09120a82007-07-24 15:49:05 +05303005 mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006
3007 /* Register this device */
3008 err = misc_register(&mptctl_miscdev);
3009 if (err < 0) {
3010 printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
3011 goto out_fail;
3012 }
3013 printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
3014 printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
3015 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
3016
3017 /*
3018 * Install our handler
3019 */
3020 ++where;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303021 mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
3022 if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
3024 misc_deregister(&mptctl_miscdev);
3025 err = -EBUSY;
3026 goto out_fail;
3027 }
3028
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05303029 mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003030 if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
3031 printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
3032 mpt_deregister(mptctl_id);
3033 misc_deregister(&mptctl_miscdev);
3034 err = -EBUSY;
3035 goto out_fail;
3036 }
3037
Prakash, Sathya09120a82007-07-24 15:49:05 +05303038 mpt_reset_register(mptctl_id, mptctl_ioc_reset);
3039 mpt_event_register(mptctl_id, mptctl_event_process);
Moore, Ericea5a7a822006-02-02 17:20:01 -07003040
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 return 0;
3042
3043out_fail:
3044
3045 mpt_device_driver_deregister(MPTCTL_DRIVER);
3046
3047 return err;
3048}
3049
3050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3051static void mptctl_exit(void)
3052{
3053 misc_deregister(&mptctl_miscdev);
3054 printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
3055 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
3056
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003057 /* De-register event handler from base module */
3058 mpt_event_deregister(mptctl_id);
3059
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 /* De-register reset handler from base module */
3061 mpt_reset_deregister(mptctl_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
3063 /* De-register callback handler from base module */
Kei Tokunaga65c054f2010-03-15 14:48:43 +09003064 mpt_deregister(mptctl_taskmgmt_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 mpt_deregister(mptctl_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
3067 mpt_device_driver_deregister(MPTCTL_DRIVER);
3068
3069}
3070
3071/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3072
3073module_init(mptctl_init);
3074module_exit(mptctl_exit);