diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-28 16:30:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-28 16:30:43 -0400 |
commit | d54b3538b0bfb31351d02d1669d4a978d2abfc5f (patch) | |
tree | 5ce539ecba525b30bbfb1c46c55487099264947e /drivers/scsi/mpt2sas/mpt2sas_ctl.c | |
parent | 5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (diff) | |
parent | af50bb993dfa673cf21ab812efe620d7e0c36319 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (119 commits)
[SCSI] scsi_dh_rdac: Retry for NOT_READY check condition
[SCSI] mpt2sas: make global symbols unique
[SCSI] sd: Make revalidate less chatty
[SCSI] sd: Try READ CAPACITY 16 first for SBC-2 devices
[SCSI] sd: Refactor sd_read_capacity()
[SCSI] mpt2sas v00.100.11.15
[SCSI] mpt2sas: add MPT2SAS_MINOR(221) to miscdevice.h
[SCSI] ch: Add scsi type modalias
[SCSI] 3w-9xxx: add power management support
[SCSI] bsg: add linux/types.h include to bsg.h
[SCSI] cxgb3i: fix function descriptions
[SCSI] libiscsi: fix possbile null ptr session command cleanup
[SCSI] iscsi class: remove host no argument from session creation callout
[SCSI] libiscsi: pass session failure a session struct
[SCSI] iscsi lib: remove qdepth param from iscsi host allocation
[SCSI] iscsi lib: have lib create work queue for transmitting IO
[SCSI] iscsi class: fix lock dep warning on logout
[SCSI] libiscsi: don't cap queue depth in iscsi modules
[SCSI] iscsi_tcp: replace scsi_debug/tcp_debug logging with iscsi conn logging
[SCSI] libiscsi_tcp: replace tcp_debug/scsi_debug logging with session/conn logging
...
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_ctl.c')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 2516 |
1 files changed, 2516 insertions, 0 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c new file mode 100644 index 000000000000..2d4f85c9d7a1 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
@@ -0,0 +1,2516 @@ | |||
1 | /* | ||
2 | * Management Module Support for MPT (Message Passing Technology) based | ||
3 | * controllers | ||
4 | * | ||
5 | * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c | ||
6 | * Copyright (C) 2007-2008 LSI Corporation | ||
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version 2 | ||
12 | * of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * NO WARRANTY | ||
20 | * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR | ||
21 | * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT | ||
22 | * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, | ||
23 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is | ||
24 | * solely responsible for determining the appropriateness of using and | ||
25 | * distributing the Program and assumes all risks associated with its | ||
26 | * exercise of rights under this Agreement, including but not limited to | ||
27 | * the risks and costs of program errors, damage to or loss of data, | ||
28 | * programs or equipment, and unavailability or interruption of operations. | ||
29 | |||
30 | * DISCLAIMER OF LIABILITY | ||
31 | * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY | ||
32 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND | ||
34 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
35 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
36 | * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | ||
37 | * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES | ||
38 | |||
39 | * You should have received a copy of the GNU General Public License | ||
40 | * along with this program; if not, write to the Free Software | ||
41 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
42 | * USA. | ||
43 | */ | ||
44 | |||
45 | #include <linux/version.h> | ||
46 | #include <linux/kernel.h> | ||
47 | #include <linux/module.h> | ||
48 | #include <linux/errno.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/slab.h> | ||
51 | #include <linux/types.h> | ||
52 | #include <linux/pci.h> | ||
53 | #include <linux/delay.h> | ||
54 | #include <linux/smp_lock.h> | ||
55 | #include <linux/compat.h> | ||
56 | #include <linux/poll.h> | ||
57 | |||
58 | #include <linux/io.h> | ||
59 | #include <linux/uaccess.h> | ||
60 | |||
61 | #include "mpt2sas_base.h" | ||
62 | #include "mpt2sas_ctl.h" | ||
63 | |||
64 | static struct fasync_struct *async_queue; | ||
65 | static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); | ||
66 | |||
67 | /** | ||
68 | * enum block_state - blocking state | ||
69 | * @NON_BLOCKING: non blocking | ||
70 | * @BLOCKING: blocking | ||
71 | * | ||
72 | * These states are for ioctls that need to wait for a response | ||
73 | * from firmware, so they probably require sleep. | ||
74 | */ | ||
75 | enum block_state { | ||
76 | NON_BLOCKING, | ||
77 | BLOCKING, | ||
78 | }; | ||
79 | |||
80 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | ||
81 | /** | ||
82 | * _ctl_display_some_debug - debug routine | ||
83 | * @ioc: per adapter object | ||
84 | * @smid: system request message index | ||
85 | * @calling_function_name: string pass from calling function | ||
86 | * @mpi_reply: reply message frame | ||
87 | * Context: none. | ||
88 | * | ||
89 | * Function for displaying debug info helpfull when debugging issues | ||
90 | * in this module. | ||
91 | */ | ||
92 | static void | ||
93 | _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, | ||
94 | char *calling_function_name, MPI2DefaultReply_t *mpi_reply) | ||
95 | { | ||
96 | Mpi2ConfigRequest_t *mpi_request; | ||
97 | char *desc = NULL; | ||
98 | |||
99 | if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) | ||
100 | return; | ||
101 | |||
102 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | ||
103 | switch (mpi_request->Function) { | ||
104 | case MPI2_FUNCTION_SCSI_IO_REQUEST: | ||
105 | { | ||
106 | Mpi2SCSIIORequest_t *scsi_request = | ||
107 | (Mpi2SCSIIORequest_t *)mpi_request; | ||
108 | |||
109 | snprintf(ioc->tmp_string, MPT_STRING_LENGTH, | ||
110 | "scsi_io, cmd(0x%02x), cdb_len(%d)", | ||
111 | scsi_request->CDB.CDB32[0], | ||
112 | le16_to_cpu(scsi_request->IoFlags) & 0xF); | ||
113 | desc = ioc->tmp_string; | ||
114 | break; | ||
115 | } | ||
116 | case MPI2_FUNCTION_SCSI_TASK_MGMT: | ||
117 | desc = "task_mgmt"; | ||
118 | break; | ||
119 | case MPI2_FUNCTION_IOC_INIT: | ||
120 | desc = "ioc_init"; | ||
121 | break; | ||
122 | case MPI2_FUNCTION_IOC_FACTS: | ||
123 | desc = "ioc_facts"; | ||
124 | break; | ||
125 | case MPI2_FUNCTION_CONFIG: | ||
126 | { | ||
127 | Mpi2ConfigRequest_t *config_request = | ||
128 | (Mpi2ConfigRequest_t *)mpi_request; | ||
129 | |||
130 | snprintf(ioc->tmp_string, MPT_STRING_LENGTH, | ||
131 | "config, type(0x%02x), ext_type(0x%02x), number(%d)", | ||
132 | (config_request->Header.PageType & | ||
133 | MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, | ||
134 | config_request->Header.PageNumber); | ||
135 | desc = ioc->tmp_string; | ||
136 | break; | ||
137 | } | ||
138 | case MPI2_FUNCTION_PORT_FACTS: | ||
139 | desc = "port_facts"; | ||
140 | break; | ||
141 | case MPI2_FUNCTION_PORT_ENABLE: | ||
142 | desc = "port_enable"; | ||
143 | break; | ||
144 | case MPI2_FUNCTION_EVENT_NOTIFICATION: | ||
145 | desc = "event_notification"; | ||
146 | break; | ||
147 | case MPI2_FUNCTION_FW_DOWNLOAD: | ||
148 | desc = "fw_download"; | ||
149 | break; | ||
150 | case MPI2_FUNCTION_FW_UPLOAD: | ||
151 | desc = "fw_upload"; | ||
152 | break; | ||
153 | case MPI2_FUNCTION_RAID_ACTION: | ||
154 | desc = "raid_action"; | ||
155 | break; | ||
156 | case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: | ||
157 | { | ||
158 | Mpi2SCSIIORequest_t *scsi_request = | ||
159 | (Mpi2SCSIIORequest_t *)mpi_request; | ||
160 | |||
161 | snprintf(ioc->tmp_string, MPT_STRING_LENGTH, | ||
162 | "raid_pass, cmd(0x%02x), cdb_len(%d)", | ||
163 | scsi_request->CDB.CDB32[0], | ||
164 | le16_to_cpu(scsi_request->IoFlags) & 0xF); | ||
165 | desc = ioc->tmp_string; | ||
166 | break; | ||
167 | } | ||
168 | case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: | ||
169 | desc = "sas_iounit_cntl"; | ||
170 | break; | ||
171 | case MPI2_FUNCTION_SATA_PASSTHROUGH: | ||
172 | desc = "sata_pass"; | ||
173 | break; | ||
174 | case MPI2_FUNCTION_DIAG_BUFFER_POST: | ||
175 | desc = "diag_buffer_post"; | ||
176 | break; | ||
177 | case MPI2_FUNCTION_DIAG_RELEASE: | ||
178 | desc = "diag_release"; | ||
179 | break; | ||
180 | case MPI2_FUNCTION_SMP_PASSTHROUGH: | ||
181 | desc = "smp_passthrough"; | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | if (!desc) | ||
186 | return; | ||
187 | |||
188 | printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n", | ||
189 | ioc->name, calling_function_name, desc, smid); | ||
190 | |||
191 | if (!mpi_reply) | ||
192 | return; | ||
193 | |||
194 | if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) | ||
195 | printk(MPT2SAS_DEBUG_FMT | ||
196 | "\tiocstatus(0x%04x), loginfo(0x%08x)\n", | ||
197 | ioc->name, le16_to_cpu(mpi_reply->IOCStatus), | ||
198 | le32_to_cpu(mpi_reply->IOCLogInfo)); | ||
199 | |||
200 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || | ||
201 | mpi_request->Function == | ||
202 | MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { | ||
203 | Mpi2SCSIIOReply_t *scsi_reply = | ||
204 | (Mpi2SCSIIOReply_t *)mpi_reply; | ||
205 | if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) | ||
206 | printk(MPT2SAS_DEBUG_FMT | ||
207 | "\tscsi_state(0x%02x), scsi_status" | ||
208 | "(0x%02x)\n", ioc->name, | ||
209 | scsi_reply->SCSIState, | ||
210 | scsi_reply->SCSIStatus); | ||
211 | } | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | /** | ||
216 | * mpt2sas_ctl_done - ctl module completion routine | ||
217 | * @ioc: per adapter object | ||
218 | * @smid: system request message index | ||
219 | * @VF_ID: virtual function id | ||
220 | * @reply: reply message frame(lower 32bit addr) | ||
221 | * Context: none. | ||
222 | * | ||
223 | * The callback handler when using ioc->ctl_cb_idx. | ||
224 | * | ||
225 | * Return nothing. | ||
226 | */ | ||
227 | void | ||
228 | mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) | ||
229 | { | ||
230 | MPI2DefaultReply_t *mpi_reply; | ||
231 | |||
232 | if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) | ||
233 | return; | ||
234 | if (ioc->ctl_cmds.smid != smid) | ||
235 | return; | ||
236 | ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE; | ||
237 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); | ||
238 | if (mpi_reply) { | ||
239 | memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); | ||
240 | ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; | ||
241 | } | ||
242 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | ||
243 | _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); | ||
244 | #endif | ||
245 | ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING; | ||
246 | complete(&ioc->ctl_cmds.done); | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * _ctl_check_event_type - determines when an event needs logging | ||
251 | * @ioc: per adapter object | ||
252 | * @event: firmware event | ||
253 | * | ||
254 | * The bitmask in ioc->event_type[] indicates which events should be | ||
255 | * be saved in the driver event_log. This bitmask is set by application. | ||
256 | * | ||
257 | * Returns 1 when event should be captured, or zero means no match. | ||
258 | */ | ||
259 | static int | ||
260 | _ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event) | ||
261 | { | ||
262 | u16 i; | ||
263 | u32 desired_event; | ||
264 | |||
265 | if (event >= 128 || !event || !ioc->event_log) | ||
266 | return 0; | ||
267 | |||
268 | desired_event = (1 << (event % 32)); | ||
269 | if (!desired_event) | ||
270 | desired_event = 1; | ||
271 | i = event / 32; | ||
272 | return desired_event & ioc->event_type[i]; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * mpt2sas_ctl_add_to_event_log - add event | ||
277 | * @ioc: per adapter object | ||
278 | * @mpi_reply: reply message frame | ||
279 | * | ||
280 | * Return nothing. | ||
281 | */ | ||
282 | void | ||
283 | mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, | ||
284 | Mpi2EventNotificationReply_t *mpi_reply) | ||
285 | { | ||
286 | struct MPT2_IOCTL_EVENTS *event_log; | ||
287 | u16 event; | ||
288 | int i; | ||
289 | u32 sz, event_data_sz; | ||
290 | u8 send_aen = 0; | ||
291 | |||
292 | if (!ioc->event_log) | ||
293 | return; | ||
294 | |||
295 | event = le16_to_cpu(mpi_reply->Event); | ||
296 | |||
297 | if (_ctl_check_event_type(ioc, event)) { | ||
298 | |||
299 | /* insert entry into circular event_log */ | ||
300 | i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE; | ||
301 | event_log = ioc->event_log; | ||
302 | event_log[i].event = event; | ||
303 | event_log[i].context = ioc->event_context++; | ||
304 | |||
305 | event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; | ||
306 | sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE); | ||
307 | memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE); | ||
308 | memcpy(event_log[i].data, mpi_reply->EventData, sz); | ||
309 | send_aen = 1; | ||
310 | } | ||
311 | |||
312 | /* This aen_event_read_flag flag is set until the | ||
313 | * application has read the event log. | ||
314 | * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. | ||
315 | */ | ||
316 | if (event == MPI2_EVENT_LOG_ENTRY_ADDED || | ||
317 | (send_aen && !ioc->aen_event_read_flag)) { | ||
318 | ioc->aen_event_read_flag = 1; | ||
319 | wake_up_interruptible(&ctl_poll_wait); | ||
320 | if (async_queue) | ||
321 | kill_fasync(&async_queue, SIGIO, POLL_IN); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) | ||
327 | * @ioc: per adapter object | ||
328 | * @VF_ID: virtual function id | ||
329 | * @reply: reply message frame(lower 32bit addr) | ||
330 | * Context: interrupt. | ||
331 | * | ||
332 | * This function merely adds a new work task into ioc->firmware_event_thread. | ||
333 | * The tasks are worked from _firmware_event_work in user context. | ||
334 | * | ||
335 | * Return nothing. | ||
336 | */ | ||
337 | void | ||
338 | mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) | ||
339 | { | ||
340 | Mpi2EventNotificationReply_t *mpi_reply; | ||
341 | |||
342 | mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); | ||
343 | mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * _ctl_verify_adapter - validates ioc_number passed from application | ||
348 | * @ioc: per adapter object | ||
349 | * @iocpp: The ioc pointer is returned in this. | ||
350 | * | ||
351 | * Return (-1) means error, else ioc_number. | ||
352 | */ | ||
353 | static int | ||
354 | _ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) | ||
355 | { | ||
356 | struct MPT2SAS_ADAPTER *ioc; | ||
357 | |||
358 | list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { | ||
359 | if (ioc->id != ioc_number) | ||
360 | continue; | ||
361 | *iocpp = ioc; | ||
362 | return ioc_number; | ||
363 | } | ||
364 | *iocpp = NULL; | ||
365 | return -1; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) | ||
370 | * @ioc: per adapter object | ||
371 | * @reset_phase: phase | ||
372 | * | ||
373 | * The handler for doing any required cleanup or initialization. | ||
374 | * | ||
375 | * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, | ||
376 | * MPT2_IOC_DONE_RESET | ||
377 | */ | ||
378 | void | ||
379 | mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) | ||
380 | { | ||
381 | switch (reset_phase) { | ||
382 | case MPT2_IOC_PRE_RESET: | ||
383 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | ||
384 | "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); | ||
385 | break; | ||
386 | case MPT2_IOC_AFTER_RESET: | ||
387 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | ||
388 | "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); | ||
389 | if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { | ||
390 | ioc->ctl_cmds.status |= MPT2_CMD_RESET; | ||
391 | mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); | ||
392 | complete(&ioc->ctl_cmds.done); | ||
393 | } | ||
394 | break; | ||
395 | case MPT2_IOC_DONE_RESET: | ||
396 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | ||
397 | "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); | ||
398 | break; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * _ctl_fasync - | ||
404 | * @fd - | ||
405 | * @filep - | ||
406 | * @mode - | ||
407 | * | ||
408 | * Called when application request fasyn callback handler. | ||
409 | */ | ||
410 | static int | ||
411 | _ctl_fasync(int fd, struct file *filep, int mode) | ||
412 | { | ||
413 | return fasync_helper(fd, filep, mode, &async_queue); | ||
414 | } | ||
415 | |||
416 | /** | ||
417 | * _ctl_release - | ||
418 | * @inode - | ||
419 | * @filep - | ||
420 | * | ||
421 | * Called when application releases the fasyn callback handler. | ||
422 | */ | ||
423 | static int | ||
424 | _ctl_release(struct inode *inode, struct file *filep) | ||
425 | { | ||
426 | return fasync_helper(-1, filep, 0, &async_queue); | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * _ctl_poll - | ||
431 | * @file - | ||
432 | * @wait - | ||
433 | * | ||
434 | */ | ||
435 | static unsigned int | ||
436 | _ctl_poll(struct file *filep, poll_table *wait) | ||
437 | { | ||
438 | struct MPT2SAS_ADAPTER *ioc; | ||
439 | |||
440 | poll_wait(filep, &ctl_poll_wait, wait); | ||
441 | |||
442 | list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { | ||
443 | if (ioc->aen_event_read_flag) | ||
444 | return POLLIN | POLLRDNORM; | ||
445 | } | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * _ctl_do_task_abort - assign an active smid to the abort_task | ||
451 | * @ioc: per adapter object | ||
452 | * @karg - (struct mpt2_ioctl_command) | ||
453 | * @tm_request - pointer to mf from user space | ||
454 | * | ||
455 | * Returns 0 when an smid if found, else fail. | ||
456 | * during failure, the reply frame is filled. | ||
457 | */ | ||
458 | static int | ||
459 | _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, | ||
460 | Mpi2SCSITaskManagementRequest_t *tm_request) | ||
461 | { | ||
462 | u8 found = 0; | ||
463 | u16 i; | ||
464 | u16 handle; | ||
465 | struct scsi_cmnd *scmd; | ||
466 | struct MPT2SAS_DEVICE *priv_data; | ||
467 | unsigned long flags; | ||
468 | Mpi2SCSITaskManagementReply_t *tm_reply; | ||
469 | u32 sz; | ||
470 | u32 lun; | ||
471 | |||
472 | lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); | ||
473 | |||
474 | handle = le16_to_cpu(tm_request->DevHandle); | ||
475 | spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); | ||
476 | for (i = ioc->request_depth; i && !found; i--) { | ||
477 | scmd = ioc->scsi_lookup[i - 1].scmd; | ||
478 | if (scmd == NULL || scmd->device == NULL || | ||
479 | scmd->device->hostdata == NULL) | ||
480 | continue; | ||
481 | if (lun != scmd->device->lun) | ||
482 | continue; | ||
483 | priv_data = scmd->device->hostdata; | ||
484 | if (priv_data->sas_target == NULL) | ||
485 | continue; | ||
486 | if (priv_data->sas_target->handle != handle) | ||
487 | continue; | ||
488 | tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); | ||
489 | found = 1; | ||
490 | } | ||
491 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); | ||
492 | |||
493 | if (!found) { | ||
494 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " | ||
495 | "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name, | ||
496 | tm_request->DevHandle, lun)); | ||
497 | tm_reply = ioc->ctl_cmds.reply; | ||
498 | tm_reply->DevHandle = tm_request->DevHandle; | ||
499 | tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; | ||
500 | tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; | ||
501 | tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; | ||
502 | tm_reply->VP_ID = tm_request->VP_ID; | ||
503 | tm_reply->VF_ID = tm_request->VF_ID; | ||
504 | sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); | ||
505 | if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, | ||
506 | sz)) | ||
507 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
508 | __LINE__, __func__); | ||
509 | return 1; | ||
510 | } | ||
511 | |||
512 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " | ||
513 | "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name, | ||
514 | tm_request->DevHandle, lun, tm_request->TaskMID)); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode | ||
520 | * @ioc: per adapter object | ||
521 | * @karg - (struct mpt2_ioctl_command) | ||
522 | * @mf - pointer to mf in user space | ||
523 | * @state - NON_BLOCKING or BLOCKING | ||
524 | */ | ||
525 | static long | ||
526 | _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | ||
527 | struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) | ||
528 | { | ||
529 | MPI2RequestHeader_t *mpi_request; | ||
530 | MPI2DefaultReply_t *mpi_reply; | ||
531 | u32 ioc_state; | ||
532 | u16 ioc_status; | ||
533 | u16 smid; | ||
534 | unsigned long timeout, timeleft; | ||
535 | u8 issue_reset; | ||
536 | u32 sz; | ||
537 | void *psge; | ||
538 | void *priv_sense = NULL; | ||
539 | void *data_out = NULL; | ||
540 | dma_addr_t data_out_dma; | ||
541 | size_t data_out_sz = 0; | ||
542 | void *data_in = NULL; | ||
543 | dma_addr_t data_in_dma; | ||
544 | size_t data_in_sz = 0; | ||
545 | u32 sgl_flags; | ||
546 | long ret; | ||
547 | u16 wait_state_count; | ||
548 | |||
549 | issue_reset = 0; | ||
550 | |||
551 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
552 | return -EAGAIN; | ||
553 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
554 | return -ERESTARTSYS; | ||
555 | |||
556 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { | ||
557 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", | ||
558 | ioc->name, __func__); | ||
559 | ret = -EAGAIN; | ||
560 | goto out; | ||
561 | } | ||
562 | |||
563 | wait_state_count = 0; | ||
564 | ioc_state = mpt2sas_base_get_iocstate(ioc, 1); | ||
565 | while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { | ||
566 | if (wait_state_count++ == 10) { | ||
567 | printk(MPT2SAS_ERR_FMT | ||
568 | "%s: failed due to ioc not operational\n", | ||
569 | ioc->name, __func__); | ||
570 | ret = -EFAULT; | ||
571 | goto out; | ||
572 | } | ||
573 | ssleep(1); | ||
574 | ioc_state = mpt2sas_base_get_iocstate(ioc, 1); | ||
575 | printk(MPT2SAS_INFO_FMT "%s: waiting for " | ||
576 | "operational state(count=%d)\n", ioc->name, | ||
577 | __func__, wait_state_count); | ||
578 | } | ||
579 | if (wait_state_count) | ||
580 | printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", | ||
581 | ioc->name, __func__); | ||
582 | |||
583 | smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); | ||
584 | if (!smid) { | ||
585 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | ||
586 | ioc->name, __func__); | ||
587 | ret = -EAGAIN; | ||
588 | goto out; | ||
589 | } | ||
590 | |||
591 | ret = 0; | ||
592 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; | ||
593 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | ||
594 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | ||
595 | ioc->ctl_cmds.smid = smid; | ||
596 | data_out_sz = karg.data_out_size; | ||
597 | data_in_sz = karg.data_in_size; | ||
598 | |||
599 | /* copy in request message frame from user */ | ||
600 | if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { | ||
601 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, | ||
602 | __func__); | ||
603 | ret = -EFAULT; | ||
604 | mpt2sas_base_free_smid(ioc, smid); | ||
605 | goto out; | ||
606 | } | ||
607 | |||
608 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || | ||
609 | mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { | ||
610 | if (!mpi_request->FunctionDependent1 || | ||
611 | mpi_request->FunctionDependent1 > | ||
612 | cpu_to_le16(ioc->facts.MaxDevHandle)) { | ||
613 | ret = -EINVAL; | ||
614 | mpt2sas_base_free_smid(ioc, smid); | ||
615 | goto out; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | /* obtain dma-able memory for data transfer */ | ||
620 | if (data_out_sz) /* WRITE */ { | ||
621 | data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, | ||
622 | &data_out_dma); | ||
623 | if (!data_out) { | ||
624 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
625 | __LINE__, __func__); | ||
626 | ret = -ENOMEM; | ||
627 | mpt2sas_base_free_smid(ioc, smid); | ||
628 | goto out; | ||
629 | } | ||
630 | if (copy_from_user(data_out, karg.data_out_buf_ptr, | ||
631 | data_out_sz)) { | ||
632 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
633 | __LINE__, __func__); | ||
634 | ret = -EFAULT; | ||
635 | mpt2sas_base_free_smid(ioc, smid); | ||
636 | goto out; | ||
637 | } | ||
638 | } | ||
639 | |||
640 | if (data_in_sz) /* READ */ { | ||
641 | data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, | ||
642 | &data_in_dma); | ||
643 | if (!data_in) { | ||
644 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
645 | __LINE__, __func__); | ||
646 | ret = -ENOMEM; | ||
647 | mpt2sas_base_free_smid(ioc, smid); | ||
648 | goto out; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | /* add scatter gather elements */ | ||
653 | psge = (void *)mpi_request + (karg.data_sge_offset*4); | ||
654 | |||
655 | if (!data_out_sz && !data_in_sz) { | ||
656 | mpt2sas_base_build_zero_len_sge(ioc, psge); | ||
657 | } else if (data_out_sz && data_in_sz) { | ||
658 | /* WRITE sgel first */ | ||
659 | sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | | ||
660 | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); | ||
661 | sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; | ||
662 | ioc->base_add_sg_single(psge, sgl_flags | | ||
663 | data_out_sz, data_out_dma); | ||
664 | |||
665 | /* incr sgel */ | ||
666 | psge += ioc->sge_size; | ||
667 | |||
668 | /* READ sgel last */ | ||
669 | sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | | ||
670 | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | | ||
671 | MPI2_SGE_FLAGS_END_OF_LIST); | ||
672 | sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; | ||
673 | ioc->base_add_sg_single(psge, sgl_flags | | ||
674 | data_in_sz, data_in_dma); | ||
675 | } else if (data_out_sz) /* WRITE */ { | ||
676 | sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | | ||
677 | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | | ||
678 | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); | ||
679 | sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; | ||
680 | ioc->base_add_sg_single(psge, sgl_flags | | ||
681 | data_out_sz, data_out_dma); | ||
682 | } else if (data_in_sz) /* READ */ { | ||
683 | sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | | ||
684 | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | | ||
685 | MPI2_SGE_FLAGS_END_OF_LIST); | ||
686 | sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; | ||
687 | ioc->base_add_sg_single(psge, sgl_flags | | ||
688 | data_in_sz, data_in_dma); | ||
689 | } | ||
690 | |||
691 | /* send command to firmware */ | ||
692 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | ||
693 | _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); | ||
694 | #endif | ||
695 | |||
696 | switch (mpi_request->Function) { | ||
697 | case MPI2_FUNCTION_SCSI_IO_REQUEST: | ||
698 | case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: | ||
699 | { | ||
700 | Mpi2SCSIIORequest_t *scsiio_request = | ||
701 | (Mpi2SCSIIORequest_t *)mpi_request; | ||
702 | scsiio_request->SenseBufferLowAddress = | ||
703 | (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); | ||
704 | priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); | ||
705 | memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
706 | mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, | ||
707 | le16_to_cpu(mpi_request->FunctionDependent1)); | ||
708 | break; | ||
709 | } | ||
710 | case MPI2_FUNCTION_SCSI_TASK_MGMT: | ||
711 | { | ||
712 | Mpi2SCSITaskManagementRequest_t *tm_request = | ||
713 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; | ||
714 | |||
715 | if (tm_request->TaskType == | ||
716 | MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { | ||
717 | if (_ctl_do_task_abort(ioc, &karg, tm_request)) | ||
718 | goto out; | ||
719 | } | ||
720 | |||
721 | mutex_lock(&ioc->tm_cmds.mutex); | ||
722 | mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( | ||
723 | tm_request->DevHandle)); | ||
724 | mpt2sas_base_put_smid_hi_priority(ioc, smid, | ||
725 | mpi_request->VF_ID); | ||
726 | break; | ||
727 | } | ||
728 | case MPI2_FUNCTION_SMP_PASSTHROUGH: | ||
729 | { | ||
730 | Mpi2SmpPassthroughRequest_t *smp_request = | ||
731 | (Mpi2SmpPassthroughRequest_t *)mpi_request; | ||
732 | u8 *data; | ||
733 | |||
734 | /* ioc determines which port to use */ | ||
735 | smp_request->PhysicalPort = 0xFF; | ||
736 | if (smp_request->PassthroughFlags & | ||
737 | MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) | ||
738 | data = (u8 *)&smp_request->SGL; | ||
739 | else | ||
740 | data = data_out; | ||
741 | |||
742 | if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { | ||
743 | ioc->ioc_link_reset_in_progress = 1; | ||
744 | ioc->ignore_loginfos = 1; | ||
745 | } | ||
746 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
747 | break; | ||
748 | } | ||
749 | case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: | ||
750 | { | ||
751 | Mpi2SasIoUnitControlRequest_t *sasiounit_request = | ||
752 | (Mpi2SasIoUnitControlRequest_t *)mpi_request; | ||
753 | |||
754 | if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET | ||
755 | || sasiounit_request->Operation == | ||
756 | MPI2_SAS_OP_PHY_LINK_RESET) { | ||
757 | ioc->ioc_link_reset_in_progress = 1; | ||
758 | ioc->ignore_loginfos = 1; | ||
759 | } | ||
760 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
761 | break; | ||
762 | } | ||
763 | default: | ||
764 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT) | ||
769 | timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; | ||
770 | else | ||
771 | timeout = karg.timeout; | ||
772 | timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, | ||
773 | timeout*HZ); | ||
774 | if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { | ||
775 | Mpi2SCSITaskManagementRequest_t *tm_request = | ||
776 | (Mpi2SCSITaskManagementRequest_t *)mpi_request; | ||
777 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
778 | mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( | ||
779 | tm_request->DevHandle)); | ||
780 | } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || | ||
781 | mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && | ||
782 | ioc->ioc_link_reset_in_progress) { | ||
783 | ioc->ioc_link_reset_in_progress = 0; | ||
784 | ioc->ignore_loginfos = 0; | ||
785 | } | ||
786 | if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { | ||
787 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, | ||
788 | __func__); | ||
789 | _debug_dump_mf(mpi_request, karg.data_sge_offset); | ||
790 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) | ||
791 | issue_reset = 1; | ||
792 | goto issue_host_reset; | ||
793 | } | ||
794 | |||
795 | mpi_reply = ioc->ctl_cmds.reply; | ||
796 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; | ||
797 | |||
798 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | ||
799 | if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && | ||
800 | (ioc->logging_level & MPT_DEBUG_TM)) { | ||
801 | Mpi2SCSITaskManagementReply_t *tm_reply = | ||
802 | (Mpi2SCSITaskManagementReply_t *)mpi_reply; | ||
803 | |||
804 | printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " | ||
805 | "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " | ||
806 | "TerminationCount(0x%08x)\n", ioc->name, | ||
807 | tm_reply->IOCStatus, tm_reply->IOCLogInfo, | ||
808 | tm_reply->TerminationCount); | ||
809 | } | ||
810 | #endif | ||
811 | /* copy out xdata to user */ | ||
812 | if (data_in_sz) { | ||
813 | if (copy_to_user(karg.data_in_buf_ptr, data_in, | ||
814 | data_in_sz)) { | ||
815 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
816 | __LINE__, __func__); | ||
817 | ret = -ENODATA; | ||
818 | goto out; | ||
819 | } | ||
820 | } | ||
821 | |||
822 | /* copy out reply message frame to user */ | ||
823 | if (karg.max_reply_bytes) { | ||
824 | sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); | ||
825 | if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, | ||
826 | sz)) { | ||
827 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
828 | __LINE__, __func__); | ||
829 | ret = -ENODATA; | ||
830 | goto out; | ||
831 | } | ||
832 | } | ||
833 | |||
834 | /* copy out sense to user */ | ||
835 | if (karg.max_sense_bytes && (mpi_request->Function == | ||
836 | MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == | ||
837 | MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { | ||
838 | sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); | ||
839 | if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) { | ||
840 | printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, | ||
841 | __LINE__, __func__); | ||
842 | ret = -ENODATA; | ||
843 | goto out; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | issue_host_reset: | ||
848 | if (issue_reset) { | ||
849 | if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || | ||
850 | mpi_request->Function == | ||
851 | MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { | ||
852 | printk(MPT2SAS_INFO_FMT "issue target reset: handle " | ||
853 | "= (0x%04x)\n", ioc->name, | ||
854 | mpi_request->FunctionDependent1); | ||
855 | mutex_lock(&ioc->tm_cmds.mutex); | ||
856 | mpt2sas_scsih_issue_tm(ioc, | ||
857 | mpi_request->FunctionDependent1, 0, | ||
858 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); | ||
859 | ioc->tm_cmds.status = MPT2_CMD_NOT_USED; | ||
860 | mutex_unlock(&ioc->tm_cmds.mutex); | ||
861 | } else | ||
862 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
863 | FORCE_BIG_HAMMER); | ||
864 | } | ||
865 | |||
866 | out: | ||
867 | |||
868 | /* free memory associated with sg buffers */ | ||
869 | if (data_in) | ||
870 | pci_free_consistent(ioc->pdev, data_in_sz, data_in, | ||
871 | data_in_dma); | ||
872 | |||
873 | if (data_out) | ||
874 | pci_free_consistent(ioc->pdev, data_out_sz, data_out, | ||
875 | data_out_dma); | ||
876 | |||
877 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
878 | mutex_unlock(&ioc->ctl_cmds.mutex); | ||
879 | return ret; | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode | ||
884 | * @arg - user space buffer containing ioctl content | ||
885 | */ | ||
886 | static long | ||
887 | _ctl_getiocinfo(void __user *arg) | ||
888 | { | ||
889 | struct mpt2_ioctl_iocinfo karg; | ||
890 | struct MPT2SAS_ADAPTER *ioc; | ||
891 | u8 revision; | ||
892 | |||
893 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
894 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
895 | __FILE__, __LINE__, __func__); | ||
896 | return -EFAULT; | ||
897 | } | ||
898 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
899 | return -ENODEV; | ||
900 | |||
901 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | ||
902 | __func__)); | ||
903 | |||
904 | memset(&karg, 0 , sizeof(karg)); | ||
905 | karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; | ||
906 | if (ioc->pfacts) | ||
907 | karg.port_number = ioc->pfacts[0].PortNumber; | ||
908 | pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); | ||
909 | karg.hw_rev = revision; | ||
910 | karg.pci_id = ioc->pdev->device; | ||
911 | karg.subsystem_device = ioc->pdev->subsystem_device; | ||
912 | karg.subsystem_vendor = ioc->pdev->subsystem_vendor; | ||
913 | karg.pci_information.u.bits.bus = ioc->pdev->bus->number; | ||
914 | karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); | ||
915 | karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); | ||
916 | karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); | ||
917 | karg.firmware_version = ioc->facts.FWVersion.Word; | ||
918 | strncpy(karg.driver_version, MPT2SAS_DRIVER_VERSION, | ||
919 | MPT2_IOCTL_VERSION_LENGTH); | ||
920 | karg.driver_version[MPT2_IOCTL_VERSION_LENGTH - 1] = '\0'; | ||
921 | karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); | ||
922 | |||
923 | if (copy_to_user(arg, &karg, sizeof(karg))) { | ||
924 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
925 | __FILE__, __LINE__, __func__); | ||
926 | return -EFAULT; | ||
927 | } | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode | ||
933 | * @arg - user space buffer containing ioctl content | ||
934 | */ | ||
935 | static long | ||
936 | _ctl_eventquery(void __user *arg) | ||
937 | { | ||
938 | struct mpt2_ioctl_eventquery karg; | ||
939 | struct MPT2SAS_ADAPTER *ioc; | ||
940 | |||
941 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
942 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
943 | __FILE__, __LINE__, __func__); | ||
944 | return -EFAULT; | ||
945 | } | ||
946 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
947 | return -ENODEV; | ||
948 | |||
949 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | ||
950 | __func__)); | ||
951 | |||
952 | karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; | ||
953 | memcpy(karg.event_types, ioc->event_type, | ||
954 | MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); | ||
955 | |||
956 | if (copy_to_user(arg, &karg, sizeof(karg))) { | ||
957 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
958 | __FILE__, __LINE__, __func__); | ||
959 | return -EFAULT; | ||
960 | } | ||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | /** | ||
965 | * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode | ||
966 | * @arg - user space buffer containing ioctl content | ||
967 | */ | ||
968 | static long | ||
969 | _ctl_eventenable(void __user *arg) | ||
970 | { | ||
971 | struct mpt2_ioctl_eventenable karg; | ||
972 | struct MPT2SAS_ADAPTER *ioc; | ||
973 | |||
974 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
975 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
976 | __FILE__, __LINE__, __func__); | ||
977 | return -EFAULT; | ||
978 | } | ||
979 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
980 | return -ENODEV; | ||
981 | |||
982 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | ||
983 | __func__)); | ||
984 | |||
985 | if (ioc->event_log) | ||
986 | return 0; | ||
987 | memcpy(ioc->event_type, karg.event_types, | ||
988 | MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); | ||
989 | mpt2sas_base_validate_event_type(ioc, ioc->event_type); | ||
990 | |||
991 | /* initialize event_log */ | ||
992 | ioc->event_context = 0; | ||
993 | ioc->aen_event_read_flag = 0; | ||
994 | ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE, | ||
995 | sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL); | ||
996 | if (!ioc->event_log) { | ||
997 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
998 | __FILE__, __LINE__, __func__); | ||
999 | return -ENOMEM; | ||
1000 | } | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | /** | ||
1005 | * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode | ||
1006 | * @arg - user space buffer containing ioctl content | ||
1007 | */ | ||
1008 | static long | ||
1009 | _ctl_eventreport(void __user *arg) | ||
1010 | { | ||
1011 | struct mpt2_ioctl_eventreport karg; | ||
1012 | struct MPT2SAS_ADAPTER *ioc; | ||
1013 | u32 number_bytes, max_events, max; | ||
1014 | struct mpt2_ioctl_eventreport __user *uarg = arg; | ||
1015 | |||
1016 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1017 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1018 | __FILE__, __LINE__, __func__); | ||
1019 | return -EFAULT; | ||
1020 | } | ||
1021 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1022 | return -ENODEV; | ||
1023 | |||
1024 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | ||
1025 | __func__)); | ||
1026 | |||
1027 | number_bytes = karg.hdr.max_data_size - | ||
1028 | sizeof(struct mpt2_ioctl_header); | ||
1029 | max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS); | ||
1030 | max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events); | ||
1031 | |||
1032 | /* If fewer than 1 event is requested, there must have | ||
1033 | * been some type of error. | ||
1034 | */ | ||
1035 | if (!max || !ioc->event_log) | ||
1036 | return -ENODATA; | ||
1037 | |||
1038 | number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS); | ||
1039 | if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { | ||
1040 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1041 | __FILE__, __LINE__, __func__); | ||
1042 | return -EFAULT; | ||
1043 | } | ||
1044 | |||
1045 | /* reset flag so SIGIO can restart */ | ||
1046 | ioc->aen_event_read_flag = 0; | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | /** | ||
1051 | * _ctl_do_reset - main handler for MPT2HARDRESET opcode | ||
1052 | * @arg - user space buffer containing ioctl content | ||
1053 | */ | ||
1054 | static long | ||
1055 | _ctl_do_reset(void __user *arg) | ||
1056 | { | ||
1057 | struct mpt2_ioctl_diag_reset karg; | ||
1058 | struct MPT2SAS_ADAPTER *ioc; | ||
1059 | int retval; | ||
1060 | |||
1061 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1062 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1063 | __FILE__, __LINE__, __func__); | ||
1064 | return -EFAULT; | ||
1065 | } | ||
1066 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1067 | return -ENODEV; | ||
1068 | |||
1069 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, | ||
1070 | __func__)); | ||
1071 | |||
1072 | retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
1073 | FORCE_BIG_HAMMER); | ||
1074 | printk(MPT2SAS_INFO_FMT "host reset: %s\n", | ||
1075 | ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); | ||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | /** | ||
1080 | * _ctl_btdh_search_sas_device - searching for sas device | ||
1081 | * @ioc: per adapter object | ||
1082 | * @btdh: btdh ioctl payload | ||
1083 | */ | ||
1084 | static int | ||
1085 | _ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc, | ||
1086 | struct mpt2_ioctl_btdh_mapping *btdh) | ||
1087 | { | ||
1088 | struct _sas_device *sas_device; | ||
1089 | unsigned long flags; | ||
1090 | int rc = 0; | ||
1091 | |||
1092 | if (list_empty(&ioc->sas_device_list)) | ||
1093 | return rc; | ||
1094 | |||
1095 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | ||
1096 | list_for_each_entry(sas_device, &ioc->sas_device_list, list) { | ||
1097 | if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && | ||
1098 | btdh->handle == sas_device->handle) { | ||
1099 | btdh->bus = sas_device->channel; | ||
1100 | btdh->id = sas_device->id; | ||
1101 | rc = 1; | ||
1102 | goto out; | ||
1103 | } else if (btdh->bus == sas_device->channel && btdh->id == | ||
1104 | sas_device->id && btdh->handle == 0xFFFF) { | ||
1105 | btdh->handle = sas_device->handle; | ||
1106 | rc = 1; | ||
1107 | goto out; | ||
1108 | } | ||
1109 | } | ||
1110 | out: | ||
1111 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
1112 | return rc; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
1116 | * _ctl_btdh_search_raid_device - searching for raid device | ||
1117 | * @ioc: per adapter object | ||
1118 | * @btdh: btdh ioctl payload | ||
1119 | */ | ||
1120 | static int | ||
1121 | _ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc, | ||
1122 | struct mpt2_ioctl_btdh_mapping *btdh) | ||
1123 | { | ||
1124 | struct _raid_device *raid_device; | ||
1125 | unsigned long flags; | ||
1126 | int rc = 0; | ||
1127 | |||
1128 | if (list_empty(&ioc->raid_device_list)) | ||
1129 | return rc; | ||
1130 | |||
1131 | spin_lock_irqsave(&ioc->raid_device_lock, flags); | ||
1132 | list_for_each_entry(raid_device, &ioc->raid_device_list, list) { | ||
1133 | if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && | ||
1134 | btdh->handle == raid_device->handle) { | ||
1135 | btdh->bus = raid_device->channel; | ||
1136 | btdh->id = raid_device->id; | ||
1137 | rc = 1; | ||
1138 | goto out; | ||
1139 | } else if (btdh->bus == raid_device->channel && btdh->id == | ||
1140 | raid_device->id && btdh->handle == 0xFFFF) { | ||
1141 | btdh->handle = raid_device->handle; | ||
1142 | rc = 1; | ||
1143 | goto out; | ||
1144 | } | ||
1145 | } | ||
1146 | out: | ||
1147 | spin_unlock_irqrestore(&ioc->raid_device_lock, flags); | ||
1148 | return rc; | ||
1149 | } | ||
1150 | |||
1151 | /** | ||
1152 | * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode | ||
1153 | * @arg - user space buffer containing ioctl content | ||
1154 | */ | ||
1155 | static long | ||
1156 | _ctl_btdh_mapping(void __user *arg) | ||
1157 | { | ||
1158 | struct mpt2_ioctl_btdh_mapping karg; | ||
1159 | struct MPT2SAS_ADAPTER *ioc; | ||
1160 | int rc; | ||
1161 | |||
1162 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1163 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1164 | __FILE__, __LINE__, __func__); | ||
1165 | return -EFAULT; | ||
1166 | } | ||
1167 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1168 | return -ENODEV; | ||
1169 | |||
1170 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1171 | __func__)); | ||
1172 | |||
1173 | rc = _ctl_btdh_search_sas_device(ioc, &karg); | ||
1174 | if (!rc) | ||
1175 | _ctl_btdh_search_raid_device(ioc, &karg); | ||
1176 | |||
1177 | if (copy_to_user(arg, &karg, sizeof(karg))) { | ||
1178 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1179 | __FILE__, __LINE__, __func__); | ||
1180 | return -EFAULT; | ||
1181 | } | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | /** | ||
1186 | * _ctl_diag_capability - return diag buffer capability | ||
1187 | * @ioc: per adapter object | ||
1188 | * @buffer_type: specifies either TRACE or SNAPSHOT | ||
1189 | * | ||
1190 | * returns 1 when diag buffer support is enabled in firmware | ||
1191 | */ | ||
1192 | static u8 | ||
1193 | _ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) | ||
1194 | { | ||
1195 | u8 rc = 0; | ||
1196 | |||
1197 | switch (buffer_type) { | ||
1198 | case MPI2_DIAG_BUF_TYPE_TRACE: | ||
1199 | if (ioc->facts.IOCCapabilities & | ||
1200 | MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) | ||
1201 | rc = 1; | ||
1202 | break; | ||
1203 | case MPI2_DIAG_BUF_TYPE_SNAPSHOT: | ||
1204 | if (ioc->facts.IOCCapabilities & | ||
1205 | MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) | ||
1206 | rc = 1; | ||
1207 | break; | ||
1208 | } | ||
1209 | |||
1210 | return rc; | ||
1211 | } | ||
1212 | |||
1213 | /** | ||
1214 | * _ctl_diag_register - application register with driver | ||
1215 | * @arg - user space buffer containing ioctl content | ||
1216 | * @state - NON_BLOCKING or BLOCKING | ||
1217 | * | ||
1218 | * This will allow the driver to setup any required buffers that will be | ||
1219 | * needed by firmware to communicate with the driver. | ||
1220 | */ | ||
1221 | static long | ||
1222 | _ctl_diag_register(void __user *arg, enum block_state state) | ||
1223 | { | ||
1224 | struct mpt2_diag_register karg; | ||
1225 | struct MPT2SAS_ADAPTER *ioc; | ||
1226 | int rc, i; | ||
1227 | void *request_data = NULL; | ||
1228 | dma_addr_t request_data_dma; | ||
1229 | u32 request_data_sz = 0; | ||
1230 | Mpi2DiagBufferPostRequest_t *mpi_request; | ||
1231 | Mpi2DiagBufferPostReply_t *mpi_reply; | ||
1232 | u8 buffer_type; | ||
1233 | unsigned long timeleft; | ||
1234 | u16 smid; | ||
1235 | u16 ioc_status; | ||
1236 | u8 issue_reset = 0; | ||
1237 | |||
1238 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1239 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1240 | __FILE__, __LINE__, __func__); | ||
1241 | return -EFAULT; | ||
1242 | } | ||
1243 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1244 | return -ENODEV; | ||
1245 | |||
1246 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1247 | __func__)); | ||
1248 | |||
1249 | buffer_type = karg.buffer_type; | ||
1250 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
1251 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
1252 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1253 | return -EPERM; | ||
1254 | } | ||
1255 | |||
1256 | if (ioc->diag_buffer_status[buffer_type] & | ||
1257 | MPT2_DIAG_BUFFER_IS_REGISTERED) { | ||
1258 | printk(MPT2SAS_ERR_FMT "%s: already has a registered " | ||
1259 | "buffer for buffer_type(0x%02x)\n", ioc->name, __func__, | ||
1260 | buffer_type); | ||
1261 | return -EINVAL; | ||
1262 | } | ||
1263 | |||
1264 | if (karg.requested_buffer_size % 4) { | ||
1265 | printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " | ||
1266 | "is not 4 byte aligned\n", ioc->name, __func__); | ||
1267 | return -EINVAL; | ||
1268 | } | ||
1269 | |||
1270 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
1271 | return -EAGAIN; | ||
1272 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
1273 | return -ERESTARTSYS; | ||
1274 | |||
1275 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { | ||
1276 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", | ||
1277 | ioc->name, __func__); | ||
1278 | rc = -EAGAIN; | ||
1279 | goto out; | ||
1280 | } | ||
1281 | |||
1282 | smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); | ||
1283 | if (!smid) { | ||
1284 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | ||
1285 | ioc->name, __func__); | ||
1286 | rc = -EAGAIN; | ||
1287 | goto out; | ||
1288 | } | ||
1289 | |||
1290 | rc = 0; | ||
1291 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; | ||
1292 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | ||
1293 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | ||
1294 | ioc->ctl_cmds.smid = smid; | ||
1295 | |||
1296 | request_data = ioc->diag_buffer[buffer_type]; | ||
1297 | request_data_sz = karg.requested_buffer_size; | ||
1298 | ioc->unique_id[buffer_type] = karg.unique_id; | ||
1299 | ioc->diag_buffer_status[buffer_type] = 0; | ||
1300 | memcpy(ioc->product_specific[buffer_type], karg.product_specific, | ||
1301 | MPT2_PRODUCT_SPECIFIC_DWORDS); | ||
1302 | ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags; | ||
1303 | |||
1304 | if (request_data) { | ||
1305 | request_data_dma = ioc->diag_buffer_dma[buffer_type]; | ||
1306 | if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { | ||
1307 | pci_free_consistent(ioc->pdev, | ||
1308 | ioc->diag_buffer_sz[buffer_type], | ||
1309 | request_data, request_data_dma); | ||
1310 | request_data = NULL; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | if (request_data == NULL) { | ||
1315 | ioc->diag_buffer_sz[buffer_type] = 0; | ||
1316 | ioc->diag_buffer_dma[buffer_type] = 0; | ||
1317 | request_data = pci_alloc_consistent( | ||
1318 | ioc->pdev, request_data_sz, &request_data_dma); | ||
1319 | if (request_data == NULL) { | ||
1320 | printk(MPT2SAS_ERR_FMT "%s: failed allocating memory" | ||
1321 | " for diag buffers, requested size(%d)\n", | ||
1322 | ioc->name, __func__, request_data_sz); | ||
1323 | mpt2sas_base_free_smid(ioc, smid); | ||
1324 | return -ENOMEM; | ||
1325 | } | ||
1326 | ioc->diag_buffer[buffer_type] = request_data; | ||
1327 | ioc->diag_buffer_sz[buffer_type] = request_data_sz; | ||
1328 | ioc->diag_buffer_dma[buffer_type] = request_data_dma; | ||
1329 | } | ||
1330 | |||
1331 | mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; | ||
1332 | mpi_request->BufferType = karg.buffer_type; | ||
1333 | mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags); | ||
1334 | mpi_request->BufferAddress = cpu_to_le64(request_data_dma); | ||
1335 | mpi_request->BufferLength = cpu_to_le32(request_data_sz); | ||
1336 | |||
1337 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " | ||
1338 | "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, | ||
1339 | (unsigned long long)request_data_dma, mpi_request->BufferLength)); | ||
1340 | |||
1341 | for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) | ||
1342 | mpi_request->ProductSpecific[i] = | ||
1343 | cpu_to_le32(ioc->product_specific[buffer_type][i]); | ||
1344 | |||
1345 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
1346 | timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, | ||
1347 | MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); | ||
1348 | |||
1349 | if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { | ||
1350 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, | ||
1351 | __func__); | ||
1352 | _debug_dump_mf(mpi_request, | ||
1353 | sizeof(Mpi2DiagBufferPostRequest_t)/4); | ||
1354 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) | ||
1355 | issue_reset = 1; | ||
1356 | goto issue_host_reset; | ||
1357 | } | ||
1358 | |||
1359 | /* process the completed Reply Message Frame */ | ||
1360 | if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { | ||
1361 | printk(MPT2SAS_ERR_FMT "%s: no reply message\n", | ||
1362 | ioc->name, __func__); | ||
1363 | rc = -EFAULT; | ||
1364 | goto out; | ||
1365 | } | ||
1366 | |||
1367 | mpi_reply = ioc->ctl_cmds.reply; | ||
1368 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; | ||
1369 | |||
1370 | if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { | ||
1371 | ioc->diag_buffer_status[buffer_type] |= | ||
1372 | MPT2_DIAG_BUFFER_IS_REGISTERED; | ||
1373 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", | ||
1374 | ioc->name, __func__)); | ||
1375 | } else { | ||
1376 | printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " | ||
1377 | "log_info(0x%08x)\n", ioc->name, __func__, | ||
1378 | ioc_status, mpi_reply->IOCLogInfo); | ||
1379 | rc = -EFAULT; | ||
1380 | } | ||
1381 | |||
1382 | issue_host_reset: | ||
1383 | if (issue_reset) | ||
1384 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
1385 | FORCE_BIG_HAMMER); | ||
1386 | |||
1387 | out: | ||
1388 | |||
1389 | if (rc && request_data) | ||
1390 | pci_free_consistent(ioc->pdev, request_data_sz, | ||
1391 | request_data, request_data_dma); | ||
1392 | |||
1393 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
1394 | mutex_unlock(&ioc->ctl_cmds.mutex); | ||
1395 | return rc; | ||
1396 | } | ||
1397 | |||
1398 | /** | ||
1399 | * _ctl_diag_unregister - application unregister with driver | ||
1400 | * @arg - user space buffer containing ioctl content | ||
1401 | * | ||
1402 | * This will allow the driver to cleanup any memory allocated for diag | ||
1403 | * messages and to free up any resources. | ||
1404 | */ | ||
1405 | static long | ||
1406 | _ctl_diag_unregister(void __user *arg) | ||
1407 | { | ||
1408 | struct mpt2_diag_unregister karg; | ||
1409 | struct MPT2SAS_ADAPTER *ioc; | ||
1410 | void *request_data; | ||
1411 | dma_addr_t request_data_dma; | ||
1412 | u32 request_data_sz; | ||
1413 | u8 buffer_type; | ||
1414 | |||
1415 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1416 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1417 | __FILE__, __LINE__, __func__); | ||
1418 | return -EFAULT; | ||
1419 | } | ||
1420 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1421 | return -ENODEV; | ||
1422 | |||
1423 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1424 | __func__)); | ||
1425 | |||
1426 | buffer_type = karg.unique_id & 0x000000ff; | ||
1427 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
1428 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
1429 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1430 | return -EPERM; | ||
1431 | } | ||
1432 | |||
1433 | if ((ioc->diag_buffer_status[buffer_type] & | ||
1434 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
1435 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " | ||
1436 | "registered\n", ioc->name, __func__, buffer_type); | ||
1437 | return -EINVAL; | ||
1438 | } | ||
1439 | if ((ioc->diag_buffer_status[buffer_type] & | ||
1440 | MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { | ||
1441 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been " | ||
1442 | "released\n", ioc->name, __func__, buffer_type); | ||
1443 | return -EINVAL; | ||
1444 | } | ||
1445 | |||
1446 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
1447 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
1448 | "registered\n", ioc->name, __func__, karg.unique_id); | ||
1449 | return -EINVAL; | ||
1450 | } | ||
1451 | |||
1452 | request_data = ioc->diag_buffer[buffer_type]; | ||
1453 | if (!request_data) { | ||
1454 | printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " | ||
1455 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1456 | return -ENOMEM; | ||
1457 | } | ||
1458 | |||
1459 | request_data_sz = ioc->diag_buffer_sz[buffer_type]; | ||
1460 | request_data_dma = ioc->diag_buffer_dma[buffer_type]; | ||
1461 | pci_free_consistent(ioc->pdev, request_data_sz, | ||
1462 | request_data, request_data_dma); | ||
1463 | ioc->diag_buffer[buffer_type] = NULL; | ||
1464 | ioc->diag_buffer_status[buffer_type] = 0; | ||
1465 | return 0; | ||
1466 | } | ||
1467 | |||
1468 | /** | ||
1469 | * _ctl_diag_query - query relevant info associated with diag buffers | ||
1470 | * @arg - user space buffer containing ioctl content | ||
1471 | * | ||
1472 | * The application will send only buffer_type and unique_id. Driver will | ||
1473 | * inspect unique_id first, if valid, fill in all the info. If unique_id is | ||
1474 | * 0x00, the driver will return info specified by Buffer Type. | ||
1475 | */ | ||
1476 | static long | ||
1477 | _ctl_diag_query(void __user *arg) | ||
1478 | { | ||
1479 | struct mpt2_diag_query karg; | ||
1480 | struct MPT2SAS_ADAPTER *ioc; | ||
1481 | void *request_data; | ||
1482 | int i; | ||
1483 | u8 buffer_type; | ||
1484 | |||
1485 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1486 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1487 | __FILE__, __LINE__, __func__); | ||
1488 | return -EFAULT; | ||
1489 | } | ||
1490 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1491 | return -ENODEV; | ||
1492 | |||
1493 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1494 | __func__)); | ||
1495 | |||
1496 | karg.application_flags = 0; | ||
1497 | buffer_type = karg.buffer_type; | ||
1498 | |||
1499 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
1500 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
1501 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1502 | return -EPERM; | ||
1503 | } | ||
1504 | |||
1505 | if ((ioc->diag_buffer_status[buffer_type] & | ||
1506 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
1507 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " | ||
1508 | "registered\n", ioc->name, __func__, buffer_type); | ||
1509 | return -EINVAL; | ||
1510 | } | ||
1511 | |||
1512 | if (karg.unique_id & 0xffffff00) { | ||
1513 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
1514 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
1515 | "registered\n", ioc->name, __func__, | ||
1516 | karg.unique_id); | ||
1517 | return -EINVAL; | ||
1518 | } | ||
1519 | } | ||
1520 | |||
1521 | request_data = ioc->diag_buffer[buffer_type]; | ||
1522 | if (!request_data) { | ||
1523 | printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " | ||
1524 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1525 | return -ENOMEM; | ||
1526 | } | ||
1527 | |||
1528 | if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED) | ||
1529 | karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | | ||
1530 | MPT2_APP_FLAGS_BUFFER_VALID); | ||
1531 | else | ||
1532 | karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | | ||
1533 | MPT2_APP_FLAGS_BUFFER_VALID | | ||
1534 | MPT2_APP_FLAGS_FW_BUFFER_ACCESS); | ||
1535 | |||
1536 | for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) | ||
1537 | karg.product_specific[i] = | ||
1538 | ioc->product_specific[buffer_type][i]; | ||
1539 | |||
1540 | karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; | ||
1541 | karg.driver_added_buffer_size = 0; | ||
1542 | karg.unique_id = ioc->unique_id[buffer_type]; | ||
1543 | karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; | ||
1544 | |||
1545 | if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) { | ||
1546 | printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query " | ||
1547 | "data @ %p\n", ioc->name, __func__, arg); | ||
1548 | return -EFAULT; | ||
1549 | } | ||
1550 | return 0; | ||
1551 | } | ||
1552 | |||
1553 | /** | ||
1554 | * _ctl_diag_release - request to send Diag Release Message to firmware | ||
1555 | * @arg - user space buffer containing ioctl content | ||
1556 | * @state - NON_BLOCKING or BLOCKING | ||
1557 | * | ||
1558 | * This allows ownership of the specified buffer to returned to the driver, | ||
1559 | * allowing an application to read the buffer without fear that firmware is | ||
1560 | * overwritting information in the buffer. | ||
1561 | */ | ||
1562 | static long | ||
1563 | _ctl_diag_release(void __user *arg, enum block_state state) | ||
1564 | { | ||
1565 | struct mpt2_diag_release karg; | ||
1566 | struct MPT2SAS_ADAPTER *ioc; | ||
1567 | void *request_data; | ||
1568 | int rc; | ||
1569 | Mpi2DiagReleaseRequest_t *mpi_request; | ||
1570 | Mpi2DiagReleaseReply_t *mpi_reply; | ||
1571 | u8 buffer_type; | ||
1572 | unsigned long timeleft; | ||
1573 | u16 smid; | ||
1574 | u16 ioc_status; | ||
1575 | u8 issue_reset = 0; | ||
1576 | |||
1577 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1578 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1579 | __FILE__, __LINE__, __func__); | ||
1580 | return -EFAULT; | ||
1581 | } | ||
1582 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1583 | return -ENODEV; | ||
1584 | |||
1585 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1586 | __func__)); | ||
1587 | |||
1588 | buffer_type = karg.unique_id & 0x000000ff; | ||
1589 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
1590 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
1591 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1592 | return -EPERM; | ||
1593 | } | ||
1594 | |||
1595 | if ((ioc->diag_buffer_status[buffer_type] & | ||
1596 | MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { | ||
1597 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " | ||
1598 | "registered\n", ioc->name, __func__, buffer_type); | ||
1599 | return -EINVAL; | ||
1600 | } | ||
1601 | |||
1602 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
1603 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
1604 | "registered\n", ioc->name, __func__, karg.unique_id); | ||
1605 | return -EINVAL; | ||
1606 | } | ||
1607 | |||
1608 | if (ioc->diag_buffer_status[buffer_type] & | ||
1609 | MPT2_DIAG_BUFFER_IS_RELEASED) { | ||
1610 | printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " | ||
1611 | "is already released\n", ioc->name, __func__, | ||
1612 | buffer_type); | ||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | request_data = ioc->diag_buffer[buffer_type]; | ||
1617 | |||
1618 | if (!request_data) { | ||
1619 | printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " | ||
1620 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1621 | return -ENOMEM; | ||
1622 | } | ||
1623 | |||
1624 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
1625 | return -EAGAIN; | ||
1626 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
1627 | return -ERESTARTSYS; | ||
1628 | |||
1629 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { | ||
1630 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", | ||
1631 | ioc->name, __func__); | ||
1632 | rc = -EAGAIN; | ||
1633 | goto out; | ||
1634 | } | ||
1635 | |||
1636 | smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); | ||
1637 | if (!smid) { | ||
1638 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | ||
1639 | ioc->name, __func__); | ||
1640 | rc = -EAGAIN; | ||
1641 | goto out; | ||
1642 | } | ||
1643 | |||
1644 | rc = 0; | ||
1645 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; | ||
1646 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | ||
1647 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | ||
1648 | ioc->ctl_cmds.smid = smid; | ||
1649 | |||
1650 | mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; | ||
1651 | mpi_request->BufferType = buffer_type; | ||
1652 | |||
1653 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
1654 | timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, | ||
1655 | MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); | ||
1656 | |||
1657 | if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { | ||
1658 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, | ||
1659 | __func__); | ||
1660 | _debug_dump_mf(mpi_request, | ||
1661 | sizeof(Mpi2DiagReleaseRequest_t)/4); | ||
1662 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) | ||
1663 | issue_reset = 1; | ||
1664 | goto issue_host_reset; | ||
1665 | } | ||
1666 | |||
1667 | /* process the completed Reply Message Frame */ | ||
1668 | if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { | ||
1669 | printk(MPT2SAS_ERR_FMT "%s: no reply message\n", | ||
1670 | ioc->name, __func__); | ||
1671 | rc = -EFAULT; | ||
1672 | goto out; | ||
1673 | } | ||
1674 | |||
1675 | mpi_reply = ioc->ctl_cmds.reply; | ||
1676 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; | ||
1677 | |||
1678 | if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { | ||
1679 | ioc->diag_buffer_status[buffer_type] |= | ||
1680 | MPT2_DIAG_BUFFER_IS_RELEASED; | ||
1681 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", | ||
1682 | ioc->name, __func__)); | ||
1683 | } else { | ||
1684 | printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " | ||
1685 | "log_info(0x%08x)\n", ioc->name, __func__, | ||
1686 | ioc_status, mpi_reply->IOCLogInfo); | ||
1687 | rc = -EFAULT; | ||
1688 | } | ||
1689 | |||
1690 | issue_host_reset: | ||
1691 | if (issue_reset) | ||
1692 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
1693 | FORCE_BIG_HAMMER); | ||
1694 | |||
1695 | out: | ||
1696 | |||
1697 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
1698 | mutex_unlock(&ioc->ctl_cmds.mutex); | ||
1699 | return rc; | ||
1700 | } | ||
1701 | |||
1702 | /** | ||
1703 | * _ctl_diag_read_buffer - request for copy of the diag buffer | ||
1704 | * @arg - user space buffer containing ioctl content | ||
1705 | * @state - NON_BLOCKING or BLOCKING | ||
1706 | */ | ||
1707 | static long | ||
1708 | _ctl_diag_read_buffer(void __user *arg, enum block_state state) | ||
1709 | { | ||
1710 | struct mpt2_diag_read_buffer karg; | ||
1711 | struct mpt2_diag_read_buffer __user *uarg = arg; | ||
1712 | struct MPT2SAS_ADAPTER *ioc; | ||
1713 | void *request_data, *diag_data; | ||
1714 | Mpi2DiagBufferPostRequest_t *mpi_request; | ||
1715 | Mpi2DiagBufferPostReply_t *mpi_reply; | ||
1716 | int rc, i; | ||
1717 | u8 buffer_type; | ||
1718 | unsigned long timeleft; | ||
1719 | u16 smid; | ||
1720 | u16 ioc_status; | ||
1721 | u8 issue_reset = 0; | ||
1722 | |||
1723 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1724 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1725 | __FILE__, __LINE__, __func__); | ||
1726 | return -EFAULT; | ||
1727 | } | ||
1728 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
1729 | return -ENODEV; | ||
1730 | |||
1731 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | ||
1732 | __func__)); | ||
1733 | |||
1734 | buffer_type = karg.unique_id & 0x000000ff; | ||
1735 | if (!_ctl_diag_capability(ioc, buffer_type)) { | ||
1736 | printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " | ||
1737 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1738 | return -EPERM; | ||
1739 | } | ||
1740 | |||
1741 | if (karg.unique_id != ioc->unique_id[buffer_type]) { | ||
1742 | printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " | ||
1743 | "registered\n", ioc->name, __func__, karg.unique_id); | ||
1744 | return -EINVAL; | ||
1745 | } | ||
1746 | |||
1747 | request_data = ioc->diag_buffer[buffer_type]; | ||
1748 | if (!request_data) { | ||
1749 | printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " | ||
1750 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); | ||
1751 | return -ENOMEM; | ||
1752 | } | ||
1753 | |||
1754 | if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { | ||
1755 | printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " | ||
1756 | "or bytes_to_read are not 4 byte aligned\n", ioc->name, | ||
1757 | __func__); | ||
1758 | return -EINVAL; | ||
1759 | } | ||
1760 | |||
1761 | diag_data = (void *)(request_data + karg.starting_offset); | ||
1762 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), " | ||
1763 | "offset(%d), sz(%d)\n", ioc->name, __func__, | ||
1764 | diag_data, karg.starting_offset, karg.bytes_to_read)); | ||
1765 | |||
1766 | if (copy_to_user((void __user *)uarg->diagnostic_data, | ||
1767 | diag_data, karg.bytes_to_read)) { | ||
1768 | printk(MPT2SAS_ERR_FMT "%s: Unable to write " | ||
1769 | "mpt_diag_read_buffer_t data @ %p\n", ioc->name, | ||
1770 | __func__, diag_data); | ||
1771 | return -EFAULT; | ||
1772 | } | ||
1773 | |||
1774 | if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) | ||
1775 | return 0; | ||
1776 | |||
1777 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister " | ||
1778 | "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); | ||
1779 | if ((ioc->diag_buffer_status[buffer_type] & | ||
1780 | MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { | ||
1781 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " | ||
1782 | "buffer_type(0x%02x) is still registered\n", ioc->name, | ||
1783 | __func__, buffer_type)); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | /* Get a free request frame and save the message context. | ||
1787 | */ | ||
1788 | if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) | ||
1789 | return -EAGAIN; | ||
1790 | else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) | ||
1791 | return -ERESTARTSYS; | ||
1792 | |||
1793 | if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { | ||
1794 | printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", | ||
1795 | ioc->name, __func__); | ||
1796 | rc = -EAGAIN; | ||
1797 | goto out; | ||
1798 | } | ||
1799 | |||
1800 | smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); | ||
1801 | if (!smid) { | ||
1802 | printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", | ||
1803 | ioc->name, __func__); | ||
1804 | rc = -EAGAIN; | ||
1805 | goto out; | ||
1806 | } | ||
1807 | |||
1808 | rc = 0; | ||
1809 | ioc->ctl_cmds.status = MPT2_CMD_PENDING; | ||
1810 | memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | ||
1811 | mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); | ||
1812 | ioc->ctl_cmds.smid = smid; | ||
1813 | |||
1814 | mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; | ||
1815 | mpi_request->BufferType = buffer_type; | ||
1816 | mpi_request->BufferLength = | ||
1817 | cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); | ||
1818 | mpi_request->BufferAddress = | ||
1819 | cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); | ||
1820 | for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) | ||
1821 | mpi_request->ProductSpecific[i] = | ||
1822 | cpu_to_le32(ioc->product_specific[buffer_type][i]); | ||
1823 | |||
1824 | mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); | ||
1825 | timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, | ||
1826 | MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); | ||
1827 | |||
1828 | if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { | ||
1829 | printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, | ||
1830 | __func__); | ||
1831 | _debug_dump_mf(mpi_request, | ||
1832 | sizeof(Mpi2DiagBufferPostRequest_t)/4); | ||
1833 | if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) | ||
1834 | issue_reset = 1; | ||
1835 | goto issue_host_reset; | ||
1836 | } | ||
1837 | |||
1838 | /* process the completed Reply Message Frame */ | ||
1839 | if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { | ||
1840 | printk(MPT2SAS_ERR_FMT "%s: no reply message\n", | ||
1841 | ioc->name, __func__); | ||
1842 | rc = -EFAULT; | ||
1843 | goto out; | ||
1844 | } | ||
1845 | |||
1846 | mpi_reply = ioc->ctl_cmds.reply; | ||
1847 | ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; | ||
1848 | |||
1849 | if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { | ||
1850 | ioc->diag_buffer_status[buffer_type] |= | ||
1851 | MPT2_DIAG_BUFFER_IS_REGISTERED; | ||
1852 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", | ||
1853 | ioc->name, __func__)); | ||
1854 | } else { | ||
1855 | printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " | ||
1856 | "log_info(0x%08x)\n", ioc->name, __func__, | ||
1857 | ioc_status, mpi_reply->IOCLogInfo); | ||
1858 | rc = -EFAULT; | ||
1859 | } | ||
1860 | |||
1861 | issue_host_reset: | ||
1862 | if (issue_reset) | ||
1863 | mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
1864 | FORCE_BIG_HAMMER); | ||
1865 | |||
1866 | out: | ||
1867 | |||
1868 | ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; | ||
1869 | mutex_unlock(&ioc->ctl_cmds.mutex); | ||
1870 | return rc; | ||
1871 | } | ||
1872 | |||
1873 | /** | ||
1874 | * _ctl_ioctl_main - main ioctl entry point | ||
1875 | * @file - (struct file) | ||
1876 | * @cmd - ioctl opcode | ||
1877 | * @arg - | ||
1878 | */ | ||
1879 | static long | ||
1880 | _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) | ||
1881 | { | ||
1882 | enum block_state state; | ||
1883 | long ret = -EINVAL; | ||
1884 | unsigned long flags; | ||
1885 | |||
1886 | state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : | ||
1887 | BLOCKING; | ||
1888 | |||
1889 | switch (cmd) { | ||
1890 | case MPT2IOCINFO: | ||
1891 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) | ||
1892 | ret = _ctl_getiocinfo(arg); | ||
1893 | break; | ||
1894 | case MPT2COMMAND: | ||
1895 | { | ||
1896 | struct mpt2_ioctl_command karg; | ||
1897 | struct mpt2_ioctl_command __user *uarg; | ||
1898 | struct MPT2SAS_ADAPTER *ioc; | ||
1899 | |||
1900 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1901 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1902 | __FILE__, __LINE__, __func__); | ||
1903 | return -EFAULT; | ||
1904 | } | ||
1905 | |||
1906 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || | ||
1907 | !ioc) | ||
1908 | return -ENODEV; | ||
1909 | |||
1910 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); | ||
1911 | if (ioc->shost_recovery) { | ||
1912 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, | ||
1913 | flags); | ||
1914 | return -EAGAIN; | ||
1915 | } | ||
1916 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); | ||
1917 | |||
1918 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { | ||
1919 | uarg = arg; | ||
1920 | ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); | ||
1921 | } | ||
1922 | break; | ||
1923 | } | ||
1924 | case MPT2EVENTQUERY: | ||
1925 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) | ||
1926 | ret = _ctl_eventquery(arg); | ||
1927 | break; | ||
1928 | case MPT2EVENTENABLE: | ||
1929 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) | ||
1930 | ret = _ctl_eventenable(arg); | ||
1931 | break; | ||
1932 | case MPT2EVENTREPORT: | ||
1933 | ret = _ctl_eventreport(arg); | ||
1934 | break; | ||
1935 | case MPT2HARDRESET: | ||
1936 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) | ||
1937 | ret = _ctl_do_reset(arg); | ||
1938 | break; | ||
1939 | case MPT2BTDHMAPPING: | ||
1940 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) | ||
1941 | ret = _ctl_btdh_mapping(arg); | ||
1942 | break; | ||
1943 | case MPT2DIAGREGISTER: | ||
1944 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) | ||
1945 | ret = _ctl_diag_register(arg, state); | ||
1946 | break; | ||
1947 | case MPT2DIAGUNREGISTER: | ||
1948 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) | ||
1949 | ret = _ctl_diag_unregister(arg); | ||
1950 | break; | ||
1951 | case MPT2DIAGQUERY: | ||
1952 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) | ||
1953 | ret = _ctl_diag_query(arg); | ||
1954 | break; | ||
1955 | case MPT2DIAGRELEASE: | ||
1956 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) | ||
1957 | ret = _ctl_diag_release(arg, state); | ||
1958 | break; | ||
1959 | case MPT2DIAGREADBUFFER: | ||
1960 | if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) | ||
1961 | ret = _ctl_diag_read_buffer(arg, state); | ||
1962 | break; | ||
1963 | default: | ||
1964 | { | ||
1965 | struct mpt2_ioctl_command karg; | ||
1966 | struct MPT2SAS_ADAPTER *ioc; | ||
1967 | |||
1968 | if (copy_from_user(&karg, arg, sizeof(karg))) { | ||
1969 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
1970 | __FILE__, __LINE__, __func__); | ||
1971 | return -EFAULT; | ||
1972 | } | ||
1973 | |||
1974 | if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || | ||
1975 | !ioc) | ||
1976 | return -ENODEV; | ||
1977 | |||
1978 | dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT | ||
1979 | "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); | ||
1980 | break; | ||
1981 | } | ||
1982 | } | ||
1983 | return ret; | ||
1984 | } | ||
1985 | |||
1986 | /** | ||
1987 | * _ctl_ioctl - main ioctl entry point (unlocked) | ||
1988 | * @file - (struct file) | ||
1989 | * @cmd - ioctl opcode | ||
1990 | * @arg - | ||
1991 | */ | ||
1992 | static long | ||
1993 | _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
1994 | { | ||
1995 | long ret; | ||
1996 | lock_kernel(); | ||
1997 | ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); | ||
1998 | unlock_kernel(); | ||
1999 | return ret; | ||
2000 | } | ||
2001 | |||
2002 | #ifdef CONFIG_COMPAT | ||
2003 | /** | ||
2004 | * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. | ||
2005 | * @file - (struct file) | ||
2006 | * @cmd - ioctl opcode | ||
2007 | * @arg - (struct mpt2_ioctl_command32) | ||
2008 | * | ||
2009 | * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. | ||
2010 | */ | ||
2011 | static long | ||
2012 | _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) | ||
2013 | { | ||
2014 | struct mpt2_ioctl_command32 karg32; | ||
2015 | struct mpt2_ioctl_command32 __user *uarg; | ||
2016 | struct mpt2_ioctl_command karg; | ||
2017 | struct MPT2SAS_ADAPTER *ioc; | ||
2018 | enum block_state state; | ||
2019 | unsigned long flags; | ||
2020 | |||
2021 | if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) | ||
2022 | return -EINVAL; | ||
2023 | |||
2024 | uarg = (struct mpt2_ioctl_command32 __user *) arg; | ||
2025 | |||
2026 | if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { | ||
2027 | printk(KERN_ERR "failure at %s:%d/%s()!\n", | ||
2028 | __FILE__, __LINE__, __func__); | ||
2029 | return -EFAULT; | ||
2030 | } | ||
2031 | if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) | ||
2032 | return -ENODEV; | ||
2033 | |||
2034 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); | ||
2035 | if (ioc->shost_recovery) { | ||
2036 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, | ||
2037 | flags); | ||
2038 | return -EAGAIN; | ||
2039 | } | ||
2040 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); | ||
2041 | |||
2042 | memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); | ||
2043 | karg.hdr.ioc_number = karg32.hdr.ioc_number; | ||
2044 | karg.hdr.port_number = karg32.hdr.port_number; | ||
2045 | karg.hdr.max_data_size = karg32.hdr.max_data_size; | ||
2046 | karg.timeout = karg32.timeout; | ||
2047 | karg.max_reply_bytes = karg32.max_reply_bytes; | ||
2048 | karg.data_in_size = karg32.data_in_size; | ||
2049 | karg.data_out_size = karg32.data_out_size; | ||
2050 | karg.max_sense_bytes = karg32.max_sense_bytes; | ||
2051 | karg.data_sge_offset = karg32.data_sge_offset; | ||
2052 | memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr, | ||
2053 | sizeof(uint32_t)); | ||
2054 | memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr, | ||
2055 | sizeof(uint32_t)); | ||
2056 | memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr, | ||
2057 | sizeof(uint32_t)); | ||
2058 | memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr, | ||
2059 | sizeof(uint32_t)); | ||
2060 | state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; | ||
2061 | return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); | ||
2062 | } | ||
2063 | |||
2064 | /** | ||
2065 | * _ctl_ioctl_compat - main ioctl entry point (compat) | ||
2066 | * @file - | ||
2067 | * @cmd - | ||
2068 | * @arg - | ||
2069 | * | ||
2070 | * This routine handles 32 bit applications in 64bit os. | ||
2071 | */ | ||
2072 | static long | ||
2073 | _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) | ||
2074 | { | ||
2075 | long ret; | ||
2076 | lock_kernel(); | ||
2077 | if (cmd == MPT2COMMAND32) | ||
2078 | ret = _ctl_compat_mpt_command(file, cmd, arg); | ||
2079 | else | ||
2080 | ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); | ||
2081 | unlock_kernel(); | ||
2082 | return ret; | ||
2083 | } | ||
2084 | #endif | ||
2085 | |||
2086 | /* scsi host attributes */ | ||
2087 | |||
2088 | /** | ||
2089 | * _ctl_version_fw_show - firmware version | ||
2090 | * @cdev - pointer to embedded class device | ||
2091 | * @buf - the buffer returned | ||
2092 | * | ||
2093 | * A sysfs 'read-only' shost attribute. | ||
2094 | */ | ||
2095 | static ssize_t | ||
2096 | _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, | ||
2097 | char *buf) | ||
2098 | { | ||
2099 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2100 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2101 | |||
2102 | return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", | ||
2103 | (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, | ||
2104 | (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, | ||
2105 | (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, | ||
2106 | ioc->facts.FWVersion.Word & 0x000000FF); | ||
2107 | } | ||
2108 | static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); | ||
2109 | |||
2110 | /** | ||
2111 | * _ctl_version_bios_show - bios version | ||
2112 | * @cdev - pointer to embedded class device | ||
2113 | * @buf - the buffer returned | ||
2114 | * | ||
2115 | * A sysfs 'read-only' shost attribute. | ||
2116 | */ | ||
2117 | static ssize_t | ||
2118 | _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, | ||
2119 | char *buf) | ||
2120 | { | ||
2121 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2122 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2123 | |||
2124 | u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); | ||
2125 | |||
2126 | return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", | ||
2127 | (version & 0xFF000000) >> 24, | ||
2128 | (version & 0x00FF0000) >> 16, | ||
2129 | (version & 0x0000FF00) >> 8, | ||
2130 | version & 0x000000FF); | ||
2131 | } | ||
2132 | static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); | ||
2133 | |||
2134 | /** | ||
2135 | * _ctl_version_mpi_show - MPI (message passing interface) version | ||
2136 | * @cdev - pointer to embedded class device | ||
2137 | * @buf - the buffer returned | ||
2138 | * | ||
2139 | * A sysfs 'read-only' shost attribute. | ||
2140 | */ | ||
2141 | static ssize_t | ||
2142 | _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, | ||
2143 | char *buf) | ||
2144 | { | ||
2145 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2146 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2147 | |||
2148 | return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", | ||
2149 | ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); | ||
2150 | } | ||
2151 | static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); | ||
2152 | |||
2153 | /** | ||
2154 | * _ctl_version_product_show - product name | ||
2155 | * @cdev - pointer to embedded class device | ||
2156 | * @buf - the buffer returned | ||
2157 | * | ||
2158 | * A sysfs 'read-only' shost attribute. | ||
2159 | */ | ||
2160 | static ssize_t | ||
2161 | _ctl_version_product_show(struct device *cdev, struct device_attribute *attr, | ||
2162 | char *buf) | ||
2163 | { | ||
2164 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2165 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2166 | |||
2167 | return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); | ||
2168 | } | ||
2169 | static DEVICE_ATTR(version_product, S_IRUGO, | ||
2170 | _ctl_version_product_show, NULL); | ||
2171 | |||
2172 | /** | ||
2173 | * _ctl_version_nvdata_persistent_show - ndvata persistent version | ||
2174 | * @cdev - pointer to embedded class device | ||
2175 | * @buf - the buffer returned | ||
2176 | * | ||
2177 | * A sysfs 'read-only' shost attribute. | ||
2178 | */ | ||
2179 | static ssize_t | ||
2180 | _ctl_version_nvdata_persistent_show(struct device *cdev, | ||
2181 | struct device_attribute *attr, char *buf) | ||
2182 | { | ||
2183 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2184 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2185 | |||
2186 | return snprintf(buf, PAGE_SIZE, "%02xh\n", | ||
2187 | le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); | ||
2188 | } | ||
2189 | static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, | ||
2190 | _ctl_version_nvdata_persistent_show, NULL); | ||
2191 | |||
2192 | /** | ||
2193 | * _ctl_version_nvdata_default_show - nvdata default version | ||
2194 | * @cdev - pointer to embedded class device | ||
2195 | * @buf - the buffer returned | ||
2196 | * | ||
2197 | * A sysfs 'read-only' shost attribute. | ||
2198 | */ | ||
2199 | static ssize_t | ||
2200 | _ctl_version_nvdata_default_show(struct device *cdev, | ||
2201 | struct device_attribute *attr, char *buf) | ||
2202 | { | ||
2203 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2204 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2205 | |||
2206 | return snprintf(buf, PAGE_SIZE, "%02xh\n", | ||
2207 | le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); | ||
2208 | } | ||
2209 | static DEVICE_ATTR(version_nvdata_default, S_IRUGO, | ||
2210 | _ctl_version_nvdata_default_show, NULL); | ||
2211 | |||
2212 | /** | ||
2213 | * _ctl_board_name_show - board name | ||
2214 | * @cdev - pointer to embedded class device | ||
2215 | * @buf - the buffer returned | ||
2216 | * | ||
2217 | * A sysfs 'read-only' shost attribute. | ||
2218 | */ | ||
2219 | static ssize_t | ||
2220 | _ctl_board_name_show(struct device *cdev, struct device_attribute *attr, | ||
2221 | char *buf) | ||
2222 | { | ||
2223 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2224 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2225 | |||
2226 | return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); | ||
2227 | } | ||
2228 | static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); | ||
2229 | |||
2230 | /** | ||
2231 | * _ctl_board_assembly_show - board assembly name | ||
2232 | * @cdev - pointer to embedded class device | ||
2233 | * @buf - the buffer returned | ||
2234 | * | ||
2235 | * A sysfs 'read-only' shost attribute. | ||
2236 | */ | ||
2237 | static ssize_t | ||
2238 | _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, | ||
2239 | char *buf) | ||
2240 | { | ||
2241 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2242 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2243 | |||
2244 | return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); | ||
2245 | } | ||
2246 | static DEVICE_ATTR(board_assembly, S_IRUGO, | ||
2247 | _ctl_board_assembly_show, NULL); | ||
2248 | |||
2249 | /** | ||
2250 | * _ctl_board_tracer_show - board tracer number | ||
2251 | * @cdev - pointer to embedded class device | ||
2252 | * @buf - the buffer returned | ||
2253 | * | ||
2254 | * A sysfs 'read-only' shost attribute. | ||
2255 | */ | ||
2256 | static ssize_t | ||
2257 | _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, | ||
2258 | char *buf) | ||
2259 | { | ||
2260 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2261 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2262 | |||
2263 | return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); | ||
2264 | } | ||
2265 | static DEVICE_ATTR(board_tracer, S_IRUGO, | ||
2266 | _ctl_board_tracer_show, NULL); | ||
2267 | |||
2268 | /** | ||
2269 | * _ctl_io_delay_show - io missing delay | ||
2270 | * @cdev - pointer to embedded class device | ||
2271 | * @buf - the buffer returned | ||
2272 | * | ||
2273 | * This is for firmware implemention for deboucing device | ||
2274 | * removal events. | ||
2275 | * | ||
2276 | * A sysfs 'read-only' shost attribute. | ||
2277 | */ | ||
2278 | static ssize_t | ||
2279 | _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, | ||
2280 | char *buf) | ||
2281 | { | ||
2282 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2283 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2284 | |||
2285 | return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); | ||
2286 | } | ||
2287 | static DEVICE_ATTR(io_delay, S_IRUGO, | ||
2288 | _ctl_io_delay_show, NULL); | ||
2289 | |||
2290 | /** | ||
2291 | * _ctl_device_delay_show - device missing delay | ||
2292 | * @cdev - pointer to embedded class device | ||
2293 | * @buf - the buffer returned | ||
2294 | * | ||
2295 | * This is for firmware implemention for deboucing device | ||
2296 | * removal events. | ||
2297 | * | ||
2298 | * A sysfs 'read-only' shost attribute. | ||
2299 | */ | ||
2300 | static ssize_t | ||
2301 | _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, | ||
2302 | char *buf) | ||
2303 | { | ||
2304 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2305 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2306 | |||
2307 | return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); | ||
2308 | } | ||
2309 | static DEVICE_ATTR(device_delay, S_IRUGO, | ||
2310 | _ctl_device_delay_show, NULL); | ||
2311 | |||
2312 | /** | ||
2313 | * _ctl_fw_queue_depth_show - global credits | ||
2314 | * @cdev - pointer to embedded class device | ||
2315 | * @buf - the buffer returned | ||
2316 | * | ||
2317 | * This is firmware queue depth limit | ||
2318 | * | ||
2319 | * A sysfs 'read-only' shost attribute. | ||
2320 | */ | ||
2321 | static ssize_t | ||
2322 | _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, | ||
2323 | char *buf) | ||
2324 | { | ||
2325 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2326 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2327 | |||
2328 | return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); | ||
2329 | } | ||
2330 | static DEVICE_ATTR(fw_queue_depth, S_IRUGO, | ||
2331 | _ctl_fw_queue_depth_show, NULL); | ||
2332 | |||
2333 | /** | ||
2334 | * _ctl_sas_address_show - sas address | ||
2335 | * @cdev - pointer to embedded class device | ||
2336 | * @buf - the buffer returned | ||
2337 | * | ||
2338 | * This is the controller sas address | ||
2339 | * | ||
2340 | * A sysfs 'read-only' shost attribute. | ||
2341 | */ | ||
2342 | static ssize_t | ||
2343 | _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, | ||
2344 | char *buf) | ||
2345 | { | ||
2346 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2347 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2348 | |||
2349 | return snprintf(buf, PAGE_SIZE, "0x%016llx\n", | ||
2350 | (unsigned long long)ioc->sas_hba.sas_address); | ||
2351 | } | ||
2352 | static DEVICE_ATTR(host_sas_address, S_IRUGO, | ||
2353 | _ctl_host_sas_address_show, NULL); | ||
2354 | |||
2355 | /** | ||
2356 | * _ctl_logging_level_show - logging level | ||
2357 | * @cdev - pointer to embedded class device | ||
2358 | * @buf - the buffer returned | ||
2359 | * | ||
2360 | * A sysfs 'read/write' shost attribute. | ||
2361 | */ | ||
2362 | static ssize_t | ||
2363 | _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, | ||
2364 | char *buf) | ||
2365 | { | ||
2366 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2367 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2368 | |||
2369 | return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); | ||
2370 | } | ||
2371 | static ssize_t | ||
2372 | _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, | ||
2373 | const char *buf, size_t count) | ||
2374 | { | ||
2375 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2376 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2377 | int val = 0; | ||
2378 | |||
2379 | if (sscanf(buf, "%x", &val) != 1) | ||
2380 | return -EINVAL; | ||
2381 | |||
2382 | ioc->logging_level = val; | ||
2383 | printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name, | ||
2384 | ioc->logging_level); | ||
2385 | return strlen(buf); | ||
2386 | } | ||
2387 | static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, | ||
2388 | _ctl_logging_level_show, _ctl_logging_level_store); | ||
2389 | |||
2390 | struct device_attribute *mpt2sas_host_attrs[] = { | ||
2391 | &dev_attr_version_fw, | ||
2392 | &dev_attr_version_bios, | ||
2393 | &dev_attr_version_mpi, | ||
2394 | &dev_attr_version_product, | ||
2395 | &dev_attr_version_nvdata_persistent, | ||
2396 | &dev_attr_version_nvdata_default, | ||
2397 | &dev_attr_board_name, | ||
2398 | &dev_attr_board_assembly, | ||
2399 | &dev_attr_board_tracer, | ||
2400 | &dev_attr_io_delay, | ||
2401 | &dev_attr_device_delay, | ||
2402 | &dev_attr_logging_level, | ||
2403 | &dev_attr_fw_queue_depth, | ||
2404 | &dev_attr_host_sas_address, | ||
2405 | NULL, | ||
2406 | }; | ||
2407 | |||
2408 | /* device attributes */ | ||
2409 | |||
2410 | /** | ||
2411 | * _ctl_device_sas_address_show - sas address | ||
2412 | * @cdev - pointer to embedded class device | ||
2413 | * @buf - the buffer returned | ||
2414 | * | ||
2415 | * This is the sas address for the target | ||
2416 | * | ||
2417 | * A sysfs 'read-only' shost attribute. | ||
2418 | */ | ||
2419 | static ssize_t | ||
2420 | _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, | ||
2421 | char *buf) | ||
2422 | { | ||
2423 | struct scsi_device *sdev = to_scsi_device(dev); | ||
2424 | struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; | ||
2425 | |||
2426 | return snprintf(buf, PAGE_SIZE, "0x%016llx\n", | ||
2427 | (unsigned long long)sas_device_priv_data->sas_target->sas_address); | ||
2428 | } | ||
2429 | static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); | ||
2430 | |||
2431 | /** | ||
2432 | * _ctl_device_handle_show - device handle | ||
2433 | * @cdev - pointer to embedded class device | ||
2434 | * @buf - the buffer returned | ||
2435 | * | ||
2436 | * This is the firmware assigned device handle | ||
2437 | * | ||
2438 | * A sysfs 'read-only' shost attribute. | ||
2439 | */ | ||
2440 | static ssize_t | ||
2441 | _ctl_device_handle_show(struct device *dev, struct device_attribute *attr, | ||
2442 | char *buf) | ||
2443 | { | ||
2444 | struct scsi_device *sdev = to_scsi_device(dev); | ||
2445 | struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; | ||
2446 | |||
2447 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", | ||
2448 | sas_device_priv_data->sas_target->handle); | ||
2449 | } | ||
2450 | static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); | ||
2451 | |||
2452 | struct device_attribute *mpt2sas_dev_attrs[] = { | ||
2453 | &dev_attr_sas_address, | ||
2454 | &dev_attr_sas_device_handle, | ||
2455 | NULL, | ||
2456 | }; | ||
2457 | |||
2458 | static const struct file_operations ctl_fops = { | ||
2459 | .owner = THIS_MODULE, | ||
2460 | .unlocked_ioctl = _ctl_ioctl, | ||
2461 | .release = _ctl_release, | ||
2462 | .poll = _ctl_poll, | ||
2463 | .fasync = _ctl_fasync, | ||
2464 | #ifdef CONFIG_COMPAT | ||
2465 | .compat_ioctl = _ctl_ioctl_compat, | ||
2466 | #endif | ||
2467 | }; | ||
2468 | |||
2469 | static struct miscdevice ctl_dev = { | ||
2470 | .minor = MPT2SAS_MINOR, | ||
2471 | .name = MPT2SAS_DEV_NAME, | ||
2472 | .fops = &ctl_fops, | ||
2473 | }; | ||
2474 | |||
2475 | /** | ||
2476 | * mpt2sas_ctl_init - main entry point for ctl. | ||
2477 | * | ||
2478 | */ | ||
2479 | void | ||
2480 | mpt2sas_ctl_init(void) | ||
2481 | { | ||
2482 | async_queue = NULL; | ||
2483 | if (misc_register(&ctl_dev) < 0) | ||
2484 | printk(KERN_ERR "%s can't register misc device [minor=%d]\n", | ||
2485 | MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); | ||
2486 | |||
2487 | init_waitqueue_head(&ctl_poll_wait); | ||
2488 | } | ||
2489 | |||
2490 | /** | ||
2491 | * mpt2sas_ctl_exit - exit point for ctl | ||
2492 | * | ||
2493 | */ | ||
2494 | void | ||
2495 | mpt2sas_ctl_exit(void) | ||
2496 | { | ||
2497 | struct MPT2SAS_ADAPTER *ioc; | ||
2498 | int i; | ||
2499 | |||
2500 | list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { | ||
2501 | |||
2502 | /* free memory associated to diag buffers */ | ||
2503 | for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { | ||
2504 | if (!ioc->diag_buffer[i]) | ||
2505 | continue; | ||
2506 | pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], | ||
2507 | ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); | ||
2508 | ioc->diag_buffer[i] = NULL; | ||
2509 | ioc->diag_buffer_status[i] = 0; | ||
2510 | } | ||
2511 | |||
2512 | kfree(ioc->event_log); | ||
2513 | } | ||
2514 | misc_deregister(&ctl_dev); | ||
2515 | } | ||
2516 | |||