diff options
author | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:15 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:59 -0400 |
commit | 07f9479a40cc778bc1462ada11f95b01360ae4ff (patch) | |
tree | 0676cf38df3844004bb3ebfd99dfa67a4a8998f5 /drivers/target | |
parent | 9d5e6bdb3013acfb311ab407eeca0b6a6a3dedbf (diff) | |
parent | cd2e49e90f1cae7726c9a2c54488d881d7f1cd1c (diff) |
Merge branch 'master' into for-next
Fast-forwarded to current state of Linus' tree as there are patches to be
applied for files that didn't exist on the old branch.
Diffstat (limited to 'drivers/target')
22 files changed, 3904 insertions, 152 deletions
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 2fac3be209ac..9ef2dbbfa62b 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig | |||
@@ -29,4 +29,6 @@ config TCM_PSCSI | |||
29 | Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered | 29 | Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered |
30 | passthrough access to Linux/SCSI device | 30 | passthrough access to Linux/SCSI device |
31 | 31 | ||
32 | source "drivers/target/loopback/Kconfig" | ||
33 | |||
32 | endif | 34 | endif |
diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 973bb190ef57..1178bbfc68fe 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ | ||
2 | 1 | ||
3 | target_core_mod-y := target_core_configfs.o \ | 2 | target_core_mod-y := target_core_configfs.o \ |
4 | target_core_device.o \ | 3 | target_core_device.o \ |
@@ -13,7 +12,8 @@ target_core_mod-y := target_core_configfs.o \ | |||
13 | target_core_transport.o \ | 12 | target_core_transport.o \ |
14 | target_core_cdb.o \ | 13 | target_core_cdb.o \ |
15 | target_core_ua.o \ | 14 | target_core_ua.o \ |
16 | target_core_rd.o | 15 | target_core_rd.o \ |
16 | target_core_stat.o | ||
17 | 17 | ||
18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | 18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o |
19 | 19 | ||
@@ -21,3 +21,6 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | |||
21 | obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o | 21 | obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o |
22 | obj-$(CONFIG_TCM_FILEIO) += target_core_file.o | 22 | obj-$(CONFIG_TCM_FILEIO) += target_core_file.o |
23 | obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o | 23 | obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o |
24 | |||
25 | # Fabric modules | ||
26 | obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ | ||
diff --git a/drivers/target/loopback/Kconfig b/drivers/target/loopback/Kconfig new file mode 100644 index 000000000000..57dcbc2d711b --- /dev/null +++ b/drivers/target/loopback/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config LOOPBACK_TARGET | ||
2 | tristate "TCM Virtual SAS target and Linux/SCSI LDD fabric loopback module" | ||
3 | help | ||
4 | Say Y here to enable the TCM Virtual SAS target and Linux/SCSI LLD | ||
5 | fabric loopback module. | ||
6 | |||
7 | config LOOPBACK_TARGET_CDB_DEBUG | ||
8 | bool "TCM loopback fabric module CDB debug code" | ||
9 | depends on LOOPBACK_TARGET | ||
10 | help | ||
11 | Say Y here to enable the TCM loopback fabric module CDB debug code | ||
diff --git a/drivers/target/loopback/Makefile b/drivers/target/loopback/Makefile new file mode 100644 index 000000000000..6abebdf95659 --- /dev/null +++ b/drivers/target/loopback/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_LOOPBACK_TARGET) += tcm_loop.o | |||
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c new file mode 100644 index 000000000000..aed4e464d31c --- /dev/null +++ b/drivers/target/loopback/tcm_loop.c | |||
@@ -0,0 +1,1579 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * This file contains the Linux/SCSI LLD virtual SCSI initiator driver | ||
4 | * for emulated SAS initiator ports | ||
5 | * | ||
6 | * © Copyright 2011 RisingTide Systems LLC. | ||
7 | * | ||
8 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
9 | * | ||
10 | * Author: Nicholas A. Bellinger <nab@risingtidesystems.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/configfs.h> | ||
29 | #include <scsi/scsi.h> | ||
30 | #include <scsi/scsi_tcq.h> | ||
31 | #include <scsi/scsi_host.h> | ||
32 | #include <scsi/scsi_device.h> | ||
33 | #include <scsi/scsi_cmnd.h> | ||
34 | #include <scsi/libsas.h> /* For TASK_ATTR_* */ | ||
35 | |||
36 | #include <target/target_core_base.h> | ||
37 | #include <target/target_core_transport.h> | ||
38 | #include <target/target_core_fabric_ops.h> | ||
39 | #include <target/target_core_fabric_configfs.h> | ||
40 | #include <target/target_core_fabric_lib.h> | ||
41 | #include <target/target_core_configfs.h> | ||
42 | #include <target/target_core_device.h> | ||
43 | #include <target/target_core_tpg.h> | ||
44 | #include <target/target_core_tmr.h> | ||
45 | |||
46 | #include "tcm_loop.h" | ||
47 | |||
48 | #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) | ||
49 | |||
50 | /* Local pointer to allocated TCM configfs fabric module */ | ||
51 | static struct target_fabric_configfs *tcm_loop_fabric_configfs; | ||
52 | |||
53 | static struct kmem_cache *tcm_loop_cmd_cache; | ||
54 | |||
55 | static int tcm_loop_hba_no_cnt; | ||
56 | |||
57 | /* | ||
58 | * Allocate a tcm_loop cmd descriptor from target_core_mod code | ||
59 | * | ||
60 | * Can be called from interrupt context in tcm_loop_queuecommand() below | ||
61 | */ | ||
62 | static struct se_cmd *tcm_loop_allocate_core_cmd( | ||
63 | struct tcm_loop_hba *tl_hba, | ||
64 | struct se_portal_group *se_tpg, | ||
65 | struct scsi_cmnd *sc) | ||
66 | { | ||
67 | struct se_cmd *se_cmd; | ||
68 | struct se_session *se_sess; | ||
69 | struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; | ||
70 | struct tcm_loop_cmd *tl_cmd; | ||
71 | int sam_task_attr; | ||
72 | |||
73 | if (!tl_nexus) { | ||
74 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" | ||
75 | " does not exist\n"); | ||
76 | set_host_byte(sc, DID_ERROR); | ||
77 | return NULL; | ||
78 | } | ||
79 | se_sess = tl_nexus->se_sess; | ||
80 | |||
81 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); | ||
82 | if (!tl_cmd) { | ||
83 | printk(KERN_ERR "Unable to allocate struct tcm_loop_cmd\n"); | ||
84 | set_host_byte(sc, DID_ERROR); | ||
85 | return NULL; | ||
86 | } | ||
87 | se_cmd = &tl_cmd->tl_se_cmd; | ||
88 | /* | ||
89 | * Save the pointer to struct scsi_cmnd *sc | ||
90 | */ | ||
91 | tl_cmd->sc = sc; | ||
92 | /* | ||
93 | * Locate the SAM Task Attr from struct scsi_cmnd * | ||
94 | */ | ||
95 | if (sc->device->tagged_supported) { | ||
96 | switch (sc->tag) { | ||
97 | case HEAD_OF_QUEUE_TAG: | ||
98 | sam_task_attr = TASK_ATTR_HOQ; | ||
99 | break; | ||
100 | case ORDERED_QUEUE_TAG: | ||
101 | sam_task_attr = TASK_ATTR_ORDERED; | ||
102 | break; | ||
103 | default: | ||
104 | sam_task_attr = TASK_ATTR_SIMPLE; | ||
105 | break; | ||
106 | } | ||
107 | } else | ||
108 | sam_task_attr = TASK_ATTR_SIMPLE; | ||
109 | |||
110 | /* | ||
111 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | ||
112 | */ | ||
113 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, | ||
114 | scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, | ||
115 | &tl_cmd->tl_sense_buf[0]); | ||
116 | |||
117 | /* | ||
118 | * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi | ||
119 | */ | ||
120 | if (scsi_bidi_cmnd(sc)) | ||
121 | T_TASK(se_cmd)->t_tasks_bidi = 1; | ||
122 | /* | ||
123 | * Locate the struct se_lun pointer and attach it to struct se_cmd | ||
124 | */ | ||
125 | if (transport_get_lun_for_cmd(se_cmd, NULL, tl_cmd->sc->device->lun) < 0) { | ||
126 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
127 | set_host_byte(sc, DID_NO_CONNECT); | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | transport_device_setup_cmd(se_cmd); | ||
132 | return se_cmd; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Called by struct target_core_fabric_ops->new_cmd_map() | ||
137 | * | ||
138 | * Always called in process context. A non zero return value | ||
139 | * here will signal to handle an exception based on the return code. | ||
140 | */ | ||
141 | static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) | ||
142 | { | ||
143 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
144 | struct tcm_loop_cmd, tl_se_cmd); | ||
145 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
146 | void *mem_ptr, *mem_bidi_ptr = NULL; | ||
147 | u32 sg_no_bidi = 0; | ||
148 | int ret; | ||
149 | /* | ||
150 | * Allocate the necessary tasks to complete the received CDB+data | ||
151 | */ | ||
152 | ret = transport_generic_allocate_tasks(se_cmd, tl_cmd->sc->cmnd); | ||
153 | if (ret == -1) { | ||
154 | /* Out of Resources */ | ||
155 | return PYX_TRANSPORT_LU_COMM_FAILURE; | ||
156 | } else if (ret == -2) { | ||
157 | /* | ||
158 | * Handle case for SAM_STAT_RESERVATION_CONFLICT | ||
159 | */ | ||
160 | if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) | ||
161 | return PYX_TRANSPORT_RESERVATION_CONFLICT; | ||
162 | /* | ||
163 | * Otherwise, return SAM_STAT_CHECK_CONDITION and return | ||
164 | * sense data. | ||
165 | */ | ||
166 | return PYX_TRANSPORT_USE_SENSE_REASON; | ||
167 | } | ||
168 | /* | ||
169 | * Setup the struct scatterlist memory from the received | ||
170 | * struct scsi_cmnd. | ||
171 | */ | ||
172 | if (scsi_sg_count(sc)) { | ||
173 | se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM; | ||
174 | mem_ptr = (void *)scsi_sglist(sc); | ||
175 | /* | ||
176 | * For BIDI commands, pass in the extra READ buffer | ||
177 | * to transport_generic_map_mem_to_cmd() below.. | ||
178 | */ | ||
179 | if (T_TASK(se_cmd)->t_tasks_bidi) { | ||
180 | struct scsi_data_buffer *sdb = scsi_in(sc); | ||
181 | |||
182 | mem_bidi_ptr = (void *)sdb->table.sgl; | ||
183 | sg_no_bidi = sdb->table.nents; | ||
184 | } | ||
185 | } else { | ||
186 | /* | ||
187 | * Used for DMA_NONE | ||
188 | */ | ||
189 | mem_ptr = NULL; | ||
190 | } | ||
191 | /* | ||
192 | * Map the SG memory into struct se_mem->page linked list using the same | ||
193 | * physical memory at sg->page_link. | ||
194 | */ | ||
195 | ret = transport_generic_map_mem_to_cmd(se_cmd, mem_ptr, | ||
196 | scsi_sg_count(sc), mem_bidi_ptr, sg_no_bidi); | ||
197 | if (ret < 0) | ||
198 | return PYX_TRANSPORT_LU_COMM_FAILURE; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Called from struct target_core_fabric_ops->check_stop_free() | ||
205 | */ | ||
206 | static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) | ||
207 | { | ||
208 | /* | ||
209 | * Do not release struct se_cmd's containing a valid TMR | ||
210 | * pointer. These will be released directly in tcm_loop_device_reset() | ||
211 | * with transport_generic_free_cmd(). | ||
212 | */ | ||
213 | if (se_cmd->se_tmr_req) | ||
214 | return; | ||
215 | /* | ||
216 | * Release the struct se_cmd, which will make a callback to release | ||
217 | * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() | ||
218 | */ | ||
219 | transport_generic_free_cmd(se_cmd, 0, 1, 0); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Called from struct target_core_fabric_ops->release_cmd_to_pool() | ||
224 | */ | ||
225 | static void tcm_loop_deallocate_core_cmd(struct se_cmd *se_cmd) | ||
226 | { | ||
227 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
228 | struct tcm_loop_cmd, tl_se_cmd); | ||
229 | |||
230 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
231 | } | ||
232 | |||
233 | static int tcm_loop_proc_info(struct Scsi_Host *host, char *buffer, | ||
234 | char **start, off_t offset, | ||
235 | int length, int inout) | ||
236 | { | ||
237 | return sprintf(buffer, "tcm_loop_proc_info()\n"); | ||
238 | } | ||
239 | |||
240 | static int tcm_loop_driver_probe(struct device *); | ||
241 | static int tcm_loop_driver_remove(struct device *); | ||
242 | |||
243 | static int pseudo_lld_bus_match(struct device *dev, | ||
244 | struct device_driver *dev_driver) | ||
245 | { | ||
246 | return 1; | ||
247 | } | ||
248 | |||
249 | static struct bus_type tcm_loop_lld_bus = { | ||
250 | .name = "tcm_loop_bus", | ||
251 | .match = pseudo_lld_bus_match, | ||
252 | .probe = tcm_loop_driver_probe, | ||
253 | .remove = tcm_loop_driver_remove, | ||
254 | }; | ||
255 | |||
256 | static struct device_driver tcm_loop_driverfs = { | ||
257 | .name = "tcm_loop", | ||
258 | .bus = &tcm_loop_lld_bus, | ||
259 | }; | ||
260 | /* | ||
261 | * Used with root_device_register() in tcm_loop_alloc_core_bus() below | ||
262 | */ | ||
263 | struct device *tcm_loop_primary; | ||
264 | |||
265 | /* | ||
266 | * Copied from drivers/scsi/libfc/fc_fcp.c:fc_change_queue_depth() and | ||
267 | * drivers/scsi/libiscsi.c:iscsi_change_queue_depth() | ||
268 | */ | ||
269 | static int tcm_loop_change_queue_depth( | ||
270 | struct scsi_device *sdev, | ||
271 | int depth, | ||
272 | int reason) | ||
273 | { | ||
274 | switch (reason) { | ||
275 | case SCSI_QDEPTH_DEFAULT: | ||
276 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
277 | break; | ||
278 | case SCSI_QDEPTH_QFULL: | ||
279 | scsi_track_queue_full(sdev, depth); | ||
280 | break; | ||
281 | case SCSI_QDEPTH_RAMP_UP: | ||
282 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
283 | break; | ||
284 | default: | ||
285 | return -EOPNOTSUPP; | ||
286 | } | ||
287 | return sdev->queue_depth; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Main entry point from struct scsi_host_template for incoming SCSI CDB+Data | ||
292 | * from Linux/SCSI subsystem for SCSI low level device drivers (LLDs) | ||
293 | */ | ||
294 | static int tcm_loop_queuecommand( | ||
295 | struct Scsi_Host *sh, | ||
296 | struct scsi_cmnd *sc) | ||
297 | { | ||
298 | struct se_cmd *se_cmd; | ||
299 | struct se_portal_group *se_tpg; | ||
300 | struct tcm_loop_hba *tl_hba; | ||
301 | struct tcm_loop_tpg *tl_tpg; | ||
302 | |||
303 | TL_CDB_DEBUG("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x" | ||
304 | " scsi_buf_len: %u\n", sc->device->host->host_no, | ||
305 | sc->device->id, sc->device->channel, sc->device->lun, | ||
306 | sc->cmnd[0], scsi_bufflen(sc)); | ||
307 | /* | ||
308 | * Locate the tcm_loop_hba_t pointer | ||
309 | */ | ||
310 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | ||
311 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | ||
312 | se_tpg = &tl_tpg->tl_se_tpg; | ||
313 | /* | ||
314 | * Determine the SAM Task Attribute and allocate tl_cmd and | ||
315 | * tl_cmd->tl_se_cmd from TCM infrastructure | ||
316 | */ | ||
317 | se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc); | ||
318 | if (!se_cmd) { | ||
319 | sc->scsi_done(sc); | ||
320 | return 0; | ||
321 | } | ||
322 | /* | ||
323 | * Queue up the newly allocated to be processed in TCM thread context. | ||
324 | */ | ||
325 | transport_generic_handle_cdb_map(se_cmd); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Called from SCSI EH process context to issue a LUN_RESET TMR | ||
331 | * to struct scsi_device | ||
332 | */ | ||
333 | static int tcm_loop_device_reset(struct scsi_cmnd *sc) | ||
334 | { | ||
335 | struct se_cmd *se_cmd = NULL; | ||
336 | struct se_portal_group *se_tpg; | ||
337 | struct se_session *se_sess; | ||
338 | struct tcm_loop_cmd *tl_cmd = NULL; | ||
339 | struct tcm_loop_hba *tl_hba; | ||
340 | struct tcm_loop_nexus *tl_nexus; | ||
341 | struct tcm_loop_tmr *tl_tmr = NULL; | ||
342 | struct tcm_loop_tpg *tl_tpg; | ||
343 | int ret = FAILED; | ||
344 | /* | ||
345 | * Locate the tcm_loop_hba_t pointer | ||
346 | */ | ||
347 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | ||
348 | /* | ||
349 | * Locate the tl_nexus and se_sess pointers | ||
350 | */ | ||
351 | tl_nexus = tl_hba->tl_nexus; | ||
352 | if (!tl_nexus) { | ||
353 | printk(KERN_ERR "Unable to perform device reset without" | ||
354 | " active I_T Nexus\n"); | ||
355 | return FAILED; | ||
356 | } | ||
357 | se_sess = tl_nexus->se_sess; | ||
358 | /* | ||
359 | * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id | ||
360 | */ | ||
361 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | ||
362 | se_tpg = &tl_tpg->tl_se_tpg; | ||
363 | |||
364 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); | ||
365 | if (!tl_cmd) { | ||
366 | printk(KERN_ERR "Unable to allocate memory for tl_cmd\n"); | ||
367 | return FAILED; | ||
368 | } | ||
369 | |||
370 | tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL); | ||
371 | if (!tl_tmr) { | ||
372 | printk(KERN_ERR "Unable to allocate memory for tl_tmr\n"); | ||
373 | goto release; | ||
374 | } | ||
375 | init_waitqueue_head(&tl_tmr->tl_tmr_wait); | ||
376 | |||
377 | se_cmd = &tl_cmd->tl_se_cmd; | ||
378 | /* | ||
379 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | ||
380 | */ | ||
381 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, | ||
382 | DMA_NONE, TASK_ATTR_SIMPLE, | ||
383 | &tl_cmd->tl_sense_buf[0]); | ||
384 | /* | ||
385 | * Allocate the LUN_RESET TMR | ||
386 | */ | ||
387 | se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, (void *)tl_tmr, | ||
388 | TMR_LUN_RESET); | ||
389 | if (!se_cmd->se_tmr_req) | ||
390 | goto release; | ||
391 | /* | ||
392 | * Locate the underlying TCM struct se_lun from sc->device->lun | ||
393 | */ | ||
394 | if (transport_get_lun_for_tmr(se_cmd, sc->device->lun) < 0) | ||
395 | goto release; | ||
396 | /* | ||
397 | * Queue the TMR to TCM Core and sleep waiting for tcm_loop_queue_tm_rsp() | ||
398 | * to wake us up. | ||
399 | */ | ||
400 | transport_generic_handle_tmr(se_cmd); | ||
401 | wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete)); | ||
402 | /* | ||
403 | * The TMR LUN_RESET has completed, check the response status and | ||
404 | * then release allocations. | ||
405 | */ | ||
406 | ret = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? | ||
407 | SUCCESS : FAILED; | ||
408 | release: | ||
409 | if (se_cmd) | ||
410 | transport_generic_free_cmd(se_cmd, 1, 1, 0); | ||
411 | else | ||
412 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
413 | kfree(tl_tmr); | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | static int tcm_loop_slave_alloc(struct scsi_device *sd) | ||
418 | { | ||
419 | set_bit(QUEUE_FLAG_BIDI, &sd->request_queue->queue_flags); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int tcm_loop_slave_configure(struct scsi_device *sd) | ||
424 | { | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static struct scsi_host_template tcm_loop_driver_template = { | ||
429 | .proc_info = tcm_loop_proc_info, | ||
430 | .proc_name = "tcm_loopback", | ||
431 | .name = "TCM_Loopback", | ||
432 | .queuecommand = tcm_loop_queuecommand, | ||
433 | .change_queue_depth = tcm_loop_change_queue_depth, | ||
434 | .eh_device_reset_handler = tcm_loop_device_reset, | ||
435 | .can_queue = TL_SCSI_CAN_QUEUE, | ||
436 | .this_id = -1, | ||
437 | .sg_tablesize = TL_SCSI_SG_TABLESIZE, | ||
438 | .cmd_per_lun = TL_SCSI_CMD_PER_LUN, | ||
439 | .max_sectors = TL_SCSI_MAX_SECTORS, | ||
440 | .use_clustering = DISABLE_CLUSTERING, | ||
441 | .slave_alloc = tcm_loop_slave_alloc, | ||
442 | .slave_configure = tcm_loop_slave_configure, | ||
443 | .module = THIS_MODULE, | ||
444 | }; | ||
445 | |||
446 | static int tcm_loop_driver_probe(struct device *dev) | ||
447 | { | ||
448 | struct tcm_loop_hba *tl_hba; | ||
449 | struct Scsi_Host *sh; | ||
450 | int error; | ||
451 | |||
452 | tl_hba = to_tcm_loop_hba(dev); | ||
453 | |||
454 | sh = scsi_host_alloc(&tcm_loop_driver_template, | ||
455 | sizeof(struct tcm_loop_hba)); | ||
456 | if (!sh) { | ||
457 | printk(KERN_ERR "Unable to allocate struct scsi_host\n"); | ||
458 | return -ENODEV; | ||
459 | } | ||
460 | tl_hba->sh = sh; | ||
461 | |||
462 | /* | ||
463 | * Assign the struct tcm_loop_hba pointer to struct Scsi_Host->hostdata | ||
464 | */ | ||
465 | *((struct tcm_loop_hba **)sh->hostdata) = tl_hba; | ||
466 | /* | ||
467 | * Setup single ID, Channel and LUN for now.. | ||
468 | */ | ||
469 | sh->max_id = 2; | ||
470 | sh->max_lun = 0; | ||
471 | sh->max_channel = 0; | ||
472 | sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN; | ||
473 | |||
474 | error = scsi_add_host(sh, &tl_hba->dev); | ||
475 | if (error) { | ||
476 | printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); | ||
477 | scsi_host_put(sh); | ||
478 | return -ENODEV; | ||
479 | } | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int tcm_loop_driver_remove(struct device *dev) | ||
484 | { | ||
485 | struct tcm_loop_hba *tl_hba; | ||
486 | struct Scsi_Host *sh; | ||
487 | |||
488 | tl_hba = to_tcm_loop_hba(dev); | ||
489 | sh = tl_hba->sh; | ||
490 | |||
491 | scsi_remove_host(sh); | ||
492 | scsi_host_put(sh); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static void tcm_loop_release_adapter(struct device *dev) | ||
497 | { | ||
498 | struct tcm_loop_hba *tl_hba = to_tcm_loop_hba(dev); | ||
499 | |||
500 | kfree(tl_hba); | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Called from tcm_loop_make_scsi_hba() in tcm_loop_configfs.c | ||
505 | */ | ||
506 | static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host_id) | ||
507 | { | ||
508 | int ret; | ||
509 | |||
510 | tl_hba->dev.bus = &tcm_loop_lld_bus; | ||
511 | tl_hba->dev.parent = tcm_loop_primary; | ||
512 | tl_hba->dev.release = &tcm_loop_release_adapter; | ||
513 | dev_set_name(&tl_hba->dev, "tcm_loop_adapter_%d", tcm_loop_host_id); | ||
514 | |||
515 | ret = device_register(&tl_hba->dev); | ||
516 | if (ret) { | ||
517 | printk(KERN_ERR "device_register() failed for" | ||
518 | " tl_hba->dev: %d\n", ret); | ||
519 | return -ENODEV; | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * Called from tcm_loop_fabric_init() in tcl_loop_fabric.c to load the emulated | ||
527 | * tcm_loop SCSI bus. | ||
528 | */ | ||
529 | static int tcm_loop_alloc_core_bus(void) | ||
530 | { | ||
531 | int ret; | ||
532 | |||
533 | tcm_loop_primary = root_device_register("tcm_loop_0"); | ||
534 | if (IS_ERR(tcm_loop_primary)) { | ||
535 | printk(KERN_ERR "Unable to allocate tcm_loop_primary\n"); | ||
536 | return PTR_ERR(tcm_loop_primary); | ||
537 | } | ||
538 | |||
539 | ret = bus_register(&tcm_loop_lld_bus); | ||
540 | if (ret) { | ||
541 | printk(KERN_ERR "bus_register() failed for tcm_loop_lld_bus\n"); | ||
542 | goto dev_unreg; | ||
543 | } | ||
544 | |||
545 | ret = driver_register(&tcm_loop_driverfs); | ||
546 | if (ret) { | ||
547 | printk(KERN_ERR "driver_register() failed for" | ||
548 | "tcm_loop_driverfs\n"); | ||
549 | goto bus_unreg; | ||
550 | } | ||
551 | |||
552 | printk(KERN_INFO "Initialized TCM Loop Core Bus\n"); | ||
553 | return ret; | ||
554 | |||
555 | bus_unreg: | ||
556 | bus_unregister(&tcm_loop_lld_bus); | ||
557 | dev_unreg: | ||
558 | root_device_unregister(tcm_loop_primary); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | static void tcm_loop_release_core_bus(void) | ||
563 | { | ||
564 | driver_unregister(&tcm_loop_driverfs); | ||
565 | bus_unregister(&tcm_loop_lld_bus); | ||
566 | root_device_unregister(tcm_loop_primary); | ||
567 | |||
568 | printk(KERN_INFO "Releasing TCM Loop Core BUS\n"); | ||
569 | } | ||
570 | |||
571 | static char *tcm_loop_get_fabric_name(void) | ||
572 | { | ||
573 | return "loopback"; | ||
574 | } | ||
575 | |||
576 | static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) | ||
577 | { | ||
578 | struct tcm_loop_tpg *tl_tpg = | ||
579 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
580 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
581 | /* | ||
582 | * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() | ||
583 | * time based on the protocol dependent prefix of the passed configfs group. | ||
584 | * | ||
585 | * Based upon tl_proto_id, TCM_Loop emulates the requested fabric | ||
586 | * ProtocolID using target_core_fabric_lib.c symbols. | ||
587 | */ | ||
588 | switch (tl_hba->tl_proto_id) { | ||
589 | case SCSI_PROTOCOL_SAS: | ||
590 | return sas_get_fabric_proto_ident(se_tpg); | ||
591 | case SCSI_PROTOCOL_FCP: | ||
592 | return fc_get_fabric_proto_ident(se_tpg); | ||
593 | case SCSI_PROTOCOL_ISCSI: | ||
594 | return iscsi_get_fabric_proto_ident(se_tpg); | ||
595 | default: | ||
596 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
597 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | return sas_get_fabric_proto_ident(se_tpg); | ||
602 | } | ||
603 | |||
604 | static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) | ||
605 | { | ||
606 | struct tcm_loop_tpg *tl_tpg = | ||
607 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
608 | /* | ||
609 | * Return the passed NAA identifier for the SAS Target Port | ||
610 | */ | ||
611 | return &tl_tpg->tl_hba->tl_wwn_address[0]; | ||
612 | } | ||
613 | |||
614 | static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) | ||
615 | { | ||
616 | struct tcm_loop_tpg *tl_tpg = | ||
617 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
618 | /* | ||
619 | * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 | ||
620 | * to represent the SCSI Target Port. | ||
621 | */ | ||
622 | return tl_tpg->tl_tpgt; | ||
623 | } | ||
624 | |||
625 | static u32 tcm_loop_get_default_depth(struct se_portal_group *se_tpg) | ||
626 | { | ||
627 | return 1; | ||
628 | } | ||
629 | |||
630 | static u32 tcm_loop_get_pr_transport_id( | ||
631 | struct se_portal_group *se_tpg, | ||
632 | struct se_node_acl *se_nacl, | ||
633 | struct t10_pr_registration *pr_reg, | ||
634 | int *format_code, | ||
635 | unsigned char *buf) | ||
636 | { | ||
637 | struct tcm_loop_tpg *tl_tpg = | ||
638 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
639 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
640 | |||
641 | switch (tl_hba->tl_proto_id) { | ||
642 | case SCSI_PROTOCOL_SAS: | ||
643 | return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
644 | format_code, buf); | ||
645 | case SCSI_PROTOCOL_FCP: | ||
646 | return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
647 | format_code, buf); | ||
648 | case SCSI_PROTOCOL_ISCSI: | ||
649 | return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
650 | format_code, buf); | ||
651 | default: | ||
652 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
653 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
658 | format_code, buf); | ||
659 | } | ||
660 | |||
661 | static u32 tcm_loop_get_pr_transport_id_len( | ||
662 | struct se_portal_group *se_tpg, | ||
663 | struct se_node_acl *se_nacl, | ||
664 | struct t10_pr_registration *pr_reg, | ||
665 | int *format_code) | ||
666 | { | ||
667 | struct tcm_loop_tpg *tl_tpg = | ||
668 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
669 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
670 | |||
671 | switch (tl_hba->tl_proto_id) { | ||
672 | case SCSI_PROTOCOL_SAS: | ||
673 | return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
674 | format_code); | ||
675 | case SCSI_PROTOCOL_FCP: | ||
676 | return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
677 | format_code); | ||
678 | case SCSI_PROTOCOL_ISCSI: | ||
679 | return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
680 | format_code); | ||
681 | default: | ||
682 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
683 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
688 | format_code); | ||
689 | } | ||
690 | |||
691 | /* | ||
692 | * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above | ||
693 | * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. | ||
694 | */ | ||
695 | static char *tcm_loop_parse_pr_out_transport_id( | ||
696 | struct se_portal_group *se_tpg, | ||
697 | const char *buf, | ||
698 | u32 *out_tid_len, | ||
699 | char **port_nexus_ptr) | ||
700 | { | ||
701 | struct tcm_loop_tpg *tl_tpg = | ||
702 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
703 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
704 | |||
705 | switch (tl_hba->tl_proto_id) { | ||
706 | case SCSI_PROTOCOL_SAS: | ||
707 | return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
708 | port_nexus_ptr); | ||
709 | case SCSI_PROTOCOL_FCP: | ||
710 | return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
711 | port_nexus_ptr); | ||
712 | case SCSI_PROTOCOL_ISCSI: | ||
713 | return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
714 | port_nexus_ptr); | ||
715 | default: | ||
716 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
717 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
722 | port_nexus_ptr); | ||
723 | } | ||
724 | |||
725 | /* | ||
726 | * Returning (1) here allows for target_core_mod struct se_node_acl to be generated | ||
727 | * based upon the incoming fabric dependent SCSI Initiator Port | ||
728 | */ | ||
729 | static int tcm_loop_check_demo_mode(struct se_portal_group *se_tpg) | ||
730 | { | ||
731 | return 1; | ||
732 | } | ||
733 | |||
734 | static int tcm_loop_check_demo_mode_cache(struct se_portal_group *se_tpg) | ||
735 | { | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * Allow I_T Nexus full READ-WRITE access without explict Initiator Node ACLs for | ||
741 | * local virtual Linux/SCSI LLD passthrough into VM hypervisor guest | ||
742 | */ | ||
743 | static int tcm_loop_check_demo_mode_write_protect(struct se_portal_group *se_tpg) | ||
744 | { | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * Because TCM_Loop does not use explict ACLs and MappedLUNs, this will | ||
750 | * never be called for TCM_Loop by target_core_fabric_configfs.c code. | ||
751 | * It has been added here as a nop for target_fabric_tf_ops_check() | ||
752 | */ | ||
753 | static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg) | ||
754 | { | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( | ||
759 | struct se_portal_group *se_tpg) | ||
760 | { | ||
761 | struct tcm_loop_nacl *tl_nacl; | ||
762 | |||
763 | tl_nacl = kzalloc(sizeof(struct tcm_loop_nacl), GFP_KERNEL); | ||
764 | if (!tl_nacl) { | ||
765 | printk(KERN_ERR "Unable to allocate struct tcm_loop_nacl\n"); | ||
766 | return NULL; | ||
767 | } | ||
768 | |||
769 | return &tl_nacl->se_node_acl; | ||
770 | } | ||
771 | |||
772 | static void tcm_loop_tpg_release_fabric_acl( | ||
773 | struct se_portal_group *se_tpg, | ||
774 | struct se_node_acl *se_nacl) | ||
775 | { | ||
776 | struct tcm_loop_nacl *tl_nacl = container_of(se_nacl, | ||
777 | struct tcm_loop_nacl, se_node_acl); | ||
778 | |||
779 | kfree(tl_nacl); | ||
780 | } | ||
781 | |||
782 | static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) | ||
783 | { | ||
784 | return 1; | ||
785 | } | ||
786 | |||
787 | static void tcm_loop_new_cmd_failure(struct se_cmd *se_cmd) | ||
788 | { | ||
789 | /* | ||
790 | * Since TCM_loop is already passing struct scatterlist data from | ||
791 | * struct scsi_cmnd, no more Linux/SCSI failure dependent state need | ||
792 | * to be handled here. | ||
793 | */ | ||
794 | return; | ||
795 | } | ||
796 | |||
797 | static int tcm_loop_is_state_remove(struct se_cmd *se_cmd) | ||
798 | { | ||
799 | /* | ||
800 | * Assume struct scsi_cmnd is not in remove state.. | ||
801 | */ | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int tcm_loop_sess_logged_in(struct se_session *se_sess) | ||
806 | { | ||
807 | /* | ||
808 | * Assume that TL Nexus is always active | ||
809 | */ | ||
810 | return 1; | ||
811 | } | ||
812 | |||
813 | static u32 tcm_loop_sess_get_index(struct se_session *se_sess) | ||
814 | { | ||
815 | return 1; | ||
816 | } | ||
817 | |||
818 | static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) | ||
819 | { | ||
820 | return; | ||
821 | } | ||
822 | |||
823 | static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) | ||
824 | { | ||
825 | return 1; | ||
826 | } | ||
827 | |||
828 | static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) | ||
829 | { | ||
830 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
831 | struct tcm_loop_cmd, tl_se_cmd); | ||
832 | |||
833 | return tl_cmd->sc_cmd_state; | ||
834 | } | ||
835 | |||
836 | static int tcm_loop_shutdown_session(struct se_session *se_sess) | ||
837 | { | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | static void tcm_loop_close_session(struct se_session *se_sess) | ||
842 | { | ||
843 | return; | ||
844 | }; | ||
845 | |||
846 | static void tcm_loop_stop_session( | ||
847 | struct se_session *se_sess, | ||
848 | int sess_sleep, | ||
849 | int conn_sleep) | ||
850 | { | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess) | ||
855 | { | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | static int tcm_loop_write_pending(struct se_cmd *se_cmd) | ||
860 | { | ||
861 | /* | ||
862 | * Since Linux/SCSI has already sent down a struct scsi_cmnd | ||
863 | * sc->sc_data_direction of DMA_TO_DEVICE with struct scatterlist array | ||
864 | * memory, and memory has already been mapped to struct se_cmd->t_mem_list | ||
865 | * format with transport_generic_map_mem_to_cmd(). | ||
866 | * | ||
867 | * We now tell TCM to add this WRITE CDB directly into the TCM storage | ||
868 | * object execution queue. | ||
869 | */ | ||
870 | transport_generic_process_write(se_cmd); | ||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | static int tcm_loop_write_pending_status(struct se_cmd *se_cmd) | ||
875 | { | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int tcm_loop_queue_data_in(struct se_cmd *se_cmd) | ||
880 | { | ||
881 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
882 | struct tcm_loop_cmd, tl_se_cmd); | ||
883 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
884 | |||
885 | TL_CDB_DEBUG("tcm_loop_queue_data_in() called for scsi_cmnd: %p" | ||
886 | " cdb: 0x%02x\n", sc, sc->cmnd[0]); | ||
887 | |||
888 | sc->result = SAM_STAT_GOOD; | ||
889 | set_host_byte(sc, DID_OK); | ||
890 | sc->scsi_done(sc); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int tcm_loop_queue_status(struct se_cmd *se_cmd) | ||
895 | { | ||
896 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
897 | struct tcm_loop_cmd, tl_se_cmd); | ||
898 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
899 | |||
900 | TL_CDB_DEBUG("tcm_loop_queue_status() called for scsi_cmnd: %p" | ||
901 | " cdb: 0x%02x\n", sc, sc->cmnd[0]); | ||
902 | |||
903 | if (se_cmd->sense_buffer && | ||
904 | ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || | ||
905 | (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { | ||
906 | |||
907 | memcpy((void *)sc->sense_buffer, (void *)se_cmd->sense_buffer, | ||
908 | SCSI_SENSE_BUFFERSIZE); | ||
909 | sc->result = SAM_STAT_CHECK_CONDITION; | ||
910 | set_driver_byte(sc, DRIVER_SENSE); | ||
911 | } else | ||
912 | sc->result = se_cmd->scsi_status; | ||
913 | |||
914 | set_host_byte(sc, DID_OK); | ||
915 | sc->scsi_done(sc); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) | ||
920 | { | ||
921 | struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; | ||
922 | struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; | ||
923 | /* | ||
924 | * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead | ||
925 | * and wake up the wait_queue_head_t in tcm_loop_device_reset() | ||
926 | */ | ||
927 | atomic_set(&tl_tmr->tmr_complete, 1); | ||
928 | wake_up(&tl_tmr->tl_tmr_wait); | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) | ||
933 | { | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static u16 tcm_loop_get_fabric_sense_len(void) | ||
938 | { | ||
939 | return 0; | ||
940 | } | ||
941 | |||
942 | static u64 tcm_loop_pack_lun(unsigned int lun) | ||
943 | { | ||
944 | u64 result; | ||
945 | |||
946 | /* LSB of lun into byte 1 big-endian */ | ||
947 | result = ((lun & 0xff) << 8); | ||
948 | /* use flat space addressing method */ | ||
949 | result |= 0x40 | ((lun >> 8) & 0x3f); | ||
950 | |||
951 | return cpu_to_le64(result); | ||
952 | } | ||
953 | |||
954 | static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba) | ||
955 | { | ||
956 | switch (tl_hba->tl_proto_id) { | ||
957 | case SCSI_PROTOCOL_SAS: | ||
958 | return "SAS"; | ||
959 | case SCSI_PROTOCOL_FCP: | ||
960 | return "FCP"; | ||
961 | case SCSI_PROTOCOL_ISCSI: | ||
962 | return "iSCSI"; | ||
963 | default: | ||
964 | break; | ||
965 | } | ||
966 | |||
967 | return "Unknown"; | ||
968 | } | ||
969 | |||
970 | /* Start items for tcm_loop_port_cit */ | ||
971 | |||
972 | static int tcm_loop_port_link( | ||
973 | struct se_portal_group *se_tpg, | ||
974 | struct se_lun *lun) | ||
975 | { | ||
976 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
977 | struct tcm_loop_tpg, tl_se_tpg); | ||
978 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
979 | |||
980 | atomic_inc(&tl_tpg->tl_tpg_port_count); | ||
981 | smp_mb__after_atomic_inc(); | ||
982 | /* | ||
983 | * Add Linux/SCSI struct scsi_device by HCTL | ||
984 | */ | ||
985 | scsi_add_device(tl_hba->sh, 0, tl_tpg->tl_tpgt, lun->unpacked_lun); | ||
986 | |||
987 | printk(KERN_INFO "TCM_Loop_ConfigFS: Port Link Successful\n"); | ||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static void tcm_loop_port_unlink( | ||
992 | struct se_portal_group *se_tpg, | ||
993 | struct se_lun *se_lun) | ||
994 | { | ||
995 | struct scsi_device *sd; | ||
996 | struct tcm_loop_hba *tl_hba; | ||
997 | struct tcm_loop_tpg *tl_tpg; | ||
998 | |||
999 | tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); | ||
1000 | tl_hba = tl_tpg->tl_hba; | ||
1001 | |||
1002 | sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt, | ||
1003 | se_lun->unpacked_lun); | ||
1004 | if (!sd) { | ||
1005 | printk(KERN_ERR "Unable to locate struct scsi_device for %d:%d:" | ||
1006 | "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); | ||
1007 | return; | ||
1008 | } | ||
1009 | /* | ||
1010 | * Remove Linux/SCSI struct scsi_device by HCTL | ||
1011 | */ | ||
1012 | scsi_remove_device(sd); | ||
1013 | scsi_device_put(sd); | ||
1014 | |||
1015 | atomic_dec(&tl_tpg->tl_tpg_port_count); | ||
1016 | smp_mb__after_atomic_dec(); | ||
1017 | |||
1018 | printk(KERN_INFO "TCM_Loop_ConfigFS: Port Unlink Successful\n"); | ||
1019 | } | ||
1020 | |||
1021 | /* End items for tcm_loop_port_cit */ | ||
1022 | |||
1023 | /* Start items for tcm_loop_nexus_cit */ | ||
1024 | |||
1025 | static int tcm_loop_make_nexus( | ||
1026 | struct tcm_loop_tpg *tl_tpg, | ||
1027 | const char *name) | ||
1028 | { | ||
1029 | struct se_portal_group *se_tpg; | ||
1030 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
1031 | struct tcm_loop_nexus *tl_nexus; | ||
1032 | |||
1033 | if (tl_tpg->tl_hba->tl_nexus) { | ||
1034 | printk(KERN_INFO "tl_tpg->tl_hba->tl_nexus already exists\n"); | ||
1035 | return -EEXIST; | ||
1036 | } | ||
1037 | se_tpg = &tl_tpg->tl_se_tpg; | ||
1038 | |||
1039 | tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); | ||
1040 | if (!tl_nexus) { | ||
1041 | printk(KERN_ERR "Unable to allocate struct tcm_loop_nexus\n"); | ||
1042 | return -ENOMEM; | ||
1043 | } | ||
1044 | /* | ||
1045 | * Initialize the struct se_session pointer | ||
1046 | */ | ||
1047 | tl_nexus->se_sess = transport_init_session(); | ||
1048 | if (!tl_nexus->se_sess) | ||
1049 | goto out; | ||
1050 | /* | ||
1051 | * Since we are running in 'demo mode' this call with generate a | ||
1052 | * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI | ||
1053 | * Initiator port name of the passed configfs group 'name'. | ||
1054 | */ | ||
1055 | tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( | ||
1056 | se_tpg, (unsigned char *)name); | ||
1057 | if (!tl_nexus->se_sess->se_node_acl) { | ||
1058 | transport_free_session(tl_nexus->se_sess); | ||
1059 | goto out; | ||
1060 | } | ||
1061 | /* | ||
1062 | * Now, register the SAS I_T Nexus as active with the call to | ||
1063 | * transport_register_session() | ||
1064 | */ | ||
1065 | __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, | ||
1066 | tl_nexus->se_sess, (void *)tl_nexus); | ||
1067 | tl_tpg->tl_hba->tl_nexus = tl_nexus; | ||
1068 | printk(KERN_INFO "TCM_Loop_ConfigFS: Established I_T Nexus to emulated" | ||
1069 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | ||
1070 | name); | ||
1071 | return 0; | ||
1072 | |||
1073 | out: | ||
1074 | kfree(tl_nexus); | ||
1075 | return -ENOMEM; | ||
1076 | } | ||
1077 | |||
1078 | static int tcm_loop_drop_nexus( | ||
1079 | struct tcm_loop_tpg *tpg) | ||
1080 | { | ||
1081 | struct se_session *se_sess; | ||
1082 | struct tcm_loop_nexus *tl_nexus; | ||
1083 | struct tcm_loop_hba *tl_hba = tpg->tl_hba; | ||
1084 | |||
1085 | tl_nexus = tpg->tl_hba->tl_nexus; | ||
1086 | if (!tl_nexus) | ||
1087 | return -ENODEV; | ||
1088 | |||
1089 | se_sess = tl_nexus->se_sess; | ||
1090 | if (!se_sess) | ||
1091 | return -ENODEV; | ||
1092 | |||
1093 | if (atomic_read(&tpg->tl_tpg_port_count)) { | ||
1094 | printk(KERN_ERR "Unable to remove TCM_Loop I_T Nexus with" | ||
1095 | " active TPG port count: %d\n", | ||
1096 | atomic_read(&tpg->tl_tpg_port_count)); | ||
1097 | return -EPERM; | ||
1098 | } | ||
1099 | |||
1100 | printk(KERN_INFO "TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" | ||
1101 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | ||
1102 | tl_nexus->se_sess->se_node_acl->initiatorname); | ||
1103 | /* | ||
1104 | * Release the SCSI I_T Nexus to the emulated SAS Target Port | ||
1105 | */ | ||
1106 | transport_deregister_session(tl_nexus->se_sess); | ||
1107 | tpg->tl_hba->tl_nexus = NULL; | ||
1108 | kfree(tl_nexus); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /* End items for tcm_loop_nexus_cit */ | ||
1113 | |||
1114 | static ssize_t tcm_loop_tpg_show_nexus( | ||
1115 | struct se_portal_group *se_tpg, | ||
1116 | char *page) | ||
1117 | { | ||
1118 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1119 | struct tcm_loop_tpg, tl_se_tpg); | ||
1120 | struct tcm_loop_nexus *tl_nexus; | ||
1121 | ssize_t ret; | ||
1122 | |||
1123 | tl_nexus = tl_tpg->tl_hba->tl_nexus; | ||
1124 | if (!tl_nexus) | ||
1125 | return -ENODEV; | ||
1126 | |||
1127 | ret = snprintf(page, PAGE_SIZE, "%s\n", | ||
1128 | tl_nexus->se_sess->se_node_acl->initiatorname); | ||
1129 | |||
1130 | return ret; | ||
1131 | } | ||
1132 | |||
1133 | static ssize_t tcm_loop_tpg_store_nexus( | ||
1134 | struct se_portal_group *se_tpg, | ||
1135 | const char *page, | ||
1136 | size_t count) | ||
1137 | { | ||
1138 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1139 | struct tcm_loop_tpg, tl_se_tpg); | ||
1140 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
1141 | unsigned char i_port[TL_WWN_ADDR_LEN], *ptr, *port_ptr; | ||
1142 | int ret; | ||
1143 | /* | ||
1144 | * Shutdown the active I_T nexus if 'NULL' is passed.. | ||
1145 | */ | ||
1146 | if (!strncmp(page, "NULL", 4)) { | ||
1147 | ret = tcm_loop_drop_nexus(tl_tpg); | ||
1148 | return (!ret) ? count : ret; | ||
1149 | } | ||
1150 | /* | ||
1151 | * Otherwise make sure the passed virtual Initiator port WWN matches | ||
1152 | * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call | ||
1153 | * tcm_loop_make_nexus() | ||
1154 | */ | ||
1155 | if (strlen(page) > TL_WWN_ADDR_LEN) { | ||
1156 | printk(KERN_ERR "Emulated NAA Sas Address: %s, exceeds" | ||
1157 | " max: %d\n", page, TL_WWN_ADDR_LEN); | ||
1158 | return -EINVAL; | ||
1159 | } | ||
1160 | snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page); | ||
1161 | |||
1162 | ptr = strstr(i_port, "naa."); | ||
1163 | if (ptr) { | ||
1164 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) { | ||
1165 | printk(KERN_ERR "Passed SAS Initiator Port %s does not" | ||
1166 | " match target port protoid: %s\n", i_port, | ||
1167 | tcm_loop_dump_proto_id(tl_hba)); | ||
1168 | return -EINVAL; | ||
1169 | } | ||
1170 | port_ptr = &i_port[0]; | ||
1171 | goto check_newline; | ||
1172 | } | ||
1173 | ptr = strstr(i_port, "fc."); | ||
1174 | if (ptr) { | ||
1175 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) { | ||
1176 | printk(KERN_ERR "Passed FCP Initiator Port %s does not" | ||
1177 | " match target port protoid: %s\n", i_port, | ||
1178 | tcm_loop_dump_proto_id(tl_hba)); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | port_ptr = &i_port[3]; /* Skip over "fc." */ | ||
1182 | goto check_newline; | ||
1183 | } | ||
1184 | ptr = strstr(i_port, "iqn."); | ||
1185 | if (ptr) { | ||
1186 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) { | ||
1187 | printk(KERN_ERR "Passed iSCSI Initiator Port %s does not" | ||
1188 | " match target port protoid: %s\n", i_port, | ||
1189 | tcm_loop_dump_proto_id(tl_hba)); | ||
1190 | return -EINVAL; | ||
1191 | } | ||
1192 | port_ptr = &i_port[0]; | ||
1193 | goto check_newline; | ||
1194 | } | ||
1195 | printk(KERN_ERR "Unable to locate prefix for emulated Initiator Port:" | ||
1196 | " %s\n", i_port); | ||
1197 | return -EINVAL; | ||
1198 | /* | ||
1199 | * Clear any trailing newline for the NAA WWN | ||
1200 | */ | ||
1201 | check_newline: | ||
1202 | if (i_port[strlen(i_port)-1] == '\n') | ||
1203 | i_port[strlen(i_port)-1] = '\0'; | ||
1204 | |||
1205 | ret = tcm_loop_make_nexus(tl_tpg, port_ptr); | ||
1206 | if (ret < 0) | ||
1207 | return ret; | ||
1208 | |||
1209 | return count; | ||
1210 | } | ||
1211 | |||
1212 | TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR); | ||
1213 | |||
1214 | static struct configfs_attribute *tcm_loop_tpg_attrs[] = { | ||
1215 | &tcm_loop_tpg_nexus.attr, | ||
1216 | NULL, | ||
1217 | }; | ||
1218 | |||
1219 | /* Start items for tcm_loop_naa_cit */ | ||
1220 | |||
1221 | struct se_portal_group *tcm_loop_make_naa_tpg( | ||
1222 | struct se_wwn *wwn, | ||
1223 | struct config_group *group, | ||
1224 | const char *name) | ||
1225 | { | ||
1226 | struct tcm_loop_hba *tl_hba = container_of(wwn, | ||
1227 | struct tcm_loop_hba, tl_hba_wwn); | ||
1228 | struct tcm_loop_tpg *tl_tpg; | ||
1229 | char *tpgt_str, *end_ptr; | ||
1230 | int ret; | ||
1231 | unsigned short int tpgt; | ||
1232 | |||
1233 | tpgt_str = strstr(name, "tpgt_"); | ||
1234 | if (!tpgt_str) { | ||
1235 | printk(KERN_ERR "Unable to locate \"tpgt_#\" directory" | ||
1236 | " group\n"); | ||
1237 | return ERR_PTR(-EINVAL); | ||
1238 | } | ||
1239 | tpgt_str += 5; /* Skip ahead of "tpgt_" */ | ||
1240 | tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); | ||
1241 | |||
1242 | if (tpgt > TL_TPGS_PER_HBA) { | ||
1243 | printk(KERN_ERR "Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:" | ||
1244 | " %u\n", tpgt, TL_TPGS_PER_HBA); | ||
1245 | return ERR_PTR(-EINVAL); | ||
1246 | } | ||
1247 | tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; | ||
1248 | tl_tpg->tl_hba = tl_hba; | ||
1249 | tl_tpg->tl_tpgt = tpgt; | ||
1250 | /* | ||
1251 | * Register the tl_tpg as a emulated SAS TCM Target Endpoint | ||
1252 | */ | ||
1253 | ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, | ||
1254 | wwn, &tl_tpg->tl_se_tpg, (void *)tl_tpg, | ||
1255 | TRANSPORT_TPG_TYPE_NORMAL); | ||
1256 | if (ret < 0) | ||
1257 | return ERR_PTR(-ENOMEM); | ||
1258 | |||
1259 | printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated Emulated %s" | ||
1260 | " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), | ||
1261 | config_item_name(&wwn->wwn_group.cg_item), tpgt); | ||
1262 | |||
1263 | return &tl_tpg->tl_se_tpg; | ||
1264 | } | ||
1265 | |||
1266 | void tcm_loop_drop_naa_tpg( | ||
1267 | struct se_portal_group *se_tpg) | ||
1268 | { | ||
1269 | struct se_wwn *wwn = se_tpg->se_tpg_wwn; | ||
1270 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1271 | struct tcm_loop_tpg, tl_se_tpg); | ||
1272 | struct tcm_loop_hba *tl_hba; | ||
1273 | unsigned short tpgt; | ||
1274 | |||
1275 | tl_hba = tl_tpg->tl_hba; | ||
1276 | tpgt = tl_tpg->tl_tpgt; | ||
1277 | /* | ||
1278 | * Release the I_T Nexus for the Virtual SAS link if present | ||
1279 | */ | ||
1280 | tcm_loop_drop_nexus(tl_tpg); | ||
1281 | /* | ||
1282 | * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint | ||
1283 | */ | ||
1284 | core_tpg_deregister(se_tpg); | ||
1285 | |||
1286 | printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated Emulated %s" | ||
1287 | " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), | ||
1288 | config_item_name(&wwn->wwn_group.cg_item), tpgt); | ||
1289 | } | ||
1290 | |||
1291 | /* End items for tcm_loop_naa_cit */ | ||
1292 | |||
1293 | /* Start items for tcm_loop_cit */ | ||
1294 | |||
1295 | struct se_wwn *tcm_loop_make_scsi_hba( | ||
1296 | struct target_fabric_configfs *tf, | ||
1297 | struct config_group *group, | ||
1298 | const char *name) | ||
1299 | { | ||
1300 | struct tcm_loop_hba *tl_hba; | ||
1301 | struct Scsi_Host *sh; | ||
1302 | char *ptr; | ||
1303 | int ret, off = 0; | ||
1304 | |||
1305 | tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL); | ||
1306 | if (!tl_hba) { | ||
1307 | printk(KERN_ERR "Unable to allocate struct tcm_loop_hba\n"); | ||
1308 | return ERR_PTR(-ENOMEM); | ||
1309 | } | ||
1310 | /* | ||
1311 | * Determine the emulated Protocol Identifier and Target Port Name | ||
1312 | * based on the incoming configfs directory name. | ||
1313 | */ | ||
1314 | ptr = strstr(name, "naa."); | ||
1315 | if (ptr) { | ||
1316 | tl_hba->tl_proto_id = SCSI_PROTOCOL_SAS; | ||
1317 | goto check_len; | ||
1318 | } | ||
1319 | ptr = strstr(name, "fc."); | ||
1320 | if (ptr) { | ||
1321 | tl_hba->tl_proto_id = SCSI_PROTOCOL_FCP; | ||
1322 | off = 3; /* Skip over "fc." */ | ||
1323 | goto check_len; | ||
1324 | } | ||
1325 | ptr = strstr(name, "iqn."); | ||
1326 | if (ptr) { | ||
1327 | tl_hba->tl_proto_id = SCSI_PROTOCOL_ISCSI; | ||
1328 | goto check_len; | ||
1329 | } | ||
1330 | |||
1331 | printk(KERN_ERR "Unable to locate prefix for emulated Target Port:" | ||
1332 | " %s\n", name); | ||
1333 | return ERR_PTR(-EINVAL); | ||
1334 | |||
1335 | check_len: | ||
1336 | if (strlen(name) > TL_WWN_ADDR_LEN) { | ||
1337 | printk(KERN_ERR "Emulated NAA %s Address: %s, exceeds" | ||
1338 | " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), | ||
1339 | TL_WWN_ADDR_LEN); | ||
1340 | kfree(tl_hba); | ||
1341 | return ERR_PTR(-EINVAL); | ||
1342 | } | ||
1343 | snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); | ||
1344 | |||
1345 | /* | ||
1346 | * Call device_register(tl_hba->dev) to register the emulated | ||
1347 | * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after | ||
1348 | * device_register() callbacks in tcm_loop_driver_probe() | ||
1349 | */ | ||
1350 | ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt); | ||
1351 | if (ret) | ||
1352 | goto out; | ||
1353 | |||
1354 | sh = tl_hba->sh; | ||
1355 | tcm_loop_hba_no_cnt++; | ||
1356 | printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated emulated Target" | ||
1357 | " %s Address: %s at Linux/SCSI Host ID: %d\n", | ||
1358 | tcm_loop_dump_proto_id(tl_hba), name, sh->host_no); | ||
1359 | |||
1360 | return &tl_hba->tl_hba_wwn; | ||
1361 | out: | ||
1362 | kfree(tl_hba); | ||
1363 | return ERR_PTR(ret); | ||
1364 | } | ||
1365 | |||
1366 | void tcm_loop_drop_scsi_hba( | ||
1367 | struct se_wwn *wwn) | ||
1368 | { | ||
1369 | struct tcm_loop_hba *tl_hba = container_of(wwn, | ||
1370 | struct tcm_loop_hba, tl_hba_wwn); | ||
1371 | int host_no = tl_hba->sh->host_no; | ||
1372 | /* | ||
1373 | * Call device_unregister() on the original tl_hba->dev. | ||
1374 | * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will | ||
1375 | * release *tl_hba; | ||
1376 | */ | ||
1377 | device_unregister(&tl_hba->dev); | ||
1378 | |||
1379 | printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated emulated Target" | ||
1380 | " SAS Address: %s at Linux/SCSI Host ID: %d\n", | ||
1381 | config_item_name(&wwn->wwn_group.cg_item), host_no); | ||
1382 | } | ||
1383 | |||
1384 | /* Start items for tcm_loop_cit */ | ||
1385 | static ssize_t tcm_loop_wwn_show_attr_version( | ||
1386 | struct target_fabric_configfs *tf, | ||
1387 | char *page) | ||
1388 | { | ||
1389 | return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION); | ||
1390 | } | ||
1391 | |||
1392 | TF_WWN_ATTR_RO(tcm_loop, version); | ||
1393 | |||
1394 | static struct configfs_attribute *tcm_loop_wwn_attrs[] = { | ||
1395 | &tcm_loop_wwn_version.attr, | ||
1396 | NULL, | ||
1397 | }; | ||
1398 | |||
1399 | /* End items for tcm_loop_cit */ | ||
1400 | |||
1401 | static int tcm_loop_register_configfs(void) | ||
1402 | { | ||
1403 | struct target_fabric_configfs *fabric; | ||
1404 | struct config_group *tf_cg; | ||
1405 | int ret; | ||
1406 | /* | ||
1407 | * Set the TCM Loop HBA counter to zero | ||
1408 | */ | ||
1409 | tcm_loop_hba_no_cnt = 0; | ||
1410 | /* | ||
1411 | * Register the top level struct config_item_type with TCM core | ||
1412 | */ | ||
1413 | fabric = target_fabric_configfs_init(THIS_MODULE, "loopback"); | ||
1414 | if (!fabric) { | ||
1415 | printk(KERN_ERR "tcm_loop_register_configfs() failed!\n"); | ||
1416 | return -1; | ||
1417 | } | ||
1418 | /* | ||
1419 | * Setup the fabric API of function pointers used by target_core_mod | ||
1420 | */ | ||
1421 | fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name; | ||
1422 | fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident; | ||
1423 | fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn; | ||
1424 | fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag; | ||
1425 | fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth; | ||
1426 | fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id; | ||
1427 | fabric->tf_ops.tpg_get_pr_transport_id_len = | ||
1428 | &tcm_loop_get_pr_transport_id_len; | ||
1429 | fabric->tf_ops.tpg_parse_pr_out_transport_id = | ||
1430 | &tcm_loop_parse_pr_out_transport_id; | ||
1431 | fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode; | ||
1432 | fabric->tf_ops.tpg_check_demo_mode_cache = | ||
1433 | &tcm_loop_check_demo_mode_cache; | ||
1434 | fabric->tf_ops.tpg_check_demo_mode_write_protect = | ||
1435 | &tcm_loop_check_demo_mode_write_protect; | ||
1436 | fabric->tf_ops.tpg_check_prod_mode_write_protect = | ||
1437 | &tcm_loop_check_prod_mode_write_protect; | ||
1438 | /* | ||
1439 | * The TCM loopback fabric module runs in demo-mode to a local | ||
1440 | * virtual SCSI device, so fabric dependent initator ACLs are | ||
1441 | * not required. | ||
1442 | */ | ||
1443 | fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl; | ||
1444 | fabric->tf_ops.tpg_release_fabric_acl = | ||
1445 | &tcm_loop_tpg_release_fabric_acl; | ||
1446 | fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index; | ||
1447 | /* | ||
1448 | * Since tcm_loop is mapping physical memory from Linux/SCSI | ||
1449 | * struct scatterlist arrays for each struct scsi_cmnd I/O, | ||
1450 | * we do not need TCM to allocate a iovec array for | ||
1451 | * virtual memory address mappings | ||
1452 | */ | ||
1453 | fabric->tf_ops.alloc_cmd_iovecs = NULL; | ||
1454 | /* | ||
1455 | * Used for setting up remaining TCM resources in process context | ||
1456 | */ | ||
1457 | fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map; | ||
1458 | fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; | ||
1459 | fabric->tf_ops.release_cmd_to_pool = &tcm_loop_deallocate_core_cmd; | ||
1460 | fabric->tf_ops.release_cmd_direct = &tcm_loop_deallocate_core_cmd; | ||
1461 | fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; | ||
1462 | fabric->tf_ops.close_session = &tcm_loop_close_session; | ||
1463 | fabric->tf_ops.stop_session = &tcm_loop_stop_session; | ||
1464 | fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0; | ||
1465 | fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in; | ||
1466 | fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; | ||
1467 | fabric->tf_ops.sess_get_initiator_sid = NULL; | ||
1468 | fabric->tf_ops.write_pending = &tcm_loop_write_pending; | ||
1469 | fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status; | ||
1470 | /* | ||
1471 | * Not used for TCM loopback | ||
1472 | */ | ||
1473 | fabric->tf_ops.set_default_node_attributes = | ||
1474 | &tcm_loop_set_default_node_attributes; | ||
1475 | fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag; | ||
1476 | fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state; | ||
1477 | fabric->tf_ops.new_cmd_failure = &tcm_loop_new_cmd_failure; | ||
1478 | fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in; | ||
1479 | fabric->tf_ops.queue_status = &tcm_loop_queue_status; | ||
1480 | fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; | ||
1481 | fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len; | ||
1482 | fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len; | ||
1483 | fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove; | ||
1484 | fabric->tf_ops.pack_lun = &tcm_loop_pack_lun; | ||
1485 | |||
1486 | tf_cg = &fabric->tf_group; | ||
1487 | /* | ||
1488 | * Setup function pointers for generic logic in target_core_fabric_configfs.c | ||
1489 | */ | ||
1490 | fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba; | ||
1491 | fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba; | ||
1492 | fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg; | ||
1493 | fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg; | ||
1494 | /* | ||
1495 | * fabric_post_link() and fabric_pre_unlink() are used for | ||
1496 | * registration and release of TCM Loop Virtual SCSI LUNs. | ||
1497 | */ | ||
1498 | fabric->tf_ops.fabric_post_link = &tcm_loop_port_link; | ||
1499 | fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink; | ||
1500 | fabric->tf_ops.fabric_make_np = NULL; | ||
1501 | fabric->tf_ops.fabric_drop_np = NULL; | ||
1502 | /* | ||
1503 | * Setup default attribute lists for various fabric->tf_cit_tmpl | ||
1504 | */ | ||
1505 | TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs; | ||
1506 | TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs; | ||
1507 | TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; | ||
1508 | TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; | ||
1509 | TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; | ||
1510 | /* | ||
1511 | * Once fabric->tf_ops has been setup, now register the fabric for | ||
1512 | * use within TCM | ||
1513 | */ | ||
1514 | ret = target_fabric_configfs_register(fabric); | ||
1515 | if (ret < 0) { | ||
1516 | printk(KERN_ERR "target_fabric_configfs_register() for" | ||
1517 | " TCM_Loop failed!\n"); | ||
1518 | target_fabric_configfs_free(fabric); | ||
1519 | return -1; | ||
1520 | } | ||
1521 | /* | ||
1522 | * Setup our local pointer to *fabric. | ||
1523 | */ | ||
1524 | tcm_loop_fabric_configfs = fabric; | ||
1525 | printk(KERN_INFO "TCM_LOOP[0] - Set fabric ->" | ||
1526 | " tcm_loop_fabric_configfs\n"); | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | static void tcm_loop_deregister_configfs(void) | ||
1531 | { | ||
1532 | if (!tcm_loop_fabric_configfs) | ||
1533 | return; | ||
1534 | |||
1535 | target_fabric_configfs_deregister(tcm_loop_fabric_configfs); | ||
1536 | tcm_loop_fabric_configfs = NULL; | ||
1537 | printk(KERN_INFO "TCM_LOOP[0] - Cleared" | ||
1538 | " tcm_loop_fabric_configfs\n"); | ||
1539 | } | ||
1540 | |||
1541 | static int __init tcm_loop_fabric_init(void) | ||
1542 | { | ||
1543 | int ret; | ||
1544 | |||
1545 | tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache", | ||
1546 | sizeof(struct tcm_loop_cmd), | ||
1547 | __alignof__(struct tcm_loop_cmd), | ||
1548 | 0, NULL); | ||
1549 | if (!tcm_loop_cmd_cache) { | ||
1550 | printk(KERN_ERR "kmem_cache_create() for" | ||
1551 | " tcm_loop_cmd_cache failed\n"); | ||
1552 | return -ENOMEM; | ||
1553 | } | ||
1554 | |||
1555 | ret = tcm_loop_alloc_core_bus(); | ||
1556 | if (ret) | ||
1557 | return ret; | ||
1558 | |||
1559 | ret = tcm_loop_register_configfs(); | ||
1560 | if (ret) { | ||
1561 | tcm_loop_release_core_bus(); | ||
1562 | return ret; | ||
1563 | } | ||
1564 | |||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | static void __exit tcm_loop_fabric_exit(void) | ||
1569 | { | ||
1570 | tcm_loop_deregister_configfs(); | ||
1571 | tcm_loop_release_core_bus(); | ||
1572 | kmem_cache_destroy(tcm_loop_cmd_cache); | ||
1573 | } | ||
1574 | |||
1575 | MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module"); | ||
1576 | MODULE_AUTHOR("Nicholas A. Bellinger <nab@risingtidesystems.com>"); | ||
1577 | MODULE_LICENSE("GPL"); | ||
1578 | module_init(tcm_loop_fabric_init); | ||
1579 | module_exit(tcm_loop_fabric_exit); | ||
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h new file mode 100644 index 000000000000..7e9f7ab45548 --- /dev/null +++ b/drivers/target/loopback/tcm_loop.h | |||
@@ -0,0 +1,77 @@ | |||
1 | #define TCM_LOOP_VERSION "v2.1-rc1" | ||
2 | #define TL_WWN_ADDR_LEN 256 | ||
3 | #define TL_TPGS_PER_HBA 32 | ||
4 | /* | ||
5 | * Defaults for struct scsi_host_template tcm_loop_driver_template | ||
6 | * | ||
7 | * We use large can_queue and cmd_per_lun here and let TCM enforce | ||
8 | * the underlying se_device_t->queue_depth. | ||
9 | */ | ||
10 | #define TL_SCSI_CAN_QUEUE 1024 | ||
11 | #define TL_SCSI_CMD_PER_LUN 1024 | ||
12 | #define TL_SCSI_MAX_SECTORS 1024 | ||
13 | #define TL_SCSI_SG_TABLESIZE 256 | ||
14 | /* | ||
15 | * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len | ||
16 | */ | ||
17 | #define TL_SCSI_MAX_CMD_LEN 32 | ||
18 | |||
19 | #ifdef CONFIG_LOOPBACK_TARGET_CDB_DEBUG | ||
20 | # define TL_CDB_DEBUG(x...) printk(KERN_INFO x) | ||
21 | #else | ||
22 | # define TL_CDB_DEBUG(x...) | ||
23 | #endif | ||
24 | |||
25 | struct tcm_loop_cmd { | ||
26 | /* State of Linux/SCSI CDB+Data descriptor */ | ||
27 | u32 sc_cmd_state; | ||
28 | /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ | ||
29 | struct scsi_cmnd *sc; | ||
30 | struct list_head *tl_cmd_list; | ||
31 | /* The TCM I/O descriptor that is accessed via container_of() */ | ||
32 | struct se_cmd tl_se_cmd; | ||
33 | /* Sense buffer that will be mapped into outgoing status */ | ||
34 | unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; | ||
35 | }; | ||
36 | |||
37 | struct tcm_loop_tmr { | ||
38 | atomic_t tmr_complete; | ||
39 | wait_queue_head_t tl_tmr_wait; | ||
40 | }; | ||
41 | |||
42 | struct tcm_loop_nexus { | ||
43 | int it_nexus_active; | ||
44 | /* | ||
45 | * Pointer to Linux/SCSI HBA from linux/include/scsi_host.h | ||
46 | */ | ||
47 | struct scsi_host *sh; | ||
48 | /* | ||
49 | * Pointer to TCM session for I_T Nexus | ||
50 | */ | ||
51 | struct se_session *se_sess; | ||
52 | }; | ||
53 | |||
54 | struct tcm_loop_nacl { | ||
55 | struct se_node_acl se_node_acl; | ||
56 | }; | ||
57 | |||
58 | struct tcm_loop_tpg { | ||
59 | unsigned short tl_tpgt; | ||
60 | atomic_t tl_tpg_port_count; | ||
61 | struct se_portal_group tl_se_tpg; | ||
62 | struct tcm_loop_hba *tl_hba; | ||
63 | }; | ||
64 | |||
65 | struct tcm_loop_hba { | ||
66 | u8 tl_proto_id; | ||
67 | unsigned char tl_wwn_address[TL_WWN_ADDR_LEN]; | ||
68 | struct se_hba_s *se_hba; | ||
69 | struct se_lun *tl_hba_lun; | ||
70 | struct se_port *tl_hba_lun_sep; | ||
71 | struct se_device_s *se_dev_hba_ptr; | ||
72 | struct tcm_loop_nexus *tl_nexus; | ||
73 | struct device dev; | ||
74 | struct Scsi_Host *sh; | ||
75 | struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; | ||
76 | struct se_wwn tl_hba_wwn; | ||
77 | }; | ||
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index e7dddafe73f6..47abb42d9c36 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -496,8 +496,8 @@ static int core_alua_state_check( | |||
496 | nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; | 496 | nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; |
497 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | 497 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); |
498 | /* | 498 | /* |
499 | * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a seperate conditional | 499 | * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a separate conditional |
500 | * statement so the complier knows explictly to check this case first. | 500 | * statement so the compiler knows explicitly to check this case first. |
501 | * For the Optimized ALUA access state case, we want to process the | 501 | * For the Optimized ALUA access state case, we want to process the |
502 | * incoming fabric cmd ASAP.. | 502 | * incoming fabric cmd ASAP.. |
503 | */ | 503 | */ |
@@ -1157,7 +1157,7 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) | |||
1157 | spin_unlock(&lu_gp->lu_gp_lock); | 1157 | spin_unlock(&lu_gp->lu_gp_lock); |
1158 | /* | 1158 | /* |
1159 | * | 1159 | * |
1160 | * lu_gp_mem is assoicated with a single | 1160 | * lu_gp_mem is associated with a single |
1161 | * struct se_device->dev_alua_lu_gp_mem, and is released when | 1161 | * struct se_device->dev_alua_lu_gp_mem, and is released when |
1162 | * struct se_device is released via core_alua_free_lu_gp_mem(). | 1162 | * struct se_device is released via core_alua_free_lu_gp_mem(). |
1163 | * | 1163 | * |
@@ -1429,7 +1429,7 @@ void core_alua_free_tg_pt_gp( | |||
1429 | } | 1429 | } |
1430 | spin_unlock(&tg_pt_gp->tg_pt_gp_lock); | 1430 | spin_unlock(&tg_pt_gp->tg_pt_gp_lock); |
1431 | /* | 1431 | /* |
1432 | * tg_pt_gp_mem is assoicated with a single | 1432 | * tg_pt_gp_mem is associated with a single |
1433 | * se_port->sep_alua_tg_pt_gp_mem, and is released via | 1433 | * se_port->sep_alua_tg_pt_gp_mem, and is released via |
1434 | * core_alua_free_tg_pt_gp_mem(). | 1434 | * core_alua_free_tg_pt_gp_mem(). |
1435 | * | 1435 | * |
@@ -1963,7 +1963,7 @@ int core_setup_alua(struct se_device *dev, int force_pt) | |||
1963 | printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3" | 1963 | printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3" |
1964 | " device\n", TRANSPORT(dev)->name); | 1964 | " device\n", TRANSPORT(dev)->name); |
1965 | /* | 1965 | /* |
1966 | * Assoicate this struct se_device with the default ALUA | 1966 | * Associate this struct se_device with the default ALUA |
1967 | * LUN Group. | 1967 | * LUN Group. |
1968 | */ | 1968 | */ |
1969 | lu_gp_mem = core_alua_allocate_lu_gp_mem(dev); | 1969 | lu_gp_mem = core_alua_allocate_lu_gp_mem(dev); |
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index caf8dc18ee0a..a5f44a6e6e1d 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c | |||
@@ -3,8 +3,8 @@ | |||
3 | * | 3 | * |
4 | * This file contains ConfigFS logic for the Generic Target Engine project. | 4 | * This file contains ConfigFS logic for the Generic Target Engine project. |
5 | * | 5 | * |
6 | * Copyright (c) 2008-2010 Rising Tide Systems | 6 | * Copyright (c) 2008-2011 Rising Tide Systems |
7 | * Copyright (c) 2008-2010 Linux-iSCSI.org | 7 | * Copyright (c) 2008-2011 Linux-iSCSI.org |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -50,6 +50,7 @@ | |||
50 | #include "target_core_hba.h" | 50 | #include "target_core_hba.h" |
51 | #include "target_core_pr.h" | 51 | #include "target_core_pr.h" |
52 | #include "target_core_rd.h" | 52 | #include "target_core_rd.h" |
53 | #include "target_core_stat.h" | ||
53 | 54 | ||
54 | static struct list_head g_tf_list; | 55 | static struct list_head g_tf_list; |
55 | static struct mutex g_tf_lock; | 56 | static struct mutex g_tf_lock; |
@@ -1451,8 +1452,8 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1451 | size_t count) | 1452 | size_t count) |
1452 | { | 1453 | { |
1453 | struct se_device *dev; | 1454 | struct se_device *dev; |
1454 | unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL; | 1455 | unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; |
1455 | unsigned char *isid = NULL; | 1456 | unsigned char *t_fabric = NULL, *t_port = NULL; |
1456 | char *orig, *ptr, *arg_p, *opts; | 1457 | char *orig, *ptr, *arg_p, *opts; |
1457 | substring_t args[MAX_OPT_ARGS]; | 1458 | substring_t args[MAX_OPT_ARGS]; |
1458 | unsigned long long tmp_ll; | 1459 | unsigned long long tmp_ll; |
@@ -1488,9 +1489,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1488 | switch (token) { | 1489 | switch (token) { |
1489 | case Opt_initiator_fabric: | 1490 | case Opt_initiator_fabric: |
1490 | i_fabric = match_strdup(&args[0]); | 1491 | i_fabric = match_strdup(&args[0]); |
1492 | if (!i_fabric) { | ||
1493 | ret = -ENOMEM; | ||
1494 | goto out; | ||
1495 | } | ||
1491 | break; | 1496 | break; |
1492 | case Opt_initiator_node: | 1497 | case Opt_initiator_node: |
1493 | i_port = match_strdup(&args[0]); | 1498 | i_port = match_strdup(&args[0]); |
1499 | if (!i_port) { | ||
1500 | ret = -ENOMEM; | ||
1501 | goto out; | ||
1502 | } | ||
1494 | if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { | 1503 | if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { |
1495 | printk(KERN_ERR "APTPL metadata initiator_node=" | 1504 | printk(KERN_ERR "APTPL metadata initiator_node=" |
1496 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", | 1505 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", |
@@ -1501,6 +1510,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1501 | break; | 1510 | break; |
1502 | case Opt_initiator_sid: | 1511 | case Opt_initiator_sid: |
1503 | isid = match_strdup(&args[0]); | 1512 | isid = match_strdup(&args[0]); |
1513 | if (!isid) { | ||
1514 | ret = -ENOMEM; | ||
1515 | goto out; | ||
1516 | } | ||
1504 | if (strlen(isid) > PR_REG_ISID_LEN) { | 1517 | if (strlen(isid) > PR_REG_ISID_LEN) { |
1505 | printk(KERN_ERR "APTPL metadata initiator_isid" | 1518 | printk(KERN_ERR "APTPL metadata initiator_isid" |
1506 | "= exceeds PR_REG_ISID_LEN: %d\n", | 1519 | "= exceeds PR_REG_ISID_LEN: %d\n", |
@@ -1511,6 +1524,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1511 | break; | 1524 | break; |
1512 | case Opt_sa_res_key: | 1525 | case Opt_sa_res_key: |
1513 | arg_p = match_strdup(&args[0]); | 1526 | arg_p = match_strdup(&args[0]); |
1527 | if (!arg_p) { | ||
1528 | ret = -ENOMEM; | ||
1529 | goto out; | ||
1530 | } | ||
1514 | ret = strict_strtoull(arg_p, 0, &tmp_ll); | 1531 | ret = strict_strtoull(arg_p, 0, &tmp_ll); |
1515 | if (ret < 0) { | 1532 | if (ret < 0) { |
1516 | printk(KERN_ERR "strict_strtoull() failed for" | 1533 | printk(KERN_ERR "strict_strtoull() failed for" |
@@ -1547,9 +1564,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1547 | */ | 1564 | */ |
1548 | case Opt_target_fabric: | 1565 | case Opt_target_fabric: |
1549 | t_fabric = match_strdup(&args[0]); | 1566 | t_fabric = match_strdup(&args[0]); |
1567 | if (!t_fabric) { | ||
1568 | ret = -ENOMEM; | ||
1569 | goto out; | ||
1570 | } | ||
1550 | break; | 1571 | break; |
1551 | case Opt_target_node: | 1572 | case Opt_target_node: |
1552 | t_port = match_strdup(&args[0]); | 1573 | t_port = match_strdup(&args[0]); |
1574 | if (!t_port) { | ||
1575 | ret = -ENOMEM; | ||
1576 | goto out; | ||
1577 | } | ||
1553 | if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { | 1578 | if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { |
1554 | printk(KERN_ERR "APTPL metadata target_node=" | 1579 | printk(KERN_ERR "APTPL metadata target_node=" |
1555 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", | 1580 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", |
@@ -1592,6 +1617,11 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1592 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, | 1617 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, |
1593 | res_holder, all_tg_pt, type); | 1618 | res_holder, all_tg_pt, type); |
1594 | out: | 1619 | out: |
1620 | kfree(i_fabric); | ||
1621 | kfree(i_port); | ||
1622 | kfree(isid); | ||
1623 | kfree(t_fabric); | ||
1624 | kfree(t_port); | ||
1595 | kfree(orig); | 1625 | kfree(orig); |
1596 | return (ret == 0) ? count : ret; | 1626 | return (ret == 0) ? count : ret; |
1597 | } | 1627 | } |
@@ -1798,7 +1828,9 @@ static ssize_t target_core_store_dev_enable( | |||
1798 | return -EINVAL; | 1828 | return -EINVAL; |
1799 | 1829 | ||
1800 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); | 1830 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); |
1801 | if (!(dev) || IS_ERR(dev)) | 1831 | if (IS_ERR(dev)) |
1832 | return PTR_ERR(dev); | ||
1833 | else if (!dev) | ||
1802 | return -EINVAL; | 1834 | return -EINVAL; |
1803 | 1835 | ||
1804 | se_dev->se_dev_ptr = dev; | 1836 | se_dev->se_dev_ptr = dev; |
@@ -2678,6 +2710,34 @@ static struct config_item_type target_core_alua_cit = { | |||
2678 | 2710 | ||
2679 | /* End functions for struct config_item_type target_core_alua_cit */ | 2711 | /* End functions for struct config_item_type target_core_alua_cit */ |
2680 | 2712 | ||
2713 | /* Start functions for struct config_item_type target_core_stat_cit */ | ||
2714 | |||
2715 | static struct config_group *target_core_stat_mkdir( | ||
2716 | struct config_group *group, | ||
2717 | const char *name) | ||
2718 | { | ||
2719 | return ERR_PTR(-ENOSYS); | ||
2720 | } | ||
2721 | |||
2722 | static void target_core_stat_rmdir( | ||
2723 | struct config_group *group, | ||
2724 | struct config_item *item) | ||
2725 | { | ||
2726 | return; | ||
2727 | } | ||
2728 | |||
2729 | static struct configfs_group_operations target_core_stat_group_ops = { | ||
2730 | .make_group = &target_core_stat_mkdir, | ||
2731 | .drop_item = &target_core_stat_rmdir, | ||
2732 | }; | ||
2733 | |||
2734 | static struct config_item_type target_core_stat_cit = { | ||
2735 | .ct_group_ops = &target_core_stat_group_ops, | ||
2736 | .ct_owner = THIS_MODULE, | ||
2737 | }; | ||
2738 | |||
2739 | /* End functions for struct config_item_type target_core_stat_cit */ | ||
2740 | |||
2681 | /* Start functions for struct config_item_type target_core_hba_cit */ | 2741 | /* Start functions for struct config_item_type target_core_hba_cit */ |
2682 | 2742 | ||
2683 | static struct config_group *target_core_make_subdev( | 2743 | static struct config_group *target_core_make_subdev( |
@@ -2690,10 +2750,12 @@ static struct config_group *target_core_make_subdev( | |||
2690 | struct config_item *hba_ci = &group->cg_item; | 2750 | struct config_item *hba_ci = &group->cg_item; |
2691 | struct se_hba *hba = item_to_hba(hba_ci); | 2751 | struct se_hba *hba = item_to_hba(hba_ci); |
2692 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; | 2752 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; |
2753 | struct config_group *dev_stat_grp = NULL; | ||
2754 | int errno = -ENOMEM, ret; | ||
2693 | 2755 | ||
2694 | if (mutex_lock_interruptible(&hba->hba_access_mutex)) | 2756 | ret = mutex_lock_interruptible(&hba->hba_access_mutex); |
2695 | return NULL; | 2757 | if (ret) |
2696 | 2758 | return ERR_PTR(ret); | |
2697 | /* | 2759 | /* |
2698 | * Locate the struct se_subsystem_api from parent's struct se_hba. | 2760 | * Locate the struct se_subsystem_api from parent's struct se_hba. |
2699 | */ | 2761 | */ |
@@ -2723,7 +2785,7 @@ static struct config_group *target_core_make_subdev( | |||
2723 | se_dev->se_dev_hba = hba; | 2785 | se_dev->se_dev_hba = hba; |
2724 | dev_cg = &se_dev->se_dev_group; | 2786 | dev_cg = &se_dev->se_dev_group; |
2725 | 2787 | ||
2726 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, | 2788 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, |
2727 | GFP_KERNEL); | 2789 | GFP_KERNEL); |
2728 | if (!(dev_cg->default_groups)) | 2790 | if (!(dev_cg->default_groups)) |
2729 | goto out; | 2791 | goto out; |
@@ -2755,13 +2817,17 @@ static struct config_group *target_core_make_subdev( | |||
2755 | &target_core_dev_wwn_cit); | 2817 | &target_core_dev_wwn_cit); |
2756 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, | 2818 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, |
2757 | "alua", &target_core_alua_tg_pt_gps_cit); | 2819 | "alua", &target_core_alua_tg_pt_gps_cit); |
2820 | config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, | ||
2821 | "statistics", &target_core_stat_cit); | ||
2822 | |||
2758 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; | 2823 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; |
2759 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; | 2824 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; |
2760 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; | 2825 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; |
2761 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; | 2826 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; |
2762 | dev_cg->default_groups[4] = NULL; | 2827 | dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; |
2828 | dev_cg->default_groups[5] = NULL; | ||
2763 | /* | 2829 | /* |
2764 | * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp | 2830 | * Add core/$HBA/$DEV/alua/default_tg_pt_gp |
2765 | */ | 2831 | */ |
2766 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); | 2832 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); |
2767 | if (!(tg_pt_gp)) | 2833 | if (!(tg_pt_gp)) |
@@ -2781,6 +2847,17 @@ static struct config_group *target_core_make_subdev( | |||
2781 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; | 2847 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; |
2782 | tg_pt_gp_cg->default_groups[1] = NULL; | 2848 | tg_pt_gp_cg->default_groups[1] = NULL; |
2783 | T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; | 2849 | T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; |
2850 | /* | ||
2851 | * Add core/$HBA/$DEV/statistics/ default groups | ||
2852 | */ | ||
2853 | dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; | ||
2854 | dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, | ||
2855 | GFP_KERNEL); | ||
2856 | if (!dev_stat_grp->default_groups) { | ||
2857 | printk(KERN_ERR "Unable to allocate dev_stat_grp->default_groups\n"); | ||
2858 | goto out; | ||
2859 | } | ||
2860 | target_stat_setup_dev_default_groups(se_dev); | ||
2784 | 2861 | ||
2785 | printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" | 2862 | printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" |
2786 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); | 2863 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); |
@@ -2792,6 +2869,8 @@ out: | |||
2792 | core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); | 2869 | core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); |
2793 | T10_ALUA(se_dev)->default_tg_pt_gp = NULL; | 2870 | T10_ALUA(se_dev)->default_tg_pt_gp = NULL; |
2794 | } | 2871 | } |
2872 | if (dev_stat_grp) | ||
2873 | kfree(dev_stat_grp->default_groups); | ||
2795 | if (tg_pt_gp_cg) | 2874 | if (tg_pt_gp_cg) |
2796 | kfree(tg_pt_gp_cg->default_groups); | 2875 | kfree(tg_pt_gp_cg->default_groups); |
2797 | if (dev_cg) | 2876 | if (dev_cg) |
@@ -2801,7 +2880,7 @@ out: | |||
2801 | kfree(se_dev); | 2880 | kfree(se_dev); |
2802 | unlock: | 2881 | unlock: |
2803 | mutex_unlock(&hba->hba_access_mutex); | 2882 | mutex_unlock(&hba->hba_access_mutex); |
2804 | return NULL; | 2883 | return ERR_PTR(errno); |
2805 | } | 2884 | } |
2806 | 2885 | ||
2807 | static void target_core_drop_subdev( | 2886 | static void target_core_drop_subdev( |
@@ -2813,7 +2892,7 @@ static void target_core_drop_subdev( | |||
2813 | struct se_hba *hba; | 2892 | struct se_hba *hba; |
2814 | struct se_subsystem_api *t; | 2893 | struct se_subsystem_api *t; |
2815 | struct config_item *df_item; | 2894 | struct config_item *df_item; |
2816 | struct config_group *dev_cg, *tg_pt_gp_cg; | 2895 | struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; |
2817 | int i; | 2896 | int i; |
2818 | 2897 | ||
2819 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); | 2898 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); |
@@ -2825,6 +2904,14 @@ static void target_core_drop_subdev( | |||
2825 | list_del(&se_dev->g_se_dev_list); | 2904 | list_del(&se_dev->g_se_dev_list); |
2826 | spin_unlock(&se_global->g_device_lock); | 2905 | spin_unlock(&se_global->g_device_lock); |
2827 | 2906 | ||
2907 | dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; | ||
2908 | for (i = 0; dev_stat_grp->default_groups[i]; i++) { | ||
2909 | df_item = &dev_stat_grp->default_groups[i]->cg_item; | ||
2910 | dev_stat_grp->default_groups[i] = NULL; | ||
2911 | config_item_put(df_item); | ||
2912 | } | ||
2913 | kfree(dev_stat_grp->default_groups); | ||
2914 | |||
2828 | tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; | 2915 | tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; |
2829 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { | 2916 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { |
2830 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; | 2917 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; |
@@ -3044,7 +3131,7 @@ static struct config_item_type target_core_cit = { | |||
3044 | 3131 | ||
3045 | /* Stop functions for struct config_item_type target_core_hba_cit */ | 3132 | /* Stop functions for struct config_item_type target_core_hba_cit */ |
3046 | 3133 | ||
3047 | static int target_core_init_configfs(void) | 3134 | static int __init target_core_init_configfs(void) |
3048 | { | 3135 | { |
3049 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; | 3136 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; |
3050 | struct config_group *lu_gp_cg = NULL; | 3137 | struct config_group *lu_gp_cg = NULL; |
@@ -3176,7 +3263,7 @@ out_global: | |||
3176 | return -1; | 3263 | return -1; |
3177 | } | 3264 | } |
3178 | 3265 | ||
3179 | static void target_core_exit_configfs(void) | 3266 | static void __exit target_core_exit_configfs(void) |
3180 | { | 3267 | { |
3181 | struct configfs_subsystem *subsys; | 3268 | struct configfs_subsystem *subsys; |
3182 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; | 3269 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; |
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 350ed401544e..d25e20829012 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -371,7 +371,7 @@ int core_update_device_list_for_node( | |||
371 | if (!(enable)) { | 371 | if (!(enable)) { |
372 | /* | 372 | /* |
373 | * deve->se_lun_acl will be NULL for demo-mode created LUNs | 373 | * deve->se_lun_acl will be NULL for demo-mode created LUNs |
374 | * that have not been explictly concerted to MappedLUNs -> | 374 | * that have not been explicitly concerted to MappedLUNs -> |
375 | * struct se_lun_acl, but we remove deve->alua_port_list from | 375 | * struct se_lun_acl, but we remove deve->alua_port_list from |
376 | * port->sep_alua_list. This also means that active UAs and | 376 | * port->sep_alua_list. This also means that active UAs and |
377 | * NodeACL context specific PR metadata for demo-mode | 377 | * NodeACL context specific PR metadata for demo-mode |
@@ -589,6 +589,7 @@ static void core_export_port( | |||
589 | * Called with struct se_device->se_port_lock spinlock held. | 589 | * Called with struct se_device->se_port_lock spinlock held. |
590 | */ | 590 | */ |
591 | static void core_release_port(struct se_device *dev, struct se_port *port) | 591 | static void core_release_port(struct se_device *dev, struct se_port *port) |
592 | __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) | ||
592 | { | 593 | { |
593 | /* | 594 | /* |
594 | * Wait for any port reference for PR ALL_TG_PT=1 operation | 595 | * Wait for any port reference for PR ALL_TG_PT=1 operation |
@@ -779,49 +780,14 @@ void se_release_vpd_for_dev(struct se_device *dev) | |||
779 | return; | 780 | return; |
780 | } | 781 | } |
781 | 782 | ||
782 | /* | ||
783 | * Called with struct se_hba->device_lock held. | ||
784 | */ | ||
785 | void se_clear_dev_ports(struct se_device *dev) | ||
786 | { | ||
787 | struct se_hba *hba = dev->se_hba; | ||
788 | struct se_lun *lun; | ||
789 | struct se_portal_group *tpg; | ||
790 | struct se_port *sep, *sep_tmp; | ||
791 | |||
792 | spin_lock(&dev->se_port_lock); | ||
793 | list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { | ||
794 | spin_unlock(&dev->se_port_lock); | ||
795 | spin_unlock(&hba->device_lock); | ||
796 | |||
797 | lun = sep->sep_lun; | ||
798 | tpg = sep->sep_tpg; | ||
799 | spin_lock(&lun->lun_sep_lock); | ||
800 | if (lun->lun_se_dev == NULL) { | ||
801 | spin_unlock(&lun->lun_sep_lock); | ||
802 | continue; | ||
803 | } | ||
804 | spin_unlock(&lun->lun_sep_lock); | ||
805 | |||
806 | core_dev_del_lun(tpg, lun->unpacked_lun); | ||
807 | |||
808 | spin_lock(&hba->device_lock); | ||
809 | spin_lock(&dev->se_port_lock); | ||
810 | } | ||
811 | spin_unlock(&dev->se_port_lock); | ||
812 | |||
813 | return; | ||
814 | } | ||
815 | |||
816 | /* se_free_virtual_device(): | 783 | /* se_free_virtual_device(): |
817 | * | 784 | * |
818 | * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. | 785 | * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. |
819 | */ | 786 | */ |
820 | int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) | 787 | int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) |
821 | { | 788 | { |
822 | spin_lock(&hba->device_lock); | 789 | if (!list_empty(&dev->dev_sep_list)) |
823 | se_clear_dev_ports(dev); | 790 | dump_stack(); |
824 | spin_unlock(&hba->device_lock); | ||
825 | 791 | ||
826 | core_alua_free_lu_gp_mem(dev); | 792 | core_alua_free_lu_gp_mem(dev); |
827 | se_release_device_for_hba(dev); | 793 | se_release_device_for_hba(dev); |
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index b65d1c8e7740..07ab5a3bb8e8 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c | |||
@@ -4,10 +4,10 @@ | |||
4 | * This file contains generic fabric module configfs infrastructure for | 4 | * This file contains generic fabric module configfs infrastructure for |
5 | * TCM v4.x code | 5 | * TCM v4.x code |
6 | * | 6 | * |
7 | * Copyright (c) 2010 Rising Tide Systems | 7 | * Copyright (c) 2010,2011 Rising Tide Systems |
8 | * Copyright (c) 2010 Linux-iSCSI.org | 8 | * Copyright (c) 2010,2011 Linux-iSCSI.org |
9 | * | 9 | * |
10 | * Copyright (c) 2010 Nicholas A. Bellinger <nab@linux-iscsi.org> | 10 | * Copyright (c) Nicholas A. Bellinger <nab@linux-iscsi.org> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -48,6 +48,7 @@ | |||
48 | #include "target_core_alua.h" | 48 | #include "target_core_alua.h" |
49 | #include "target_core_hba.h" | 49 | #include "target_core_hba.h" |
50 | #include "target_core_pr.h" | 50 | #include "target_core_pr.h" |
51 | #include "target_core_stat.h" | ||
51 | 52 | ||
52 | #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ | 53 | #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ |
53 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ | 54 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ |
@@ -241,6 +242,32 @@ TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, | |||
241 | 242 | ||
242 | /* End of tfc_tpg_mappedlun_cit */ | 243 | /* End of tfc_tpg_mappedlun_cit */ |
243 | 244 | ||
245 | /* Start of tfc_tpg_mappedlun_port_cit */ | ||
246 | |||
247 | static struct config_group *target_core_mappedlun_stat_mkdir( | ||
248 | struct config_group *group, | ||
249 | const char *name) | ||
250 | { | ||
251 | return ERR_PTR(-ENOSYS); | ||
252 | } | ||
253 | |||
254 | static void target_core_mappedlun_stat_rmdir( | ||
255 | struct config_group *group, | ||
256 | struct config_item *item) | ||
257 | { | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { | ||
262 | .make_group = target_core_mappedlun_stat_mkdir, | ||
263 | .drop_item = target_core_mappedlun_stat_rmdir, | ||
264 | }; | ||
265 | |||
266 | TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, | ||
267 | NULL); | ||
268 | |||
269 | /* End of tfc_tpg_mappedlun_port_cit */ | ||
270 | |||
244 | /* Start of tfc_tpg_nacl_attrib_cit */ | 271 | /* Start of tfc_tpg_nacl_attrib_cit */ |
245 | 272 | ||
246 | CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); | 273 | CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); |
@@ -294,6 +321,7 @@ static struct config_group *target_fabric_make_mappedlun( | |||
294 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | 321 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; |
295 | struct se_lun_acl *lacl; | 322 | struct se_lun_acl *lacl; |
296 | struct config_item *acl_ci; | 323 | struct config_item *acl_ci; |
324 | struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; | ||
297 | char *buf; | 325 | char *buf; |
298 | unsigned long mapped_lun; | 326 | unsigned long mapped_lun; |
299 | int ret = 0; | 327 | int ret = 0; |
@@ -330,15 +358,42 @@ static struct config_group *target_fabric_make_mappedlun( | |||
330 | 358 | ||
331 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, | 359 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, |
332 | config_item_name(acl_ci), &ret); | 360 | config_item_name(acl_ci), &ret); |
333 | if (!(lacl)) | 361 | if (!(lacl)) { |
362 | ret = -EINVAL; | ||
334 | goto out; | 363 | goto out; |
364 | } | ||
365 | |||
366 | lacl_cg = &lacl->se_lun_group; | ||
367 | lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | ||
368 | GFP_KERNEL); | ||
369 | if (!lacl_cg->default_groups) { | ||
370 | printk(KERN_ERR "Unable to allocate lacl_cg->default_groups\n"); | ||
371 | ret = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
335 | 374 | ||
336 | config_group_init_type_name(&lacl->se_lun_group, name, | 375 | config_group_init_type_name(&lacl->se_lun_group, name, |
337 | &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); | 376 | &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); |
377 | config_group_init_type_name(&lacl->ml_stat_grps.stat_group, | ||
378 | "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit); | ||
379 | lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; | ||
380 | lacl_cg->default_groups[1] = NULL; | ||
381 | |||
382 | ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
383 | ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, | ||
384 | GFP_KERNEL); | ||
385 | if (!ml_stat_grp->default_groups) { | ||
386 | printk(KERN_ERR "Unable to allocate ml_stat_grp->default_groups\n"); | ||
387 | ret = -ENOMEM; | ||
388 | goto out; | ||
389 | } | ||
390 | target_stat_setup_mappedlun_default_groups(lacl); | ||
338 | 391 | ||
339 | kfree(buf); | 392 | kfree(buf); |
340 | return &lacl->se_lun_group; | 393 | return &lacl->se_lun_group; |
341 | out: | 394 | out: |
395 | if (lacl_cg) | ||
396 | kfree(lacl_cg->default_groups); | ||
342 | kfree(buf); | 397 | kfree(buf); |
343 | return ERR_PTR(ret); | 398 | return ERR_PTR(ret); |
344 | } | 399 | } |
@@ -347,6 +402,28 @@ static void target_fabric_drop_mappedlun( | |||
347 | struct config_group *group, | 402 | struct config_group *group, |
348 | struct config_item *item) | 403 | struct config_item *item) |
349 | { | 404 | { |
405 | struct se_lun_acl *lacl = container_of(to_config_group(item), | ||
406 | struct se_lun_acl, se_lun_group); | ||
407 | struct config_item *df_item; | ||
408 | struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; | ||
409 | int i; | ||
410 | |||
411 | ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
412 | for (i = 0; ml_stat_grp->default_groups[i]; i++) { | ||
413 | df_item = &ml_stat_grp->default_groups[i]->cg_item; | ||
414 | ml_stat_grp->default_groups[i] = NULL; | ||
415 | config_item_put(df_item); | ||
416 | } | ||
417 | kfree(ml_stat_grp->default_groups); | ||
418 | |||
419 | lacl_cg = &lacl->se_lun_group; | ||
420 | for (i = 0; lacl_cg->default_groups[i]; i++) { | ||
421 | df_item = &lacl_cg->default_groups[i]->cg_item; | ||
422 | lacl_cg->default_groups[i] = NULL; | ||
423 | config_item_put(df_item); | ||
424 | } | ||
425 | kfree(lacl_cg->default_groups); | ||
426 | |||
350 | config_item_put(item); | 427 | config_item_put(item); |
351 | } | 428 | } |
352 | 429 | ||
@@ -376,6 +453,15 @@ TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, | |||
376 | 453 | ||
377 | /* End of tfc_tpg_nacl_base_cit */ | 454 | /* End of tfc_tpg_nacl_base_cit */ |
378 | 455 | ||
456 | /* Start of tfc_node_fabric_stats_cit */ | ||
457 | /* | ||
458 | * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group | ||
459 | * to allow fabrics access to ->acl_fabric_stat_group->default_groups[] | ||
460 | */ | ||
461 | TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL); | ||
462 | |||
463 | /* End of tfc_wwn_fabric_stats_cit */ | ||
464 | |||
379 | /* Start of tfc_tpg_nacl_cit */ | 465 | /* Start of tfc_tpg_nacl_cit */ |
380 | 466 | ||
381 | static struct config_group *target_fabric_make_nodeacl( | 467 | static struct config_group *target_fabric_make_nodeacl( |
@@ -402,7 +488,8 @@ static struct config_group *target_fabric_make_nodeacl( | |||
402 | nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; | 488 | nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; |
403 | nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; | 489 | nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; |
404 | nacl_cg->default_groups[2] = &se_nacl->acl_param_group; | 490 | nacl_cg->default_groups[2] = &se_nacl->acl_param_group; |
405 | nacl_cg->default_groups[3] = NULL; | 491 | nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group; |
492 | nacl_cg->default_groups[4] = NULL; | ||
406 | 493 | ||
407 | config_group_init_type_name(&se_nacl->acl_group, name, | 494 | config_group_init_type_name(&se_nacl->acl_group, name, |
408 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); | 495 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); |
@@ -412,6 +499,9 @@ static struct config_group *target_fabric_make_nodeacl( | |||
412 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); | 499 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); |
413 | config_group_init_type_name(&se_nacl->acl_param_group, "param", | 500 | config_group_init_type_name(&se_nacl->acl_param_group, "param", |
414 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); | 501 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); |
502 | config_group_init_type_name(&se_nacl->acl_fabric_stat_group, | ||
503 | "fabric_statistics", | ||
504 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit); | ||
415 | 505 | ||
416 | return &se_nacl->acl_group; | 506 | return &se_nacl->acl_group; |
417 | } | 507 | } |
@@ -758,6 +848,31 @@ TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_at | |||
758 | 848 | ||
759 | /* End of tfc_tpg_port_cit */ | 849 | /* End of tfc_tpg_port_cit */ |
760 | 850 | ||
851 | /* Start of tfc_tpg_port_stat_cit */ | ||
852 | |||
853 | static struct config_group *target_core_port_stat_mkdir( | ||
854 | struct config_group *group, | ||
855 | const char *name) | ||
856 | { | ||
857 | return ERR_PTR(-ENOSYS); | ||
858 | } | ||
859 | |||
860 | static void target_core_port_stat_rmdir( | ||
861 | struct config_group *group, | ||
862 | struct config_item *item) | ||
863 | { | ||
864 | return; | ||
865 | } | ||
866 | |||
867 | static struct configfs_group_operations target_fabric_port_stat_group_ops = { | ||
868 | .make_group = target_core_port_stat_mkdir, | ||
869 | .drop_item = target_core_port_stat_rmdir, | ||
870 | }; | ||
871 | |||
872 | TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL); | ||
873 | |||
874 | /* End of tfc_tpg_port_stat_cit */ | ||
875 | |||
761 | /* Start of tfc_tpg_lun_cit */ | 876 | /* Start of tfc_tpg_lun_cit */ |
762 | 877 | ||
763 | static struct config_group *target_fabric_make_lun( | 878 | static struct config_group *target_fabric_make_lun( |
@@ -768,7 +883,9 @@ static struct config_group *target_fabric_make_lun( | |||
768 | struct se_portal_group *se_tpg = container_of(group, | 883 | struct se_portal_group *se_tpg = container_of(group, |
769 | struct se_portal_group, tpg_lun_group); | 884 | struct se_portal_group, tpg_lun_group); |
770 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | 885 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; |
886 | struct config_group *lun_cg = NULL, *port_stat_grp = NULL; | ||
771 | unsigned long unpacked_lun; | 887 | unsigned long unpacked_lun; |
888 | int errno; | ||
772 | 889 | ||
773 | if (strstr(name, "lun_") != name) { | 890 | if (strstr(name, "lun_") != name) { |
774 | printk(KERN_ERR "Unable to locate \'_\" in" | 891 | printk(KERN_ERR "Unable to locate \'_\" in" |
@@ -782,16 +899,64 @@ static struct config_group *target_fabric_make_lun( | |||
782 | if (!(lun)) | 899 | if (!(lun)) |
783 | return ERR_PTR(-EINVAL); | 900 | return ERR_PTR(-EINVAL); |
784 | 901 | ||
902 | lun_cg = &lun->lun_group; | ||
903 | lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | ||
904 | GFP_KERNEL); | ||
905 | if (!lun_cg->default_groups) { | ||
906 | printk(KERN_ERR "Unable to allocate lun_cg->default_groups\n"); | ||
907 | return ERR_PTR(-ENOMEM); | ||
908 | } | ||
909 | |||
785 | config_group_init_type_name(&lun->lun_group, name, | 910 | config_group_init_type_name(&lun->lun_group, name, |
786 | &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); | 911 | &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); |
912 | config_group_init_type_name(&lun->port_stat_grps.stat_group, | ||
913 | "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit); | ||
914 | lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; | ||
915 | lun_cg->default_groups[1] = NULL; | ||
916 | |||
917 | port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
918 | port_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, | ||
919 | GFP_KERNEL); | ||
920 | if (!port_stat_grp->default_groups) { | ||
921 | printk(KERN_ERR "Unable to allocate port_stat_grp->default_groups\n"); | ||
922 | errno = -ENOMEM; | ||
923 | goto out; | ||
924 | } | ||
925 | target_stat_setup_port_default_groups(lun); | ||
787 | 926 | ||
788 | return &lun->lun_group; | 927 | return &lun->lun_group; |
928 | out: | ||
929 | if (lun_cg) | ||
930 | kfree(lun_cg->default_groups); | ||
931 | return ERR_PTR(errno); | ||
789 | } | 932 | } |
790 | 933 | ||
791 | static void target_fabric_drop_lun( | 934 | static void target_fabric_drop_lun( |
792 | struct config_group *group, | 935 | struct config_group *group, |
793 | struct config_item *item) | 936 | struct config_item *item) |
794 | { | 937 | { |
938 | struct se_lun *lun = container_of(to_config_group(item), | ||
939 | struct se_lun, lun_group); | ||
940 | struct config_item *df_item; | ||
941 | struct config_group *lun_cg, *port_stat_grp; | ||
942 | int i; | ||
943 | |||
944 | port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
945 | for (i = 0; port_stat_grp->default_groups[i]; i++) { | ||
946 | df_item = &port_stat_grp->default_groups[i]->cg_item; | ||
947 | port_stat_grp->default_groups[i] = NULL; | ||
948 | config_item_put(df_item); | ||
949 | } | ||
950 | kfree(port_stat_grp->default_groups); | ||
951 | |||
952 | lun_cg = &lun->lun_group; | ||
953 | for (i = 0; lun_cg->default_groups[i]; i++) { | ||
954 | df_item = &lun_cg->default_groups[i]->cg_item; | ||
955 | lun_cg->default_groups[i] = NULL; | ||
956 | config_item_put(df_item); | ||
957 | } | ||
958 | kfree(lun_cg->default_groups); | ||
959 | |||
795 | config_item_put(item); | 960 | config_item_put(item); |
796 | } | 961 | } |
797 | 962 | ||
@@ -946,6 +1111,15 @@ TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, | |||
946 | 1111 | ||
947 | /* End of tfc_tpg_cit */ | 1112 | /* End of tfc_tpg_cit */ |
948 | 1113 | ||
1114 | /* Start of tfc_wwn_fabric_stats_cit */ | ||
1115 | /* | ||
1116 | * This is used as a placeholder for struct se_wwn->fabric_stat_group | ||
1117 | * to allow fabrics access to ->fabric_stat_group->default_groups[] | ||
1118 | */ | ||
1119 | TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL); | ||
1120 | |||
1121 | /* End of tfc_wwn_fabric_stats_cit */ | ||
1122 | |||
949 | /* Start of tfc_wwn_cit */ | 1123 | /* Start of tfc_wwn_cit */ |
950 | 1124 | ||
951 | static struct config_group *target_fabric_make_wwn( | 1125 | static struct config_group *target_fabric_make_wwn( |
@@ -966,8 +1140,17 @@ static struct config_group *target_fabric_make_wwn( | |||
966 | return ERR_PTR(-EINVAL); | 1140 | return ERR_PTR(-EINVAL); |
967 | 1141 | ||
968 | wwn->wwn_tf = tf; | 1142 | wwn->wwn_tf = tf; |
1143 | /* | ||
1144 | * Setup default groups from pre-allocated wwn->wwn_default_groups | ||
1145 | */ | ||
1146 | wwn->wwn_group.default_groups = wwn->wwn_default_groups; | ||
1147 | wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; | ||
1148 | wwn->wwn_group.default_groups[1] = NULL; | ||
1149 | |||
969 | config_group_init_type_name(&wwn->wwn_group, name, | 1150 | config_group_init_type_name(&wwn->wwn_group, name, |
970 | &TF_CIT_TMPL(tf)->tfc_tpg_cit); | 1151 | &TF_CIT_TMPL(tf)->tfc_tpg_cit); |
1152 | config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", | ||
1153 | &TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit); | ||
971 | 1154 | ||
972 | return &wwn->wwn_group; | 1155 | return &wwn->wwn_group; |
973 | } | 1156 | } |
@@ -976,6 +1159,18 @@ static void target_fabric_drop_wwn( | |||
976 | struct config_group *group, | 1159 | struct config_group *group, |
977 | struct config_item *item) | 1160 | struct config_item *item) |
978 | { | 1161 | { |
1162 | struct se_wwn *wwn = container_of(to_config_group(item), | ||
1163 | struct se_wwn, wwn_group); | ||
1164 | struct config_item *df_item; | ||
1165 | struct config_group *cg = &wwn->wwn_group; | ||
1166 | int i; | ||
1167 | |||
1168 | for (i = 0; cg->default_groups[i]; i++) { | ||
1169 | df_item = &cg->default_groups[i]->cg_item; | ||
1170 | cg->default_groups[i] = NULL; | ||
1171 | config_item_put(df_item); | ||
1172 | } | ||
1173 | |||
979 | config_item_put(item); | 1174 | config_item_put(item); |
980 | } | 1175 | } |
981 | 1176 | ||
@@ -1015,9 +1210,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) | |||
1015 | { | 1210 | { |
1016 | target_fabric_setup_discovery_cit(tf); | 1211 | target_fabric_setup_discovery_cit(tf); |
1017 | target_fabric_setup_wwn_cit(tf); | 1212 | target_fabric_setup_wwn_cit(tf); |
1213 | target_fabric_setup_wwn_fabric_stats_cit(tf); | ||
1018 | target_fabric_setup_tpg_cit(tf); | 1214 | target_fabric_setup_tpg_cit(tf); |
1019 | target_fabric_setup_tpg_base_cit(tf); | 1215 | target_fabric_setup_tpg_base_cit(tf); |
1020 | target_fabric_setup_tpg_port_cit(tf); | 1216 | target_fabric_setup_tpg_port_cit(tf); |
1217 | target_fabric_setup_tpg_port_stat_cit(tf); | ||
1021 | target_fabric_setup_tpg_lun_cit(tf); | 1218 | target_fabric_setup_tpg_lun_cit(tf); |
1022 | target_fabric_setup_tpg_np_cit(tf); | 1219 | target_fabric_setup_tpg_np_cit(tf); |
1023 | target_fabric_setup_tpg_np_base_cit(tf); | 1220 | target_fabric_setup_tpg_np_base_cit(tf); |
@@ -1028,7 +1225,9 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) | |||
1028 | target_fabric_setup_tpg_nacl_attrib_cit(tf); | 1225 | target_fabric_setup_tpg_nacl_attrib_cit(tf); |
1029 | target_fabric_setup_tpg_nacl_auth_cit(tf); | 1226 | target_fabric_setup_tpg_nacl_auth_cit(tf); |
1030 | target_fabric_setup_tpg_nacl_param_cit(tf); | 1227 | target_fabric_setup_tpg_nacl_param_cit(tf); |
1228 | target_fabric_setup_tpg_nacl_stat_cit(tf); | ||
1031 | target_fabric_setup_tpg_mappedlun_cit(tf); | 1229 | target_fabric_setup_tpg_mappedlun_cit(tf); |
1230 | target_fabric_setup_tpg_mappedlun_stat_cit(tf); | ||
1032 | 1231 | ||
1033 | return 0; | 1232 | return 0; |
1034 | } | 1233 | } |
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index a3c695adabec..1e193f324895 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <target/target_core_base.h> | 34 | #include <target/target_core_base.h> |
35 | #include <target/target_core_device.h> | 35 | #include <target/target_core_device.h> |
36 | #include <target/target_core_transport.h> | 36 | #include <target/target_core_transport.h> |
37 | #include <target/target_core_fabric_lib.h> | ||
37 | #include <target/target_core_fabric_ops.h> | 38 | #include <target/target_core_fabric_ops.h> |
38 | #include <target/target_core_configfs.h> | 39 | #include <target/target_core_configfs.h> |
39 | 40 | ||
@@ -432,7 +433,7 @@ char *iscsi_parse_pr_out_transport_id( | |||
432 | /* | 433 | /* |
433 | * Go ahead and do the lower case conversion of the received | 434 | * Go ahead and do the lower case conversion of the received |
434 | * 12 ASCII characters representing the ISID in the TransportID | 435 | * 12 ASCII characters representing the ISID in the TransportID |
435 | * for comparision against the running iSCSI session's ISID from | 436 | * for comparison against the running iSCSI session's ISID from |
436 | * iscsi_target.c:lio_sess_get_initiator_sid() | 437 | * iscsi_target.c:lio_sess_get_initiator_sid() |
437 | */ | 438 | */ |
438 | for (i = 0; i < 12; i++) { | 439 | for (i = 0; i < 12; i++) { |
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 190ca8ac2498..150c4305f385 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -134,7 +134,7 @@ static struct se_device *fd_create_virtdevice( | |||
134 | mm_segment_t old_fs; | 134 | mm_segment_t old_fs; |
135 | struct file *file; | 135 | struct file *file; |
136 | struct inode *inode = NULL; | 136 | struct inode *inode = NULL; |
137 | int dev_flags = 0, flags; | 137 | int dev_flags = 0, flags, ret = -EINVAL; |
138 | 138 | ||
139 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 139 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
140 | 140 | ||
@@ -146,6 +146,7 @@ static struct se_device *fd_create_virtdevice( | |||
146 | if (IS_ERR(dev_p)) { | 146 | if (IS_ERR(dev_p)) { |
147 | printk(KERN_ERR "getname(%s) failed: %lu\n", | 147 | printk(KERN_ERR "getname(%s) failed: %lu\n", |
148 | fd_dev->fd_dev_name, IS_ERR(dev_p)); | 148 | fd_dev->fd_dev_name, IS_ERR(dev_p)); |
149 | ret = PTR_ERR(dev_p); | ||
149 | goto fail; | 150 | goto fail; |
150 | } | 151 | } |
151 | #if 0 | 152 | #if 0 |
@@ -158,15 +159,19 @@ static struct se_device *fd_create_virtdevice( | |||
158 | #endif | 159 | #endif |
159 | /* flags |= O_DIRECT; */ | 160 | /* flags |= O_DIRECT; */ |
160 | /* | 161 | /* |
161 | * If fd_buffered_io=1 has not been set explictly (the default), | 162 | * If fd_buffered_io=1 has not been set explicitly (the default), |
162 | * use O_SYNC to force FILEIO writes to disk. | 163 | * use O_SYNC to force FILEIO writes to disk. |
163 | */ | 164 | */ |
164 | if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) | 165 | if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) |
165 | flags |= O_SYNC; | 166 | flags |= O_SYNC; |
166 | 167 | ||
167 | file = filp_open(dev_p, flags, 0600); | 168 | file = filp_open(dev_p, flags, 0600); |
168 | 169 | if (IS_ERR(file)) { | |
169 | if (IS_ERR(file) || !file || !file->f_dentry) { | 170 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); |
171 | ret = PTR_ERR(file); | ||
172 | goto fail; | ||
173 | } | ||
174 | if (!file || !file->f_dentry) { | ||
170 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); | 175 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); |
171 | goto fail; | 176 | goto fail; |
172 | } | 177 | } |
@@ -241,7 +246,7 @@ fail: | |||
241 | fd_dev->fd_file = NULL; | 246 | fd_dev->fd_file = NULL; |
242 | } | 247 | } |
243 | putname(dev_p); | 248 | putname(dev_p); |
244 | return NULL; | 249 | return ERR_PTR(ret); |
245 | } | 250 | } |
246 | 251 | ||
247 | /* fd_free_device(): (Part of se_subsystem_api_t template) | 252 | /* fd_free_device(): (Part of se_subsystem_api_t template) |
@@ -509,7 +514,7 @@ enum { | |||
509 | static match_table_t tokens = { | 514 | static match_table_t tokens = { |
510 | {Opt_fd_dev_name, "fd_dev_name=%s"}, | 515 | {Opt_fd_dev_name, "fd_dev_name=%s"}, |
511 | {Opt_fd_dev_size, "fd_dev_size=%s"}, | 516 | {Opt_fd_dev_size, "fd_dev_size=%s"}, |
512 | {Opt_fd_buffered_io, "fd_buffered_id=%d"}, | 517 | {Opt_fd_buffered_io, "fd_buffered_io=%d"}, |
513 | {Opt_err, NULL} | 518 | {Opt_err, NULL} |
514 | }; | 519 | }; |
515 | 520 | ||
@@ -536,15 +541,26 @@ static ssize_t fd_set_configfs_dev_params( | |||
536 | token = match_token(ptr, tokens, args); | 541 | token = match_token(ptr, tokens, args); |
537 | switch (token) { | 542 | switch (token) { |
538 | case Opt_fd_dev_name: | 543 | case Opt_fd_dev_name: |
544 | arg_p = match_strdup(&args[0]); | ||
545 | if (!arg_p) { | ||
546 | ret = -ENOMEM; | ||
547 | break; | ||
548 | } | ||
539 | snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, | 549 | snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, |
540 | "%s", match_strdup(&args[0])); | 550 | "%s", arg_p); |
551 | kfree(arg_p); | ||
541 | printk(KERN_INFO "FILEIO: Referencing Path: %s\n", | 552 | printk(KERN_INFO "FILEIO: Referencing Path: %s\n", |
542 | fd_dev->fd_dev_name); | 553 | fd_dev->fd_dev_name); |
543 | fd_dev->fbd_flags |= FBDF_HAS_PATH; | 554 | fd_dev->fbd_flags |= FBDF_HAS_PATH; |
544 | break; | 555 | break; |
545 | case Opt_fd_dev_size: | 556 | case Opt_fd_dev_size: |
546 | arg_p = match_strdup(&args[0]); | 557 | arg_p = match_strdup(&args[0]); |
558 | if (!arg_p) { | ||
559 | ret = -ENOMEM; | ||
560 | break; | ||
561 | } | ||
547 | ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); | 562 | ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); |
563 | kfree(arg_p); | ||
548 | if (ret < 0) { | 564 | if (ret < 0) { |
549 | printk(KERN_ERR "strict_strtoull() failed for" | 565 | printk(KERN_ERR "strict_strtoull() failed for" |
550 | " fd_dev_size=\n"); | 566 | " fd_dev_size=\n"); |
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 6ec51cbc018e..0b8f8da89019 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c | |||
@@ -151,19 +151,8 @@ out_free_hba: | |||
151 | int | 151 | int |
152 | core_delete_hba(struct se_hba *hba) | 152 | core_delete_hba(struct se_hba *hba) |
153 | { | 153 | { |
154 | struct se_device *dev, *dev_tmp; | 154 | if (!list_empty(&hba->hba_dev_list)) |
155 | 155 | dump_stack(); | |
156 | spin_lock(&hba->device_lock); | ||
157 | list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) { | ||
158 | |||
159 | se_clear_dev_ports(dev); | ||
160 | spin_unlock(&hba->device_lock); | ||
161 | |||
162 | se_release_device_for_hba(dev); | ||
163 | |||
164 | spin_lock(&hba->device_lock); | ||
165 | } | ||
166 | spin_unlock(&hba->device_lock); | ||
167 | 156 | ||
168 | hba->transport->detach_hba(hba); | 157 | hba->transport->detach_hba(hba); |
169 | 158 | ||
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 3df570db0e4f..86639004af9e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -129,10 +129,11 @@ static struct se_device *iblock_create_virtdevice( | |||
129 | struct request_queue *q; | 129 | struct request_queue *q; |
130 | struct queue_limits *limits; | 130 | struct queue_limits *limits; |
131 | u32 dev_flags = 0; | 131 | u32 dev_flags = 0; |
132 | int ret = -EINVAL; | ||
132 | 133 | ||
133 | if (!(ib_dev)) { | 134 | if (!(ib_dev)) { |
134 | printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); | 135 | printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); |
135 | return 0; | 136 | return ERR_PTR(ret); |
136 | } | 137 | } |
137 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 138 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
138 | /* | 139 | /* |
@@ -141,7 +142,7 @@ static struct se_device *iblock_create_virtdevice( | |||
141 | ib_dev->ibd_bio_set = bioset_create(32, 64); | 142 | ib_dev->ibd_bio_set = bioset_create(32, 64); |
142 | if (!(ib_dev->ibd_bio_set)) { | 143 | if (!(ib_dev->ibd_bio_set)) { |
143 | printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); | 144 | printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); |
144 | return 0; | 145 | return ERR_PTR(-ENOMEM); |
145 | } | 146 | } |
146 | printk(KERN_INFO "IBLOCK: Created bio_set()\n"); | 147 | printk(KERN_INFO "IBLOCK: Created bio_set()\n"); |
147 | /* | 148 | /* |
@@ -153,8 +154,10 @@ static struct se_device *iblock_create_virtdevice( | |||
153 | 154 | ||
154 | bd = blkdev_get_by_path(ib_dev->ibd_udev_path, | 155 | bd = blkdev_get_by_path(ib_dev->ibd_udev_path, |
155 | FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); | 156 | FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); |
156 | if (IS_ERR(bd)) | 157 | if (IS_ERR(bd)) { |
158 | ret = PTR_ERR(bd); | ||
157 | goto failed; | 159 | goto failed; |
160 | } | ||
158 | /* | 161 | /* |
159 | * Setup the local scope queue_limits from struct request_queue->limits | 162 | * Setup the local scope queue_limits from struct request_queue->limits |
160 | * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. | 163 | * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. |
@@ -184,9 +187,7 @@ static struct se_device *iblock_create_virtdevice( | |||
184 | * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM | 187 | * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM |
185 | * in ATA and we need to set TPE=1 | 188 | * in ATA and we need to set TPE=1 |
186 | */ | 189 | */ |
187 | if (blk_queue_discard(bdev_get_queue(bd))) { | 190 | if (blk_queue_discard(q)) { |
188 | struct request_queue *q = bdev_get_queue(bd); | ||
189 | |||
190 | DEV_ATTRIB(dev)->max_unmap_lba_count = | 191 | DEV_ATTRIB(dev)->max_unmap_lba_count = |
191 | q->limits.max_discard_sectors; | 192 | q->limits.max_discard_sectors; |
192 | /* | 193 | /* |
@@ -212,7 +213,7 @@ failed: | |||
212 | ib_dev->ibd_bd = NULL; | 213 | ib_dev->ibd_bd = NULL; |
213 | ib_dev->ibd_major = 0; | 214 | ib_dev->ibd_major = 0; |
214 | ib_dev->ibd_minor = 0; | 215 | ib_dev->ibd_minor = 0; |
215 | return NULL; | 216 | return ERR_PTR(ret); |
216 | } | 217 | } |
217 | 218 | ||
218 | static void iblock_free_device(void *p) | 219 | static void iblock_free_device(void *p) |
@@ -391,9 +392,8 @@ static int iblock_do_task(struct se_task *task) | |||
391 | { | 392 | { |
392 | struct se_device *dev = task->task_se_cmd->se_dev; | 393 | struct se_device *dev = task->task_se_cmd->se_dev; |
393 | struct iblock_req *req = IBLOCK_REQ(task); | 394 | struct iblock_req *req = IBLOCK_REQ(task); |
394 | struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev; | ||
395 | struct request_queue *q = bdev_get_queue(ibd->ibd_bd); | ||
396 | struct bio *bio = req->ib_bio, *nbio = NULL; | 395 | struct bio *bio = req->ib_bio, *nbio = NULL; |
396 | struct blk_plug plug; | ||
397 | int rw; | 397 | int rw; |
398 | 398 | ||
399 | if (task->task_data_direction == DMA_TO_DEVICE) { | 399 | if (task->task_data_direction == DMA_TO_DEVICE) { |
@@ -411,6 +411,7 @@ static int iblock_do_task(struct se_task *task) | |||
411 | rw = READ; | 411 | rw = READ; |
412 | } | 412 | } |
413 | 413 | ||
414 | blk_start_plug(&plug); | ||
414 | while (bio) { | 415 | while (bio) { |
415 | nbio = bio->bi_next; | 416 | nbio = bio->bi_next; |
416 | bio->bi_next = NULL; | 417 | bio->bi_next = NULL; |
@@ -420,9 +421,8 @@ static int iblock_do_task(struct se_task *task) | |||
420 | submit_bio(rw, bio); | 421 | submit_bio(rw, bio); |
421 | bio = nbio; | 422 | bio = nbio; |
422 | } | 423 | } |
424 | blk_finish_plug(&plug); | ||
423 | 425 | ||
424 | if (q->unplug_fn) | ||
425 | q->unplug_fn(q); | ||
426 | return PYX_TRANSPORT_SENT_TO_TRANSPORT; | 426 | return PYX_TRANSPORT_SENT_TO_TRANSPORT; |
427 | } | 427 | } |
428 | 428 | ||
@@ -468,7 +468,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, | |||
468 | const char *page, ssize_t count) | 468 | const char *page, ssize_t count) |
469 | { | 469 | { |
470 | struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; | 470 | struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; |
471 | char *orig, *ptr, *opts; | 471 | char *orig, *ptr, *arg_p, *opts; |
472 | substring_t args[MAX_OPT_ARGS]; | 472 | substring_t args[MAX_OPT_ARGS]; |
473 | int ret = 0, arg, token; | 473 | int ret = 0, arg, token; |
474 | 474 | ||
@@ -491,9 +491,14 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, | |||
491 | ret = -EEXIST; | 491 | ret = -EEXIST; |
492 | goto out; | 492 | goto out; |
493 | } | 493 | } |
494 | 494 | arg_p = match_strdup(&args[0]); | |
495 | ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, | 495 | if (!arg_p) { |
496 | "%s", match_strdup(&args[0])); | 496 | ret = -ENOMEM; |
497 | break; | ||
498 | } | ||
499 | snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, | ||
500 | "%s", arg_p); | ||
501 | kfree(arg_p); | ||
497 | printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", | 502 | printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", |
498 | ib_dev->ibd_udev_path); | 503 | ib_dev->ibd_udev_path); |
499 | ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; | 504 | ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 2521f75362c3..a79f518ca6e2 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -478,7 +478,7 @@ static int core_scsi3_pr_seq_non_holder( | |||
478 | break; | 478 | break; |
479 | } | 479 | } |
480 | /* | 480 | /* |
481 | * Case where the CDB is explictly allowed in the above switch | 481 | * Case where the CDB is explicitly allowed in the above switch |
482 | * statement. | 482 | * statement. |
483 | */ | 483 | */ |
484 | if (!(ret) && !(other_cdb)) { | 484 | if (!(ret) && !(other_cdb)) { |
@@ -3735,7 +3735,7 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) | |||
3735 | return PYX_TRANSPORT_LU_COMM_FAILURE; | 3735 | return PYX_TRANSPORT_LU_COMM_FAILURE; |
3736 | 3736 | ||
3737 | if (cmd->data_length < 24) { | 3737 | if (cmd->data_length < 24) { |
3738 | printk(KERN_WARNING "SPC-PR: Recieved PR OUT parameter list" | 3738 | printk(KERN_WARNING "SPC-PR: Received PR OUT parameter list" |
3739 | " length too small: %u\n", cmd->data_length); | 3739 | " length too small: %u\n", cmd->data_length); |
3740 | return PYX_TRANSPORT_INVALID_PARAMETER_LIST; | 3740 | return PYX_TRANSPORT_INVALID_PARAMETER_LIST; |
3741 | } | 3741 | } |
@@ -3778,7 +3778,7 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) | |||
3778 | */ | 3778 | */ |
3779 | if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && | 3779 | if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && |
3780 | (cmd->data_length != 24)) { | 3780 | (cmd->data_length != 24)) { |
3781 | printk(KERN_WARNING "SPC-PR: Recieved PR OUT illegal parameter" | 3781 | printk(KERN_WARNING "SPC-PR: Received PR OUT illegal parameter" |
3782 | " list length: %u\n", cmd->data_length); | 3782 | " list length: %u\n", cmd->data_length); |
3783 | return PYX_TRANSPORT_INVALID_PARAMETER_LIST; | 3783 | return PYX_TRANSPORT_INVALID_PARAMETER_LIST; |
3784 | } | 3784 | } |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 5a9d2ba4b609..7ff6a35f26ac 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
@@ -441,6 +441,7 @@ static struct se_device *pscsi_create_type_disk( | |||
441 | struct pscsi_dev_virt *pdv, | 441 | struct pscsi_dev_virt *pdv, |
442 | struct se_subsystem_dev *se_dev, | 442 | struct se_subsystem_dev *se_dev, |
443 | struct se_hba *hba) | 443 | struct se_hba *hba) |
444 | __releases(sh->host_lock) | ||
444 | { | 445 | { |
445 | struct se_device *dev; | 446 | struct se_device *dev; |
446 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 447 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -488,6 +489,7 @@ static struct se_device *pscsi_create_type_rom( | |||
488 | struct pscsi_dev_virt *pdv, | 489 | struct pscsi_dev_virt *pdv, |
489 | struct se_subsystem_dev *se_dev, | 490 | struct se_subsystem_dev *se_dev, |
490 | struct se_hba *hba) | 491 | struct se_hba *hba) |
492 | __releases(sh->host_lock) | ||
491 | { | 493 | { |
492 | struct se_device *dev; | 494 | struct se_device *dev; |
493 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 495 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -522,6 +524,7 @@ static struct se_device *pscsi_create_type_other( | |||
522 | struct pscsi_dev_virt *pdv, | 524 | struct pscsi_dev_virt *pdv, |
523 | struct se_subsystem_dev *se_dev, | 525 | struct se_subsystem_dev *se_dev, |
524 | struct se_hba *hba) | 526 | struct se_hba *hba) |
527 | __releases(sh->host_lock) | ||
525 | { | 528 | { |
526 | struct se_device *dev; | 529 | struct se_device *dev; |
527 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 530 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -555,7 +558,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
555 | if (!(pdv)) { | 558 | if (!(pdv)) { |
556 | printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" | 559 | printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" |
557 | " parameter\n"); | 560 | " parameter\n"); |
558 | return NULL; | 561 | return ERR_PTR(-EINVAL); |
559 | } | 562 | } |
560 | /* | 563 | /* |
561 | * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the | 564 | * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the |
@@ -565,7 +568,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
565 | if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { | 568 | if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { |
566 | printk(KERN_ERR "pSCSI: Unable to locate struct" | 569 | printk(KERN_ERR "pSCSI: Unable to locate struct" |
567 | " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); | 570 | " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); |
568 | return NULL; | 571 | return ERR_PTR(-ENODEV); |
569 | } | 572 | } |
570 | /* | 573 | /* |
571 | * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device | 574 | * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device |
@@ -574,7 +577,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
574 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { | 577 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { |
575 | printk(KERN_ERR "pSCSI: udev_path attribute has not" | 578 | printk(KERN_ERR "pSCSI: udev_path attribute has not" |
576 | " been set before ENABLE=1\n"); | 579 | " been set before ENABLE=1\n"); |
577 | return NULL; | 580 | return ERR_PTR(-EINVAL); |
578 | } | 581 | } |
579 | /* | 582 | /* |
580 | * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, | 583 | * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, |
@@ -587,12 +590,12 @@ static struct se_device *pscsi_create_virtdevice( | |||
587 | printk(KERN_ERR "pSCSI: Unable to set hba_mode" | 590 | printk(KERN_ERR "pSCSI: Unable to set hba_mode" |
588 | " with active devices\n"); | 591 | " with active devices\n"); |
589 | spin_unlock(&hba->device_lock); | 592 | spin_unlock(&hba->device_lock); |
590 | return NULL; | 593 | return ERR_PTR(-EEXIST); |
591 | } | 594 | } |
592 | spin_unlock(&hba->device_lock); | 595 | spin_unlock(&hba->device_lock); |
593 | 596 | ||
594 | if (pscsi_pmode_enable_hba(hba, 1) != 1) | 597 | if (pscsi_pmode_enable_hba(hba, 1) != 1) |
595 | return NULL; | 598 | return ERR_PTR(-ENODEV); |
596 | 599 | ||
597 | legacy_mode_enable = 1; | 600 | legacy_mode_enable = 1; |
598 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; | 601 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; |
@@ -602,14 +605,14 @@ static struct se_device *pscsi_create_virtdevice( | |||
602 | if (!(sh)) { | 605 | if (!(sh)) { |
603 | printk(KERN_ERR "pSCSI: Unable to locate" | 606 | printk(KERN_ERR "pSCSI: Unable to locate" |
604 | " pdv_host_id: %d\n", pdv->pdv_host_id); | 607 | " pdv_host_id: %d\n", pdv->pdv_host_id); |
605 | return NULL; | 608 | return ERR_PTR(-ENODEV); |
606 | } | 609 | } |
607 | } | 610 | } |
608 | } else { | 611 | } else { |
609 | if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { | 612 | if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { |
610 | printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" | 613 | printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" |
611 | " struct Scsi_Host exists\n"); | 614 | " struct Scsi_Host exists\n"); |
612 | return NULL; | 615 | return ERR_PTR(-EEXIST); |
613 | } | 616 | } |
614 | } | 617 | } |
615 | 618 | ||
@@ -644,7 +647,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
644 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; | 647 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; |
645 | } | 648 | } |
646 | pdv->pdv_sd = NULL; | 649 | pdv->pdv_sd = NULL; |
647 | return NULL; | 650 | return ERR_PTR(-ENODEV); |
648 | } | 651 | } |
649 | return dev; | 652 | return dev; |
650 | } | 653 | } |
@@ -660,7 +663,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
660 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; | 663 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; |
661 | } | 664 | } |
662 | 665 | ||
663 | return NULL; | 666 | return ERR_PTR(-ENODEV); |
664 | } | 667 | } |
665 | 668 | ||
666 | /* pscsi_free_device(): (Part of se_subsystem_api_t template) | 669 | /* pscsi_free_device(): (Part of se_subsystem_api_t template) |
@@ -816,6 +819,7 @@ pscsi_alloc_task(struct se_cmd *cmd) | |||
816 | if (!(pt->pscsi_cdb)) { | 819 | if (!(pt->pscsi_cdb)) { |
817 | printk(KERN_ERR "pSCSI: Unable to allocate extended" | 820 | printk(KERN_ERR "pSCSI: Unable to allocate extended" |
818 | " pt->pscsi_cdb\n"); | 821 | " pt->pscsi_cdb\n"); |
822 | kfree(pt); | ||
819 | return NULL; | 823 | return NULL; |
820 | } | 824 | } |
821 | } else | 825 | } else |
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 8dc6d74c1d40..7837dd365a9d 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -150,7 +150,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
150 | if (rd_dev->rd_page_count <= 0) { | 150 | if (rd_dev->rd_page_count <= 0) { |
151 | printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", | 151 | printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", |
152 | rd_dev->rd_page_count); | 152 | rd_dev->rd_page_count); |
153 | return -1; | 153 | return -EINVAL; |
154 | } | 154 | } |
155 | total_sg_needed = rd_dev->rd_page_count; | 155 | total_sg_needed = rd_dev->rd_page_count; |
156 | 156 | ||
@@ -160,7 +160,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
160 | if (!(sg_table)) { | 160 | if (!(sg_table)) { |
161 | printk(KERN_ERR "Unable to allocate memory for Ramdisk" | 161 | printk(KERN_ERR "Unable to allocate memory for Ramdisk" |
162 | " scatterlist tables\n"); | 162 | " scatterlist tables\n"); |
163 | return -1; | 163 | return -ENOMEM; |
164 | } | 164 | } |
165 | 165 | ||
166 | rd_dev->sg_table_array = sg_table; | 166 | rd_dev->sg_table_array = sg_table; |
@@ -175,7 +175,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
175 | if (!(sg)) { | 175 | if (!(sg)) { |
176 | printk(KERN_ERR "Unable to allocate scatterlist array" | 176 | printk(KERN_ERR "Unable to allocate scatterlist array" |
177 | " for struct rd_dev\n"); | 177 | " for struct rd_dev\n"); |
178 | return -1; | 178 | return -ENOMEM; |
179 | } | 179 | } |
180 | 180 | ||
181 | sg_init_table((struct scatterlist *)&sg[0], sg_per_table); | 181 | sg_init_table((struct scatterlist *)&sg[0], sg_per_table); |
@@ -191,7 +191,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
191 | if (!(pg)) { | 191 | if (!(pg)) { |
192 | printk(KERN_ERR "Unable to allocate scatterlist" | 192 | printk(KERN_ERR "Unable to allocate scatterlist" |
193 | " pages for struct rd_dev_sg_table\n"); | 193 | " pages for struct rd_dev_sg_table\n"); |
194 | return -1; | 194 | return -ENOMEM; |
195 | } | 195 | } |
196 | sg_assign_page(&sg[j], pg); | 196 | sg_assign_page(&sg[j], pg); |
197 | sg[j].length = PAGE_SIZE; | 197 | sg[j].length = PAGE_SIZE; |
@@ -253,12 +253,13 @@ static struct se_device *rd_create_virtdevice( | |||
253 | struct se_dev_limits dev_limits; | 253 | struct se_dev_limits dev_limits; |
254 | struct rd_dev *rd_dev = p; | 254 | struct rd_dev *rd_dev = p; |
255 | struct rd_host *rd_host = hba->hba_ptr; | 255 | struct rd_host *rd_host = hba->hba_ptr; |
256 | int dev_flags = 0; | 256 | int dev_flags = 0, ret; |
257 | char prod[16], rev[4]; | 257 | char prod[16], rev[4]; |
258 | 258 | ||
259 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 259 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
260 | 260 | ||
261 | if (rd_build_device_space(rd_dev) < 0) | 261 | ret = rd_build_device_space(rd_dev); |
262 | if (ret < 0) | ||
262 | goto fail; | 263 | goto fail; |
263 | 264 | ||
264 | snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); | 265 | snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); |
@@ -292,7 +293,7 @@ static struct se_device *rd_create_virtdevice( | |||
292 | 293 | ||
293 | fail: | 294 | fail: |
294 | rd_release_device_space(rd_dev); | 295 | rd_release_device_space(rd_dev); |
295 | return NULL; | 296 | return ERR_PTR(ret); |
296 | } | 297 | } |
297 | 298 | ||
298 | static struct se_device *rd_DIRECT_create_virtdevice( | 299 | static struct se_device *rd_DIRECT_create_virtdevice( |
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 13badfbaf9c0..3ea19e29d8ec 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h | |||
@@ -14,8 +14,6 @@ | |||
14 | #define RD_BLOCKSIZE 512 | 14 | #define RD_BLOCKSIZE 512 |
15 | #define RD_MAX_SECTORS 1024 | 15 | #define RD_MAX_SECTORS 1024 |
16 | 16 | ||
17 | extern struct kmem_cache *se_mem_cache; | ||
18 | |||
19 | /* Used in target_core_init_configfs() for virtual LUN 0 access */ | 17 | /* Used in target_core_init_configfs() for virtual LUN 0 access */ |
20 | int __init rd_module_init(void); | 18 | int __init rd_module_init(void); |
21 | void rd_module_exit(void); | 19 | void rd_module_exit(void); |
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c new file mode 100644 index 000000000000..5e3a067a7475 --- /dev/null +++ b/drivers/target/target_core_stat.c | |||
@@ -0,0 +1,1810 @@ | |||
1 | /******************************************************************************* | ||
2 | * Filename: target_core_stat.c | ||
3 | * | ||
4 | * Copyright (c) 2011 Rising Tide Systems | ||
5 | * Copyright (c) 2011 Linux-iSCSI.org | ||
6 | * | ||
7 | * Modern ConfigFS group context specific statistics based on original | ||
8 | * target_core_mib.c code | ||
9 | * | ||
10 | * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. | ||
11 | * | ||
12 | * Nicholas A. Bellinger <nab@linux-iscsi.org> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
27 | * | ||
28 | ******************************************************************************/ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/timer.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/version.h> | ||
36 | #include <generated/utsrelease.h> | ||
37 | #include <linux/utsname.h> | ||
38 | #include <linux/proc_fs.h> | ||
39 | #include <linux/seq_file.h> | ||
40 | #include <linux/blkdev.h> | ||
41 | #include <linux/configfs.h> | ||
42 | #include <scsi/scsi.h> | ||
43 | #include <scsi/scsi_device.h> | ||
44 | #include <scsi/scsi_host.h> | ||
45 | |||
46 | #include <target/target_core_base.h> | ||
47 | #include <target/target_core_transport.h> | ||
48 | #include <target/target_core_fabric_ops.h> | ||
49 | #include <target/target_core_configfs.h> | ||
50 | #include <target/configfs_macros.h> | ||
51 | |||
52 | #include "target_core_hba.h" | ||
53 | |||
54 | #ifndef INITIAL_JIFFIES | ||
55 | #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) | ||
56 | #endif | ||
57 | |||
58 | #define NONE "None" | ||
59 | #define ISPRINT(a) ((a >= ' ') && (a <= '~')) | ||
60 | |||
61 | #define SCSI_LU_INDEX 1 | ||
62 | #define LU_COUNT 1 | ||
63 | |||
64 | /* | ||
65 | * SCSI Device Table | ||
66 | */ | ||
67 | |||
68 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps); | ||
69 | #define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \ | ||
70 | static struct target_stat_scsi_dev_attribute \ | ||
71 | target_stat_scsi_dev_##_name = \ | ||
72 | __CONFIGFS_EATTR(_name, _mode, \ | ||
73 | target_stat_scsi_dev_show_attr_##_name, \ | ||
74 | target_stat_scsi_dev_store_attr_##_name); | ||
75 | |||
76 | #define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \ | ||
77 | static struct target_stat_scsi_dev_attribute \ | ||
78 | target_stat_scsi_dev_##_name = \ | ||
79 | __CONFIGFS_EATTR_RO(_name, \ | ||
80 | target_stat_scsi_dev_show_attr_##_name); | ||
81 | |||
82 | static ssize_t target_stat_scsi_dev_show_attr_inst( | ||
83 | struct se_dev_stat_grps *sgrps, char *page) | ||
84 | { | ||
85 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
86 | struct se_subsystem_dev, dev_stat_grps); | ||
87 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
88 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
89 | |||
90 | if (!dev) | ||
91 | return -ENODEV; | ||
92 | |||
93 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
94 | } | ||
95 | DEV_STAT_SCSI_DEV_ATTR_RO(inst); | ||
96 | |||
97 | static ssize_t target_stat_scsi_dev_show_attr_indx( | ||
98 | struct se_dev_stat_grps *sgrps, char *page) | ||
99 | { | ||
100 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
101 | struct se_subsystem_dev, dev_stat_grps); | ||
102 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
103 | |||
104 | if (!dev) | ||
105 | return -ENODEV; | ||
106 | |||
107 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
108 | } | ||
109 | DEV_STAT_SCSI_DEV_ATTR_RO(indx); | ||
110 | |||
111 | static ssize_t target_stat_scsi_dev_show_attr_role( | ||
112 | struct se_dev_stat_grps *sgrps, char *page) | ||
113 | { | ||
114 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
115 | struct se_subsystem_dev, dev_stat_grps); | ||
116 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
117 | |||
118 | if (!dev) | ||
119 | return -ENODEV; | ||
120 | |||
121 | return snprintf(page, PAGE_SIZE, "Target\n"); | ||
122 | } | ||
123 | DEV_STAT_SCSI_DEV_ATTR_RO(role); | ||
124 | |||
125 | static ssize_t target_stat_scsi_dev_show_attr_ports( | ||
126 | struct se_dev_stat_grps *sgrps, char *page) | ||
127 | { | ||
128 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
129 | struct se_subsystem_dev, dev_stat_grps); | ||
130 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
131 | |||
132 | if (!dev) | ||
133 | return -ENODEV; | ||
134 | |||
135 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); | ||
136 | } | ||
137 | DEV_STAT_SCSI_DEV_ATTR_RO(ports); | ||
138 | |||
139 | CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group); | ||
140 | |||
141 | static struct configfs_attribute *target_stat_scsi_dev_attrs[] = { | ||
142 | &target_stat_scsi_dev_inst.attr, | ||
143 | &target_stat_scsi_dev_indx.attr, | ||
144 | &target_stat_scsi_dev_role.attr, | ||
145 | &target_stat_scsi_dev_ports.attr, | ||
146 | NULL, | ||
147 | }; | ||
148 | |||
149 | static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = { | ||
150 | .show_attribute = target_stat_scsi_dev_attr_show, | ||
151 | .store_attribute = target_stat_scsi_dev_attr_store, | ||
152 | }; | ||
153 | |||
154 | static struct config_item_type target_stat_scsi_dev_cit = { | ||
155 | .ct_item_ops = &target_stat_scsi_dev_attrib_ops, | ||
156 | .ct_attrs = target_stat_scsi_dev_attrs, | ||
157 | .ct_owner = THIS_MODULE, | ||
158 | }; | ||
159 | |||
160 | /* | ||
161 | * SCSI Target Device Table | ||
162 | */ | ||
163 | |||
164 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps); | ||
165 | #define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \ | ||
166 | static struct target_stat_scsi_tgt_dev_attribute \ | ||
167 | target_stat_scsi_tgt_dev_##_name = \ | ||
168 | __CONFIGFS_EATTR(_name, _mode, \ | ||
169 | target_stat_scsi_tgt_dev_show_attr_##_name, \ | ||
170 | target_stat_scsi_tgt_dev_store_attr_##_name); | ||
171 | |||
172 | #define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \ | ||
173 | static struct target_stat_scsi_tgt_dev_attribute \ | ||
174 | target_stat_scsi_tgt_dev_##_name = \ | ||
175 | __CONFIGFS_EATTR_RO(_name, \ | ||
176 | target_stat_scsi_tgt_dev_show_attr_##_name); | ||
177 | |||
178 | static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( | ||
179 | struct se_dev_stat_grps *sgrps, char *page) | ||
180 | { | ||
181 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
182 | struct se_subsystem_dev, dev_stat_grps); | ||
183 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
184 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
185 | |||
186 | if (!dev) | ||
187 | return -ENODEV; | ||
188 | |||
189 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
190 | } | ||
191 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); | ||
192 | |||
193 | static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( | ||
194 | struct se_dev_stat_grps *sgrps, char *page) | ||
195 | { | ||
196 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
197 | struct se_subsystem_dev, dev_stat_grps); | ||
198 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
199 | |||
200 | if (!dev) | ||
201 | return -ENODEV; | ||
202 | |||
203 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
204 | } | ||
205 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); | ||
206 | |||
207 | static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( | ||
208 | struct se_dev_stat_grps *sgrps, char *page) | ||
209 | { | ||
210 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
211 | struct se_subsystem_dev, dev_stat_grps); | ||
212 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
213 | |||
214 | if (!dev) | ||
215 | return -ENODEV; | ||
216 | |||
217 | return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); | ||
218 | } | ||
219 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); | ||
220 | |||
221 | static ssize_t target_stat_scsi_tgt_dev_show_attr_status( | ||
222 | struct se_dev_stat_grps *sgrps, char *page) | ||
223 | { | ||
224 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
225 | struct se_subsystem_dev, dev_stat_grps); | ||
226 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
227 | char status[16]; | ||
228 | |||
229 | if (!dev) | ||
230 | return -ENODEV; | ||
231 | |||
232 | switch (dev->dev_status) { | ||
233 | case TRANSPORT_DEVICE_ACTIVATED: | ||
234 | strcpy(status, "activated"); | ||
235 | break; | ||
236 | case TRANSPORT_DEVICE_DEACTIVATED: | ||
237 | strcpy(status, "deactivated"); | ||
238 | break; | ||
239 | case TRANSPORT_DEVICE_SHUTDOWN: | ||
240 | strcpy(status, "shutdown"); | ||
241 | break; | ||
242 | case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: | ||
243 | case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: | ||
244 | strcpy(status, "offline"); | ||
245 | break; | ||
246 | default: | ||
247 | sprintf(status, "unknown(%d)", dev->dev_status); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | return snprintf(page, PAGE_SIZE, "%s\n", status); | ||
252 | } | ||
253 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); | ||
254 | |||
255 | static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( | ||
256 | struct se_dev_stat_grps *sgrps, char *page) | ||
257 | { | ||
258 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
259 | struct se_subsystem_dev, dev_stat_grps); | ||
260 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
261 | int non_accessible_lus; | ||
262 | |||
263 | if (!dev) | ||
264 | return -ENODEV; | ||
265 | |||
266 | switch (dev->dev_status) { | ||
267 | case TRANSPORT_DEVICE_ACTIVATED: | ||
268 | non_accessible_lus = 0; | ||
269 | break; | ||
270 | case TRANSPORT_DEVICE_DEACTIVATED: | ||
271 | case TRANSPORT_DEVICE_SHUTDOWN: | ||
272 | case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: | ||
273 | case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: | ||
274 | default: | ||
275 | non_accessible_lus = 1; | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); | ||
280 | } | ||
281 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); | ||
282 | |||
283 | static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( | ||
284 | struct se_dev_stat_grps *sgrps, char *page) | ||
285 | { | ||
286 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
287 | struct se_subsystem_dev, dev_stat_grps); | ||
288 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
289 | |||
290 | if (!dev) | ||
291 | return -ENODEV; | ||
292 | |||
293 | return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); | ||
294 | } | ||
295 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets); | ||
296 | |||
297 | |||
298 | CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group); | ||
299 | |||
300 | static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = { | ||
301 | &target_stat_scsi_tgt_dev_inst.attr, | ||
302 | &target_stat_scsi_tgt_dev_indx.attr, | ||
303 | &target_stat_scsi_tgt_dev_num_lus.attr, | ||
304 | &target_stat_scsi_tgt_dev_status.attr, | ||
305 | &target_stat_scsi_tgt_dev_non_access_lus.attr, | ||
306 | &target_stat_scsi_tgt_dev_resets.attr, | ||
307 | NULL, | ||
308 | }; | ||
309 | |||
310 | static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = { | ||
311 | .show_attribute = target_stat_scsi_tgt_dev_attr_show, | ||
312 | .store_attribute = target_stat_scsi_tgt_dev_attr_store, | ||
313 | }; | ||
314 | |||
315 | static struct config_item_type target_stat_scsi_tgt_dev_cit = { | ||
316 | .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops, | ||
317 | .ct_attrs = target_stat_scsi_tgt_dev_attrs, | ||
318 | .ct_owner = THIS_MODULE, | ||
319 | }; | ||
320 | |||
321 | /* | ||
322 | * SCSI Logical Unit Table | ||
323 | */ | ||
324 | |||
325 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps); | ||
326 | #define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \ | ||
327 | static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ | ||
328 | __CONFIGFS_EATTR(_name, _mode, \ | ||
329 | target_stat_scsi_lu_show_attr_##_name, \ | ||
330 | target_stat_scsi_lu_store_attr_##_name); | ||
331 | |||
332 | #define DEV_STAT_SCSI_LU_ATTR_RO(_name) \ | ||
333 | static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ | ||
334 | __CONFIGFS_EATTR_RO(_name, \ | ||
335 | target_stat_scsi_lu_show_attr_##_name); | ||
336 | |||
337 | static ssize_t target_stat_scsi_lu_show_attr_inst( | ||
338 | struct se_dev_stat_grps *sgrps, char *page) | ||
339 | { | ||
340 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
341 | struct se_subsystem_dev, dev_stat_grps); | ||
342 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
343 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
344 | |||
345 | if (!dev) | ||
346 | return -ENODEV; | ||
347 | |||
348 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
349 | } | ||
350 | DEV_STAT_SCSI_LU_ATTR_RO(inst); | ||
351 | |||
352 | static ssize_t target_stat_scsi_lu_show_attr_dev( | ||
353 | struct se_dev_stat_grps *sgrps, char *page) | ||
354 | { | ||
355 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
356 | struct se_subsystem_dev, dev_stat_grps); | ||
357 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
358 | |||
359 | if (!dev) | ||
360 | return -ENODEV; | ||
361 | |||
362 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
363 | } | ||
364 | DEV_STAT_SCSI_LU_ATTR_RO(dev); | ||
365 | |||
366 | static ssize_t target_stat_scsi_lu_show_attr_indx( | ||
367 | struct se_dev_stat_grps *sgrps, char *page) | ||
368 | { | ||
369 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
370 | struct se_subsystem_dev, dev_stat_grps); | ||
371 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
372 | |||
373 | if (!dev) | ||
374 | return -ENODEV; | ||
375 | |||
376 | return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); | ||
377 | } | ||
378 | DEV_STAT_SCSI_LU_ATTR_RO(indx); | ||
379 | |||
380 | static ssize_t target_stat_scsi_lu_show_attr_lun( | ||
381 | struct se_dev_stat_grps *sgrps, char *page) | ||
382 | { | ||
383 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
384 | struct se_subsystem_dev, dev_stat_grps); | ||
385 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
386 | |||
387 | if (!dev) | ||
388 | return -ENODEV; | ||
389 | /* FIXME: scsiLuDefaultLun */ | ||
390 | return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); | ||
391 | } | ||
392 | DEV_STAT_SCSI_LU_ATTR_RO(lun); | ||
393 | |||
394 | static ssize_t target_stat_scsi_lu_show_attr_lu_name( | ||
395 | struct se_dev_stat_grps *sgrps, char *page) | ||
396 | { | ||
397 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
398 | struct se_subsystem_dev, dev_stat_grps); | ||
399 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
400 | |||
401 | if (!dev) | ||
402 | return -ENODEV; | ||
403 | /* scsiLuWwnName */ | ||
404 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
405 | (strlen(DEV_T10_WWN(dev)->unit_serial)) ? | ||
406 | (char *)&DEV_T10_WWN(dev)->unit_serial[0] : "None"); | ||
407 | } | ||
408 | DEV_STAT_SCSI_LU_ATTR_RO(lu_name); | ||
409 | |||
410 | static ssize_t target_stat_scsi_lu_show_attr_vend( | ||
411 | struct se_dev_stat_grps *sgrps, char *page) | ||
412 | { | ||
413 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
414 | struct se_subsystem_dev, dev_stat_grps); | ||
415 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
416 | int j; | ||
417 | char str[28]; | ||
418 | |||
419 | if (!dev) | ||
420 | return -ENODEV; | ||
421 | /* scsiLuVendorId */ | ||
422 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
423 | for (j = 0; j < 8; j++) | ||
424 | str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? | ||
425 | DEV_T10_WWN(dev)->vendor[j] : 0x20; | ||
426 | str[8] = 0; | ||
427 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
428 | } | ||
429 | DEV_STAT_SCSI_LU_ATTR_RO(vend); | ||
430 | |||
431 | static ssize_t target_stat_scsi_lu_show_attr_prod( | ||
432 | struct se_dev_stat_grps *sgrps, char *page) | ||
433 | { | ||
434 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
435 | struct se_subsystem_dev, dev_stat_grps); | ||
436 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
437 | int j; | ||
438 | char str[28]; | ||
439 | |||
440 | if (!dev) | ||
441 | return -ENODEV; | ||
442 | |||
443 | /* scsiLuProductId */ | ||
444 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
445 | for (j = 0; j < 16; j++) | ||
446 | str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? | ||
447 | DEV_T10_WWN(dev)->model[j] : 0x20; | ||
448 | str[16] = 0; | ||
449 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
450 | } | ||
451 | DEV_STAT_SCSI_LU_ATTR_RO(prod); | ||
452 | |||
453 | static ssize_t target_stat_scsi_lu_show_attr_rev( | ||
454 | struct se_dev_stat_grps *sgrps, char *page) | ||
455 | { | ||
456 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
457 | struct se_subsystem_dev, dev_stat_grps); | ||
458 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
459 | int j; | ||
460 | char str[28]; | ||
461 | |||
462 | if (!dev) | ||
463 | return -ENODEV; | ||
464 | |||
465 | /* scsiLuRevisionId */ | ||
466 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
467 | for (j = 0; j < 4; j++) | ||
468 | str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? | ||
469 | DEV_T10_WWN(dev)->revision[j] : 0x20; | ||
470 | str[4] = 0; | ||
471 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
472 | } | ||
473 | DEV_STAT_SCSI_LU_ATTR_RO(rev); | ||
474 | |||
475 | static ssize_t target_stat_scsi_lu_show_attr_dev_type( | ||
476 | struct se_dev_stat_grps *sgrps, char *page) | ||
477 | { | ||
478 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
479 | struct se_subsystem_dev, dev_stat_grps); | ||
480 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
481 | |||
482 | if (!dev) | ||
483 | return -ENODEV; | ||
484 | |||
485 | /* scsiLuPeripheralType */ | ||
486 | return snprintf(page, PAGE_SIZE, "%u\n", | ||
487 | TRANSPORT(dev)->get_device_type(dev)); | ||
488 | } | ||
489 | DEV_STAT_SCSI_LU_ATTR_RO(dev_type); | ||
490 | |||
491 | static ssize_t target_stat_scsi_lu_show_attr_status( | ||
492 | struct se_dev_stat_grps *sgrps, char *page) | ||
493 | { | ||
494 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
495 | struct se_subsystem_dev, dev_stat_grps); | ||
496 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
497 | |||
498 | if (!dev) | ||
499 | return -ENODEV; | ||
500 | |||
501 | /* scsiLuStatus */ | ||
502 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
503 | (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? | ||
504 | "available" : "notavailable"); | ||
505 | } | ||
506 | DEV_STAT_SCSI_LU_ATTR_RO(status); | ||
507 | |||
508 | static ssize_t target_stat_scsi_lu_show_attr_state_bit( | ||
509 | struct se_dev_stat_grps *sgrps, char *page) | ||
510 | { | ||
511 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
512 | struct se_subsystem_dev, dev_stat_grps); | ||
513 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
514 | |||
515 | if (!dev) | ||
516 | return -ENODEV; | ||
517 | |||
518 | /* scsiLuState */ | ||
519 | return snprintf(page, PAGE_SIZE, "exposed\n"); | ||
520 | } | ||
521 | DEV_STAT_SCSI_LU_ATTR_RO(state_bit); | ||
522 | |||
523 | static ssize_t target_stat_scsi_lu_show_attr_num_cmds( | ||
524 | struct se_dev_stat_grps *sgrps, char *page) | ||
525 | { | ||
526 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
527 | struct se_subsystem_dev, dev_stat_grps); | ||
528 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
529 | |||
530 | if (!dev) | ||
531 | return -ENODEV; | ||
532 | |||
533 | /* scsiLuNumCommands */ | ||
534 | return snprintf(page, PAGE_SIZE, "%llu\n", | ||
535 | (unsigned long long)dev->num_cmds); | ||
536 | } | ||
537 | DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); | ||
538 | |||
539 | static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( | ||
540 | struct se_dev_stat_grps *sgrps, char *page) | ||
541 | { | ||
542 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
543 | struct se_subsystem_dev, dev_stat_grps); | ||
544 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
545 | |||
546 | if (!dev) | ||
547 | return -ENODEV; | ||
548 | |||
549 | /* scsiLuReadMegaBytes */ | ||
550 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); | ||
551 | } | ||
552 | DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); | ||
553 | |||
554 | static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( | ||
555 | struct se_dev_stat_grps *sgrps, char *page) | ||
556 | { | ||
557 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
558 | struct se_subsystem_dev, dev_stat_grps); | ||
559 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
560 | |||
561 | if (!dev) | ||
562 | return -ENODEV; | ||
563 | |||
564 | /* scsiLuWrittenMegaBytes */ | ||
565 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); | ||
566 | } | ||
567 | DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); | ||
568 | |||
569 | static ssize_t target_stat_scsi_lu_show_attr_resets( | ||
570 | struct se_dev_stat_grps *sgrps, char *page) | ||
571 | { | ||
572 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
573 | struct se_subsystem_dev, dev_stat_grps); | ||
574 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
575 | |||
576 | if (!dev) | ||
577 | return -ENODEV; | ||
578 | |||
579 | /* scsiLuInResets */ | ||
580 | return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); | ||
581 | } | ||
582 | DEV_STAT_SCSI_LU_ATTR_RO(resets); | ||
583 | |||
584 | static ssize_t target_stat_scsi_lu_show_attr_full_stat( | ||
585 | struct se_dev_stat_grps *sgrps, char *page) | ||
586 | { | ||
587 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
588 | struct se_subsystem_dev, dev_stat_grps); | ||
589 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
590 | |||
591 | if (!dev) | ||
592 | return -ENODEV; | ||
593 | |||
594 | /* FIXME: scsiLuOutTaskSetFullStatus */ | ||
595 | return snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
596 | } | ||
597 | DEV_STAT_SCSI_LU_ATTR_RO(full_stat); | ||
598 | |||
599 | static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( | ||
600 | struct se_dev_stat_grps *sgrps, char *page) | ||
601 | { | ||
602 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
603 | struct se_subsystem_dev, dev_stat_grps); | ||
604 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
605 | |||
606 | if (!dev) | ||
607 | return -ENODEV; | ||
608 | |||
609 | /* FIXME: scsiLuHSInCommands */ | ||
610 | return snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
611 | } | ||
612 | DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); | ||
613 | |||
614 | static ssize_t target_stat_scsi_lu_show_attr_creation_time( | ||
615 | struct se_dev_stat_grps *sgrps, char *page) | ||
616 | { | ||
617 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
618 | struct se_subsystem_dev, dev_stat_grps); | ||
619 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
620 | |||
621 | if (!dev) | ||
622 | return -ENODEV; | ||
623 | |||
624 | /* scsiLuCreationTime */ | ||
625 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - | ||
626 | INITIAL_JIFFIES) * 100 / HZ)); | ||
627 | } | ||
628 | DEV_STAT_SCSI_LU_ATTR_RO(creation_time); | ||
629 | |||
630 | CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group); | ||
631 | |||
632 | static struct configfs_attribute *target_stat_scsi_lu_attrs[] = { | ||
633 | &target_stat_scsi_lu_inst.attr, | ||
634 | &target_stat_scsi_lu_dev.attr, | ||
635 | &target_stat_scsi_lu_indx.attr, | ||
636 | &target_stat_scsi_lu_lun.attr, | ||
637 | &target_stat_scsi_lu_lu_name.attr, | ||
638 | &target_stat_scsi_lu_vend.attr, | ||
639 | &target_stat_scsi_lu_prod.attr, | ||
640 | &target_stat_scsi_lu_rev.attr, | ||
641 | &target_stat_scsi_lu_dev_type.attr, | ||
642 | &target_stat_scsi_lu_status.attr, | ||
643 | &target_stat_scsi_lu_state_bit.attr, | ||
644 | &target_stat_scsi_lu_num_cmds.attr, | ||
645 | &target_stat_scsi_lu_read_mbytes.attr, | ||
646 | &target_stat_scsi_lu_write_mbytes.attr, | ||
647 | &target_stat_scsi_lu_resets.attr, | ||
648 | &target_stat_scsi_lu_full_stat.attr, | ||
649 | &target_stat_scsi_lu_hs_num_cmds.attr, | ||
650 | &target_stat_scsi_lu_creation_time.attr, | ||
651 | NULL, | ||
652 | }; | ||
653 | |||
654 | static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = { | ||
655 | .show_attribute = target_stat_scsi_lu_attr_show, | ||
656 | .store_attribute = target_stat_scsi_lu_attr_store, | ||
657 | }; | ||
658 | |||
659 | static struct config_item_type target_stat_scsi_lu_cit = { | ||
660 | .ct_item_ops = &target_stat_scsi_lu_attrib_ops, | ||
661 | .ct_attrs = target_stat_scsi_lu_attrs, | ||
662 | .ct_owner = THIS_MODULE, | ||
663 | }; | ||
664 | |||
665 | /* | ||
666 | * Called from target_core_configfs.c:target_core_make_subdev() to setup | ||
667 | * the target statistics groups + configfs CITs located in target_core_stat.c | ||
668 | */ | ||
669 | void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) | ||
670 | { | ||
671 | struct config_group *dev_stat_grp = &DEV_STAT_GRP(se_subdev)->stat_group; | ||
672 | |||
673 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_dev_group, | ||
674 | "scsi_dev", &target_stat_scsi_dev_cit); | ||
675 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group, | ||
676 | "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); | ||
677 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_lu_group, | ||
678 | "scsi_lu", &target_stat_scsi_lu_cit); | ||
679 | |||
680 | dev_stat_grp->default_groups[0] = &DEV_STAT_GRP(se_subdev)->scsi_dev_group; | ||
681 | dev_stat_grp->default_groups[1] = &DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group; | ||
682 | dev_stat_grp->default_groups[2] = &DEV_STAT_GRP(se_subdev)->scsi_lu_group; | ||
683 | dev_stat_grp->default_groups[3] = NULL; | ||
684 | } | ||
685 | |||
686 | /* | ||
687 | * SCSI Port Table | ||
688 | */ | ||
689 | |||
690 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps); | ||
691 | #define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \ | ||
692 | static struct target_stat_scsi_port_attribute \ | ||
693 | target_stat_scsi_port_##_name = \ | ||
694 | __CONFIGFS_EATTR(_name, _mode, \ | ||
695 | target_stat_scsi_port_show_attr_##_name, \ | ||
696 | target_stat_scsi_port_store_attr_##_name); | ||
697 | |||
698 | #define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \ | ||
699 | static struct target_stat_scsi_port_attribute \ | ||
700 | target_stat_scsi_port_##_name = \ | ||
701 | __CONFIGFS_EATTR_RO(_name, \ | ||
702 | target_stat_scsi_port_show_attr_##_name); | ||
703 | |||
704 | static ssize_t target_stat_scsi_port_show_attr_inst( | ||
705 | struct se_port_stat_grps *pgrps, char *page) | ||
706 | { | ||
707 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
708 | struct se_port *sep; | ||
709 | struct se_device *dev = lun->lun_se_dev; | ||
710 | struct se_hba *hba; | ||
711 | ssize_t ret; | ||
712 | |||
713 | spin_lock(&lun->lun_sep_lock); | ||
714 | sep = lun->lun_sep; | ||
715 | if (!sep) { | ||
716 | spin_unlock(&lun->lun_sep_lock); | ||
717 | return -ENODEV; | ||
718 | } | ||
719 | hba = dev->se_hba; | ||
720 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
721 | spin_unlock(&lun->lun_sep_lock); | ||
722 | return ret; | ||
723 | } | ||
724 | DEV_STAT_SCSI_PORT_ATTR_RO(inst); | ||
725 | |||
726 | static ssize_t target_stat_scsi_port_show_attr_dev( | ||
727 | struct se_port_stat_grps *pgrps, char *page) | ||
728 | { | ||
729 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
730 | struct se_port *sep; | ||
731 | struct se_device *dev = lun->lun_se_dev; | ||
732 | ssize_t ret; | ||
733 | |||
734 | spin_lock(&lun->lun_sep_lock); | ||
735 | sep = lun->lun_sep; | ||
736 | if (!sep) { | ||
737 | spin_unlock(&lun->lun_sep_lock); | ||
738 | return -ENODEV; | ||
739 | } | ||
740 | ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
741 | spin_unlock(&lun->lun_sep_lock); | ||
742 | return ret; | ||
743 | } | ||
744 | DEV_STAT_SCSI_PORT_ATTR_RO(dev); | ||
745 | |||
746 | static ssize_t target_stat_scsi_port_show_attr_indx( | ||
747 | struct se_port_stat_grps *pgrps, char *page) | ||
748 | { | ||
749 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
750 | struct se_port *sep; | ||
751 | ssize_t ret; | ||
752 | |||
753 | spin_lock(&lun->lun_sep_lock); | ||
754 | sep = lun->lun_sep; | ||
755 | if (!sep) { | ||
756 | spin_unlock(&lun->lun_sep_lock); | ||
757 | return -ENODEV; | ||
758 | } | ||
759 | ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); | ||
760 | spin_unlock(&lun->lun_sep_lock); | ||
761 | return ret; | ||
762 | } | ||
763 | DEV_STAT_SCSI_PORT_ATTR_RO(indx); | ||
764 | |||
765 | static ssize_t target_stat_scsi_port_show_attr_role( | ||
766 | struct se_port_stat_grps *pgrps, char *page) | ||
767 | { | ||
768 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
769 | struct se_device *dev = lun->lun_se_dev; | ||
770 | struct se_port *sep; | ||
771 | ssize_t ret; | ||
772 | |||
773 | if (!dev) | ||
774 | return -ENODEV; | ||
775 | |||
776 | spin_lock(&lun->lun_sep_lock); | ||
777 | sep = lun->lun_sep; | ||
778 | if (!sep) { | ||
779 | spin_unlock(&lun->lun_sep_lock); | ||
780 | return -ENODEV; | ||
781 | } | ||
782 | ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); | ||
783 | spin_unlock(&lun->lun_sep_lock); | ||
784 | return ret; | ||
785 | } | ||
786 | DEV_STAT_SCSI_PORT_ATTR_RO(role); | ||
787 | |||
788 | static ssize_t target_stat_scsi_port_show_attr_busy_count( | ||
789 | struct se_port_stat_grps *pgrps, char *page) | ||
790 | { | ||
791 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
792 | struct se_port *sep; | ||
793 | ssize_t ret; | ||
794 | |||
795 | spin_lock(&lun->lun_sep_lock); | ||
796 | sep = lun->lun_sep; | ||
797 | if (!sep) { | ||
798 | spin_unlock(&lun->lun_sep_lock); | ||
799 | return -ENODEV; | ||
800 | } | ||
801 | /* FIXME: scsiPortBusyStatuses */ | ||
802 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
803 | spin_unlock(&lun->lun_sep_lock); | ||
804 | return ret; | ||
805 | } | ||
806 | DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); | ||
807 | |||
808 | CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group); | ||
809 | |||
810 | static struct configfs_attribute *target_stat_scsi_port_attrs[] = { | ||
811 | &target_stat_scsi_port_inst.attr, | ||
812 | &target_stat_scsi_port_dev.attr, | ||
813 | &target_stat_scsi_port_indx.attr, | ||
814 | &target_stat_scsi_port_role.attr, | ||
815 | &target_stat_scsi_port_busy_count.attr, | ||
816 | NULL, | ||
817 | }; | ||
818 | |||
819 | static struct configfs_item_operations target_stat_scsi_port_attrib_ops = { | ||
820 | .show_attribute = target_stat_scsi_port_attr_show, | ||
821 | .store_attribute = target_stat_scsi_port_attr_store, | ||
822 | }; | ||
823 | |||
824 | static struct config_item_type target_stat_scsi_port_cit = { | ||
825 | .ct_item_ops = &target_stat_scsi_port_attrib_ops, | ||
826 | .ct_attrs = target_stat_scsi_port_attrs, | ||
827 | .ct_owner = THIS_MODULE, | ||
828 | }; | ||
829 | |||
830 | /* | ||
831 | * SCSI Target Port Table | ||
832 | */ | ||
833 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps); | ||
834 | #define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \ | ||
835 | static struct target_stat_scsi_tgt_port_attribute \ | ||
836 | target_stat_scsi_tgt_port_##_name = \ | ||
837 | __CONFIGFS_EATTR(_name, _mode, \ | ||
838 | target_stat_scsi_tgt_port_show_attr_##_name, \ | ||
839 | target_stat_scsi_tgt_port_store_attr_##_name); | ||
840 | |||
841 | #define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \ | ||
842 | static struct target_stat_scsi_tgt_port_attribute \ | ||
843 | target_stat_scsi_tgt_port_##_name = \ | ||
844 | __CONFIGFS_EATTR_RO(_name, \ | ||
845 | target_stat_scsi_tgt_port_show_attr_##_name); | ||
846 | |||
847 | static ssize_t target_stat_scsi_tgt_port_show_attr_inst( | ||
848 | struct se_port_stat_grps *pgrps, char *page) | ||
849 | { | ||
850 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
851 | struct se_device *dev = lun->lun_se_dev; | ||
852 | struct se_port *sep; | ||
853 | struct se_hba *hba; | ||
854 | ssize_t ret; | ||
855 | |||
856 | spin_lock(&lun->lun_sep_lock); | ||
857 | sep = lun->lun_sep; | ||
858 | if (!sep) { | ||
859 | spin_unlock(&lun->lun_sep_lock); | ||
860 | return -ENODEV; | ||
861 | } | ||
862 | hba = dev->se_hba; | ||
863 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
864 | spin_unlock(&lun->lun_sep_lock); | ||
865 | return ret; | ||
866 | } | ||
867 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); | ||
868 | |||
869 | static ssize_t target_stat_scsi_tgt_port_show_attr_dev( | ||
870 | struct se_port_stat_grps *pgrps, char *page) | ||
871 | { | ||
872 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
873 | struct se_device *dev = lun->lun_se_dev; | ||
874 | struct se_port *sep; | ||
875 | ssize_t ret; | ||
876 | |||
877 | spin_lock(&lun->lun_sep_lock); | ||
878 | sep = lun->lun_sep; | ||
879 | if (!sep) { | ||
880 | spin_unlock(&lun->lun_sep_lock); | ||
881 | return -ENODEV; | ||
882 | } | ||
883 | ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
884 | spin_unlock(&lun->lun_sep_lock); | ||
885 | return ret; | ||
886 | } | ||
887 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); | ||
888 | |||
889 | static ssize_t target_stat_scsi_tgt_port_show_attr_indx( | ||
890 | struct se_port_stat_grps *pgrps, char *page) | ||
891 | { | ||
892 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
893 | struct se_port *sep; | ||
894 | ssize_t ret; | ||
895 | |||
896 | spin_lock(&lun->lun_sep_lock); | ||
897 | sep = lun->lun_sep; | ||
898 | if (!sep) { | ||
899 | spin_unlock(&lun->lun_sep_lock); | ||
900 | return -ENODEV; | ||
901 | } | ||
902 | ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); | ||
903 | spin_unlock(&lun->lun_sep_lock); | ||
904 | return ret; | ||
905 | } | ||
906 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); | ||
907 | |||
908 | static ssize_t target_stat_scsi_tgt_port_show_attr_name( | ||
909 | struct se_port_stat_grps *pgrps, char *page) | ||
910 | { | ||
911 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
912 | struct se_port *sep; | ||
913 | struct se_portal_group *tpg; | ||
914 | ssize_t ret; | ||
915 | |||
916 | spin_lock(&lun->lun_sep_lock); | ||
917 | sep = lun->lun_sep; | ||
918 | if (!sep) { | ||
919 | spin_unlock(&lun->lun_sep_lock); | ||
920 | return -ENODEV; | ||
921 | } | ||
922 | tpg = sep->sep_tpg; | ||
923 | |||
924 | ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", | ||
925 | TPG_TFO(tpg)->get_fabric_name(), sep->sep_index); | ||
926 | spin_unlock(&lun->lun_sep_lock); | ||
927 | return ret; | ||
928 | } | ||
929 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); | ||
930 | |||
931 | static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( | ||
932 | struct se_port_stat_grps *pgrps, char *page) | ||
933 | { | ||
934 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
935 | struct se_port *sep; | ||
936 | struct se_portal_group *tpg; | ||
937 | ssize_t ret; | ||
938 | |||
939 | spin_lock(&lun->lun_sep_lock); | ||
940 | sep = lun->lun_sep; | ||
941 | if (!sep) { | ||
942 | spin_unlock(&lun->lun_sep_lock); | ||
943 | return -ENODEV; | ||
944 | } | ||
945 | tpg = sep->sep_tpg; | ||
946 | |||
947 | ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", | ||
948 | TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", | ||
949 | TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
950 | spin_unlock(&lun->lun_sep_lock); | ||
951 | return ret; | ||
952 | } | ||
953 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); | ||
954 | |||
955 | static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( | ||
956 | struct se_port_stat_grps *pgrps, char *page) | ||
957 | { | ||
958 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
959 | struct se_port *sep; | ||
960 | struct se_portal_group *tpg; | ||
961 | ssize_t ret; | ||
962 | |||
963 | spin_lock(&lun->lun_sep_lock); | ||
964 | sep = lun->lun_sep; | ||
965 | if (!sep) { | ||
966 | spin_unlock(&lun->lun_sep_lock); | ||
967 | return -ENODEV; | ||
968 | } | ||
969 | tpg = sep->sep_tpg; | ||
970 | |||
971 | ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); | ||
972 | spin_unlock(&lun->lun_sep_lock); | ||
973 | return ret; | ||
974 | } | ||
975 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); | ||
976 | |||
977 | static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( | ||
978 | struct se_port_stat_grps *pgrps, char *page) | ||
979 | { | ||
980 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
981 | struct se_port *sep; | ||
982 | struct se_portal_group *tpg; | ||
983 | ssize_t ret; | ||
984 | |||
985 | spin_lock(&lun->lun_sep_lock); | ||
986 | sep = lun->lun_sep; | ||
987 | if (!sep) { | ||
988 | spin_unlock(&lun->lun_sep_lock); | ||
989 | return -ENODEV; | ||
990 | } | ||
991 | tpg = sep->sep_tpg; | ||
992 | |||
993 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
994 | (u32)(sep->sep_stats.rx_data_octets >> 20)); | ||
995 | spin_unlock(&lun->lun_sep_lock); | ||
996 | return ret; | ||
997 | } | ||
998 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); | ||
999 | |||
1000 | static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( | ||
1001 | struct se_port_stat_grps *pgrps, char *page) | ||
1002 | { | ||
1003 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1004 | struct se_port *sep; | ||
1005 | struct se_portal_group *tpg; | ||
1006 | ssize_t ret; | ||
1007 | |||
1008 | spin_lock(&lun->lun_sep_lock); | ||
1009 | sep = lun->lun_sep; | ||
1010 | if (!sep) { | ||
1011 | spin_unlock(&lun->lun_sep_lock); | ||
1012 | return -ENODEV; | ||
1013 | } | ||
1014 | tpg = sep->sep_tpg; | ||
1015 | |||
1016 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1017 | (u32)(sep->sep_stats.tx_data_octets >> 20)); | ||
1018 | spin_unlock(&lun->lun_sep_lock); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); | ||
1022 | |||
1023 | static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( | ||
1024 | struct se_port_stat_grps *pgrps, char *page) | ||
1025 | { | ||
1026 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1027 | struct se_port *sep; | ||
1028 | struct se_portal_group *tpg; | ||
1029 | ssize_t ret; | ||
1030 | |||
1031 | spin_lock(&lun->lun_sep_lock); | ||
1032 | sep = lun->lun_sep; | ||
1033 | if (!sep) { | ||
1034 | spin_unlock(&lun->lun_sep_lock); | ||
1035 | return -ENODEV; | ||
1036 | } | ||
1037 | tpg = sep->sep_tpg; | ||
1038 | |||
1039 | /* FIXME: scsiTgtPortHsInCommands */ | ||
1040 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1041 | spin_unlock(&lun->lun_sep_lock); | ||
1042 | return ret; | ||
1043 | } | ||
1044 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); | ||
1045 | |||
1046 | CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps, | ||
1047 | scsi_tgt_port_group); | ||
1048 | |||
1049 | static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = { | ||
1050 | &target_stat_scsi_tgt_port_inst.attr, | ||
1051 | &target_stat_scsi_tgt_port_dev.attr, | ||
1052 | &target_stat_scsi_tgt_port_indx.attr, | ||
1053 | &target_stat_scsi_tgt_port_name.attr, | ||
1054 | &target_stat_scsi_tgt_port_port_index.attr, | ||
1055 | &target_stat_scsi_tgt_port_in_cmds.attr, | ||
1056 | &target_stat_scsi_tgt_port_write_mbytes.attr, | ||
1057 | &target_stat_scsi_tgt_port_read_mbytes.attr, | ||
1058 | &target_stat_scsi_tgt_port_hs_in_cmds.attr, | ||
1059 | NULL, | ||
1060 | }; | ||
1061 | |||
1062 | static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = { | ||
1063 | .show_attribute = target_stat_scsi_tgt_port_attr_show, | ||
1064 | .store_attribute = target_stat_scsi_tgt_port_attr_store, | ||
1065 | }; | ||
1066 | |||
1067 | static struct config_item_type target_stat_scsi_tgt_port_cit = { | ||
1068 | .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops, | ||
1069 | .ct_attrs = target_stat_scsi_tgt_port_attrs, | ||
1070 | .ct_owner = THIS_MODULE, | ||
1071 | }; | ||
1072 | |||
1073 | /* | ||
1074 | * SCSI Transport Table | ||
1075 | o */ | ||
1076 | |||
1077 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps); | ||
1078 | #define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \ | ||
1079 | static struct target_stat_scsi_transport_attribute \ | ||
1080 | target_stat_scsi_transport_##_name = \ | ||
1081 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1082 | target_stat_scsi_transport_show_attr_##_name, \ | ||
1083 | target_stat_scsi_transport_store_attr_##_name); | ||
1084 | |||
1085 | #define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \ | ||
1086 | static struct target_stat_scsi_transport_attribute \ | ||
1087 | target_stat_scsi_transport_##_name = \ | ||
1088 | __CONFIGFS_EATTR_RO(_name, \ | ||
1089 | target_stat_scsi_transport_show_attr_##_name); | ||
1090 | |||
1091 | static ssize_t target_stat_scsi_transport_show_attr_inst( | ||
1092 | struct se_port_stat_grps *pgrps, char *page) | ||
1093 | { | ||
1094 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1095 | struct se_device *dev = lun->lun_se_dev; | ||
1096 | struct se_port *sep; | ||
1097 | struct se_hba *hba; | ||
1098 | ssize_t ret; | ||
1099 | |||
1100 | spin_lock(&lun->lun_sep_lock); | ||
1101 | sep = lun->lun_sep; | ||
1102 | if (!sep) { | ||
1103 | spin_unlock(&lun->lun_sep_lock); | ||
1104 | return -ENODEV; | ||
1105 | } | ||
1106 | |||
1107 | hba = dev->se_hba; | ||
1108 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
1109 | spin_unlock(&lun->lun_sep_lock); | ||
1110 | return ret; | ||
1111 | } | ||
1112 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); | ||
1113 | |||
1114 | static ssize_t target_stat_scsi_transport_show_attr_device( | ||
1115 | struct se_port_stat_grps *pgrps, char *page) | ||
1116 | { | ||
1117 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1118 | struct se_port *sep; | ||
1119 | struct se_portal_group *tpg; | ||
1120 | ssize_t ret; | ||
1121 | |||
1122 | spin_lock(&lun->lun_sep_lock); | ||
1123 | sep = lun->lun_sep; | ||
1124 | if (!sep) { | ||
1125 | spin_unlock(&lun->lun_sep_lock); | ||
1126 | return -ENODEV; | ||
1127 | } | ||
1128 | tpg = sep->sep_tpg; | ||
1129 | /* scsiTransportType */ | ||
1130 | ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", | ||
1131 | TPG_TFO(tpg)->get_fabric_name()); | ||
1132 | spin_unlock(&lun->lun_sep_lock); | ||
1133 | return ret; | ||
1134 | } | ||
1135 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); | ||
1136 | |||
1137 | static ssize_t target_stat_scsi_transport_show_attr_indx( | ||
1138 | struct se_port_stat_grps *pgrps, char *page) | ||
1139 | { | ||
1140 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1141 | struct se_port *sep; | ||
1142 | struct se_portal_group *tpg; | ||
1143 | ssize_t ret; | ||
1144 | |||
1145 | spin_lock(&lun->lun_sep_lock); | ||
1146 | sep = lun->lun_sep; | ||
1147 | if (!sep) { | ||
1148 | spin_unlock(&lun->lun_sep_lock); | ||
1149 | return -ENODEV; | ||
1150 | } | ||
1151 | tpg = sep->sep_tpg; | ||
1152 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1153 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1154 | spin_unlock(&lun->lun_sep_lock); | ||
1155 | return ret; | ||
1156 | } | ||
1157 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); | ||
1158 | |||
1159 | static ssize_t target_stat_scsi_transport_show_attr_dev_name( | ||
1160 | struct se_port_stat_grps *pgrps, char *page) | ||
1161 | { | ||
1162 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1163 | struct se_device *dev = lun->lun_se_dev; | ||
1164 | struct se_port *sep; | ||
1165 | struct se_portal_group *tpg; | ||
1166 | struct t10_wwn *wwn; | ||
1167 | ssize_t ret; | ||
1168 | |||
1169 | spin_lock(&lun->lun_sep_lock); | ||
1170 | sep = lun->lun_sep; | ||
1171 | if (!sep) { | ||
1172 | spin_unlock(&lun->lun_sep_lock); | ||
1173 | return -ENODEV; | ||
1174 | } | ||
1175 | tpg = sep->sep_tpg; | ||
1176 | wwn = DEV_T10_WWN(dev); | ||
1177 | /* scsiTransportDevName */ | ||
1178 | ret = snprintf(page, PAGE_SIZE, "%s+%s\n", | ||
1179 | TPG_TFO(tpg)->tpg_get_wwn(tpg), | ||
1180 | (strlen(wwn->unit_serial)) ? wwn->unit_serial : | ||
1181 | wwn->vendor); | ||
1182 | spin_unlock(&lun->lun_sep_lock); | ||
1183 | return ret; | ||
1184 | } | ||
1185 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); | ||
1186 | |||
1187 | CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps, | ||
1188 | scsi_transport_group); | ||
1189 | |||
1190 | static struct configfs_attribute *target_stat_scsi_transport_attrs[] = { | ||
1191 | &target_stat_scsi_transport_inst.attr, | ||
1192 | &target_stat_scsi_transport_device.attr, | ||
1193 | &target_stat_scsi_transport_indx.attr, | ||
1194 | &target_stat_scsi_transport_dev_name.attr, | ||
1195 | NULL, | ||
1196 | }; | ||
1197 | |||
1198 | static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = { | ||
1199 | .show_attribute = target_stat_scsi_transport_attr_show, | ||
1200 | .store_attribute = target_stat_scsi_transport_attr_store, | ||
1201 | }; | ||
1202 | |||
1203 | static struct config_item_type target_stat_scsi_transport_cit = { | ||
1204 | .ct_item_ops = &target_stat_scsi_transport_attrib_ops, | ||
1205 | .ct_attrs = target_stat_scsi_transport_attrs, | ||
1206 | .ct_owner = THIS_MODULE, | ||
1207 | }; | ||
1208 | |||
1209 | /* | ||
1210 | * Called from target_core_fabric_configfs.c:target_fabric_make_lun() to setup | ||
1211 | * the target port statistics groups + configfs CITs located in target_core_stat.c | ||
1212 | */ | ||
1213 | void target_stat_setup_port_default_groups(struct se_lun *lun) | ||
1214 | { | ||
1215 | struct config_group *port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
1216 | |||
1217 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_port_group, | ||
1218 | "scsi_port", &target_stat_scsi_port_cit); | ||
1219 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_tgt_port_group, | ||
1220 | "scsi_tgt_port", &target_stat_scsi_tgt_port_cit); | ||
1221 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_transport_group, | ||
1222 | "scsi_transport", &target_stat_scsi_transport_cit); | ||
1223 | |||
1224 | port_stat_grp->default_groups[0] = &PORT_STAT_GRP(lun)->scsi_port_group; | ||
1225 | port_stat_grp->default_groups[1] = &PORT_STAT_GRP(lun)->scsi_tgt_port_group; | ||
1226 | port_stat_grp->default_groups[2] = &PORT_STAT_GRP(lun)->scsi_transport_group; | ||
1227 | port_stat_grp->default_groups[3] = NULL; | ||
1228 | } | ||
1229 | |||
1230 | /* | ||
1231 | * SCSI Authorized Initiator Table | ||
1232 | */ | ||
1233 | |||
1234 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps); | ||
1235 | #define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \ | ||
1236 | static struct target_stat_scsi_auth_intr_attribute \ | ||
1237 | target_stat_scsi_auth_intr_##_name = \ | ||
1238 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1239 | target_stat_scsi_auth_intr_show_attr_##_name, \ | ||
1240 | target_stat_scsi_auth_intr_store_attr_##_name); | ||
1241 | |||
1242 | #define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \ | ||
1243 | static struct target_stat_scsi_auth_intr_attribute \ | ||
1244 | target_stat_scsi_auth_intr_##_name = \ | ||
1245 | __CONFIGFS_EATTR_RO(_name, \ | ||
1246 | target_stat_scsi_auth_intr_show_attr_##_name); | ||
1247 | |||
1248 | static ssize_t target_stat_scsi_auth_intr_show_attr_inst( | ||
1249 | struct se_ml_stat_grps *lgrps, char *page) | ||
1250 | { | ||
1251 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1252 | struct se_lun_acl, ml_stat_grps); | ||
1253 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1254 | struct se_dev_entry *deve; | ||
1255 | struct se_portal_group *tpg; | ||
1256 | ssize_t ret; | ||
1257 | |||
1258 | spin_lock_irq(&nacl->device_list_lock); | ||
1259 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1260 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1261 | spin_unlock_irq(&nacl->device_list_lock); | ||
1262 | return -ENODEV; | ||
1263 | } | ||
1264 | tpg = nacl->se_tpg; | ||
1265 | /* scsiInstIndex */ | ||
1266 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1267 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1268 | spin_unlock_irq(&nacl->device_list_lock); | ||
1269 | return ret; | ||
1270 | } | ||
1271 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); | ||
1272 | |||
1273 | static ssize_t target_stat_scsi_auth_intr_show_attr_dev( | ||
1274 | struct se_ml_stat_grps *lgrps, char *page) | ||
1275 | { | ||
1276 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1277 | struct se_lun_acl, ml_stat_grps); | ||
1278 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1279 | struct se_dev_entry *deve; | ||
1280 | struct se_lun *lun; | ||
1281 | struct se_portal_group *tpg; | ||
1282 | ssize_t ret; | ||
1283 | |||
1284 | spin_lock_irq(&nacl->device_list_lock); | ||
1285 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1286 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1287 | spin_unlock_irq(&nacl->device_list_lock); | ||
1288 | return -ENODEV; | ||
1289 | } | ||
1290 | tpg = nacl->se_tpg; | ||
1291 | lun = deve->se_lun; | ||
1292 | /* scsiDeviceIndex */ | ||
1293 | ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); | ||
1294 | spin_unlock_irq(&nacl->device_list_lock); | ||
1295 | return ret; | ||
1296 | } | ||
1297 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); | ||
1298 | |||
1299 | static ssize_t target_stat_scsi_auth_intr_show_attr_port( | ||
1300 | struct se_ml_stat_grps *lgrps, char *page) | ||
1301 | { | ||
1302 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1303 | struct se_lun_acl, ml_stat_grps); | ||
1304 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1305 | struct se_dev_entry *deve; | ||
1306 | struct se_portal_group *tpg; | ||
1307 | ssize_t ret; | ||
1308 | |||
1309 | spin_lock_irq(&nacl->device_list_lock); | ||
1310 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1311 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1312 | spin_unlock_irq(&nacl->device_list_lock); | ||
1313 | return -ENODEV; | ||
1314 | } | ||
1315 | tpg = nacl->se_tpg; | ||
1316 | /* scsiAuthIntrTgtPortIndex */ | ||
1317 | ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
1318 | spin_unlock_irq(&nacl->device_list_lock); | ||
1319 | return ret; | ||
1320 | } | ||
1321 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); | ||
1322 | |||
1323 | static ssize_t target_stat_scsi_auth_intr_show_attr_indx( | ||
1324 | struct se_ml_stat_grps *lgrps, char *page) | ||
1325 | { | ||
1326 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1327 | struct se_lun_acl, ml_stat_grps); | ||
1328 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1329 | struct se_dev_entry *deve; | ||
1330 | ssize_t ret; | ||
1331 | |||
1332 | spin_lock_irq(&nacl->device_list_lock); | ||
1333 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1334 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1335 | spin_unlock_irq(&nacl->device_list_lock); | ||
1336 | return -ENODEV; | ||
1337 | } | ||
1338 | /* scsiAuthIntrIndex */ | ||
1339 | ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); | ||
1340 | spin_unlock_irq(&nacl->device_list_lock); | ||
1341 | return ret; | ||
1342 | } | ||
1343 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); | ||
1344 | |||
1345 | static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( | ||
1346 | struct se_ml_stat_grps *lgrps, char *page) | ||
1347 | { | ||
1348 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1349 | struct se_lun_acl, ml_stat_grps); | ||
1350 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1351 | struct se_dev_entry *deve; | ||
1352 | ssize_t ret; | ||
1353 | |||
1354 | spin_lock_irq(&nacl->device_list_lock); | ||
1355 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1356 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1357 | spin_unlock_irq(&nacl->device_list_lock); | ||
1358 | return -ENODEV; | ||
1359 | } | ||
1360 | /* scsiAuthIntrDevOrPort */ | ||
1361 | ret = snprintf(page, PAGE_SIZE, "%u\n", 1); | ||
1362 | spin_unlock_irq(&nacl->device_list_lock); | ||
1363 | return ret; | ||
1364 | } | ||
1365 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); | ||
1366 | |||
1367 | static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( | ||
1368 | struct se_ml_stat_grps *lgrps, char *page) | ||
1369 | { | ||
1370 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1371 | struct se_lun_acl, ml_stat_grps); | ||
1372 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1373 | struct se_dev_entry *deve; | ||
1374 | ssize_t ret; | ||
1375 | |||
1376 | spin_lock_irq(&nacl->device_list_lock); | ||
1377 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1378 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1379 | spin_unlock_irq(&nacl->device_list_lock); | ||
1380 | return -ENODEV; | ||
1381 | } | ||
1382 | /* scsiAuthIntrName */ | ||
1383 | ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); | ||
1384 | spin_unlock_irq(&nacl->device_list_lock); | ||
1385 | return ret; | ||
1386 | } | ||
1387 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); | ||
1388 | |||
1389 | static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( | ||
1390 | struct se_ml_stat_grps *lgrps, char *page) | ||
1391 | { | ||
1392 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1393 | struct se_lun_acl, ml_stat_grps); | ||
1394 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1395 | struct se_dev_entry *deve; | ||
1396 | ssize_t ret; | ||
1397 | |||
1398 | spin_lock_irq(&nacl->device_list_lock); | ||
1399 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1400 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1401 | spin_unlock_irq(&nacl->device_list_lock); | ||
1402 | return -ENODEV; | ||
1403 | } | ||
1404 | /* FIXME: scsiAuthIntrLunMapIndex */ | ||
1405 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1406 | spin_unlock_irq(&nacl->device_list_lock); | ||
1407 | return ret; | ||
1408 | } | ||
1409 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); | ||
1410 | |||
1411 | static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( | ||
1412 | struct se_ml_stat_grps *lgrps, char *page) | ||
1413 | { | ||
1414 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1415 | struct se_lun_acl, ml_stat_grps); | ||
1416 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1417 | struct se_dev_entry *deve; | ||
1418 | ssize_t ret; | ||
1419 | |||
1420 | spin_lock_irq(&nacl->device_list_lock); | ||
1421 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1422 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1423 | spin_unlock_irq(&nacl->device_list_lock); | ||
1424 | return -ENODEV; | ||
1425 | } | ||
1426 | /* scsiAuthIntrAttachedTimes */ | ||
1427 | ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); | ||
1428 | spin_unlock_irq(&nacl->device_list_lock); | ||
1429 | return ret; | ||
1430 | } | ||
1431 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); | ||
1432 | |||
1433 | static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( | ||
1434 | struct se_ml_stat_grps *lgrps, char *page) | ||
1435 | { | ||
1436 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1437 | struct se_lun_acl, ml_stat_grps); | ||
1438 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1439 | struct se_dev_entry *deve; | ||
1440 | ssize_t ret; | ||
1441 | |||
1442 | spin_lock_irq(&nacl->device_list_lock); | ||
1443 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1444 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1445 | spin_unlock_irq(&nacl->device_list_lock); | ||
1446 | return -ENODEV; | ||
1447 | } | ||
1448 | /* scsiAuthIntrOutCommands */ | ||
1449 | ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); | ||
1450 | spin_unlock_irq(&nacl->device_list_lock); | ||
1451 | return ret; | ||
1452 | } | ||
1453 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); | ||
1454 | |||
1455 | static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( | ||
1456 | struct se_ml_stat_grps *lgrps, char *page) | ||
1457 | { | ||
1458 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1459 | struct se_lun_acl, ml_stat_grps); | ||
1460 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1461 | struct se_dev_entry *deve; | ||
1462 | ssize_t ret; | ||
1463 | |||
1464 | spin_lock_irq(&nacl->device_list_lock); | ||
1465 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1466 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1467 | spin_unlock_irq(&nacl->device_list_lock); | ||
1468 | return -ENODEV; | ||
1469 | } | ||
1470 | /* scsiAuthIntrReadMegaBytes */ | ||
1471 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); | ||
1472 | spin_unlock_irq(&nacl->device_list_lock); | ||
1473 | return ret; | ||
1474 | } | ||
1475 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); | ||
1476 | |||
1477 | static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( | ||
1478 | struct se_ml_stat_grps *lgrps, char *page) | ||
1479 | { | ||
1480 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1481 | struct se_lun_acl, ml_stat_grps); | ||
1482 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1483 | struct se_dev_entry *deve; | ||
1484 | ssize_t ret; | ||
1485 | |||
1486 | spin_lock_irq(&nacl->device_list_lock); | ||
1487 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1488 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1489 | spin_unlock_irq(&nacl->device_list_lock); | ||
1490 | return -ENODEV; | ||
1491 | } | ||
1492 | /* scsiAuthIntrWrittenMegaBytes */ | ||
1493 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); | ||
1494 | spin_unlock_irq(&nacl->device_list_lock); | ||
1495 | return ret; | ||
1496 | } | ||
1497 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); | ||
1498 | |||
1499 | static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( | ||
1500 | struct se_ml_stat_grps *lgrps, char *page) | ||
1501 | { | ||
1502 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1503 | struct se_lun_acl, ml_stat_grps); | ||
1504 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1505 | struct se_dev_entry *deve; | ||
1506 | ssize_t ret; | ||
1507 | |||
1508 | spin_lock_irq(&nacl->device_list_lock); | ||
1509 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1510 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1511 | spin_unlock_irq(&nacl->device_list_lock); | ||
1512 | return -ENODEV; | ||
1513 | } | ||
1514 | /* FIXME: scsiAuthIntrHSOutCommands */ | ||
1515 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1516 | spin_unlock_irq(&nacl->device_list_lock); | ||
1517 | return ret; | ||
1518 | } | ||
1519 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); | ||
1520 | |||
1521 | static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( | ||
1522 | struct se_ml_stat_grps *lgrps, char *page) | ||
1523 | { | ||
1524 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1525 | struct se_lun_acl, ml_stat_grps); | ||
1526 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1527 | struct se_dev_entry *deve; | ||
1528 | ssize_t ret; | ||
1529 | |||
1530 | spin_lock_irq(&nacl->device_list_lock); | ||
1531 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1532 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1533 | spin_unlock_irq(&nacl->device_list_lock); | ||
1534 | return -ENODEV; | ||
1535 | } | ||
1536 | /* scsiAuthIntrLastCreation */ | ||
1537 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - | ||
1538 | INITIAL_JIFFIES) * 100 / HZ)); | ||
1539 | spin_unlock_irq(&nacl->device_list_lock); | ||
1540 | return ret; | ||
1541 | } | ||
1542 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); | ||
1543 | |||
1544 | static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( | ||
1545 | struct se_ml_stat_grps *lgrps, char *page) | ||
1546 | { | ||
1547 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1548 | struct se_lun_acl, ml_stat_grps); | ||
1549 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1550 | struct se_dev_entry *deve; | ||
1551 | ssize_t ret; | ||
1552 | |||
1553 | spin_lock_irq(&nacl->device_list_lock); | ||
1554 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1555 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1556 | spin_unlock_irq(&nacl->device_list_lock); | ||
1557 | return -ENODEV; | ||
1558 | } | ||
1559 | /* FIXME: scsiAuthIntrRowStatus */ | ||
1560 | ret = snprintf(page, PAGE_SIZE, "Ready\n"); | ||
1561 | spin_unlock_irq(&nacl->device_list_lock); | ||
1562 | return ret; | ||
1563 | } | ||
1564 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); | ||
1565 | |||
1566 | CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps, | ||
1567 | scsi_auth_intr_group); | ||
1568 | |||
1569 | static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = { | ||
1570 | &target_stat_scsi_auth_intr_inst.attr, | ||
1571 | &target_stat_scsi_auth_intr_dev.attr, | ||
1572 | &target_stat_scsi_auth_intr_port.attr, | ||
1573 | &target_stat_scsi_auth_intr_indx.attr, | ||
1574 | &target_stat_scsi_auth_intr_dev_or_port.attr, | ||
1575 | &target_stat_scsi_auth_intr_intr_name.attr, | ||
1576 | &target_stat_scsi_auth_intr_map_indx.attr, | ||
1577 | &target_stat_scsi_auth_intr_att_count.attr, | ||
1578 | &target_stat_scsi_auth_intr_num_cmds.attr, | ||
1579 | &target_stat_scsi_auth_intr_read_mbytes.attr, | ||
1580 | &target_stat_scsi_auth_intr_write_mbytes.attr, | ||
1581 | &target_stat_scsi_auth_intr_hs_num_cmds.attr, | ||
1582 | &target_stat_scsi_auth_intr_creation_time.attr, | ||
1583 | &target_stat_scsi_auth_intr_row_status.attr, | ||
1584 | NULL, | ||
1585 | }; | ||
1586 | |||
1587 | static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = { | ||
1588 | .show_attribute = target_stat_scsi_auth_intr_attr_show, | ||
1589 | .store_attribute = target_stat_scsi_auth_intr_attr_store, | ||
1590 | }; | ||
1591 | |||
1592 | static struct config_item_type target_stat_scsi_auth_intr_cit = { | ||
1593 | .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops, | ||
1594 | .ct_attrs = target_stat_scsi_auth_intr_attrs, | ||
1595 | .ct_owner = THIS_MODULE, | ||
1596 | }; | ||
1597 | |||
1598 | /* | ||
1599 | * SCSI Attached Initiator Port Table | ||
1600 | */ | ||
1601 | |||
1602 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps); | ||
1603 | #define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \ | ||
1604 | static struct target_stat_scsi_att_intr_port_attribute \ | ||
1605 | target_stat_scsi_att_intr_port_##_name = \ | ||
1606 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1607 | target_stat_scsi_att_intr_port_show_attr_##_name, \ | ||
1608 | target_stat_scsi_att_intr_port_store_attr_##_name); | ||
1609 | |||
1610 | #define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \ | ||
1611 | static struct target_stat_scsi_att_intr_port_attribute \ | ||
1612 | target_stat_scsi_att_intr_port_##_name = \ | ||
1613 | __CONFIGFS_EATTR_RO(_name, \ | ||
1614 | target_stat_scsi_att_intr_port_show_attr_##_name); | ||
1615 | |||
1616 | static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( | ||
1617 | struct se_ml_stat_grps *lgrps, char *page) | ||
1618 | { | ||
1619 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1620 | struct se_lun_acl, ml_stat_grps); | ||
1621 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1622 | struct se_dev_entry *deve; | ||
1623 | struct se_portal_group *tpg; | ||
1624 | ssize_t ret; | ||
1625 | |||
1626 | spin_lock_irq(&nacl->device_list_lock); | ||
1627 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1628 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1629 | spin_unlock_irq(&nacl->device_list_lock); | ||
1630 | return -ENODEV; | ||
1631 | } | ||
1632 | tpg = nacl->se_tpg; | ||
1633 | /* scsiInstIndex */ | ||
1634 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1635 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1636 | spin_unlock_irq(&nacl->device_list_lock); | ||
1637 | return ret; | ||
1638 | } | ||
1639 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); | ||
1640 | |||
1641 | static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( | ||
1642 | struct se_ml_stat_grps *lgrps, char *page) | ||
1643 | { | ||
1644 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1645 | struct se_lun_acl, ml_stat_grps); | ||
1646 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1647 | struct se_dev_entry *deve; | ||
1648 | struct se_lun *lun; | ||
1649 | struct se_portal_group *tpg; | ||
1650 | ssize_t ret; | ||
1651 | |||
1652 | spin_lock_irq(&nacl->device_list_lock); | ||
1653 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1654 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1655 | spin_unlock_irq(&nacl->device_list_lock); | ||
1656 | return -ENODEV; | ||
1657 | } | ||
1658 | tpg = nacl->se_tpg; | ||
1659 | lun = deve->se_lun; | ||
1660 | /* scsiDeviceIndex */ | ||
1661 | ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); | ||
1662 | spin_unlock_irq(&nacl->device_list_lock); | ||
1663 | return ret; | ||
1664 | } | ||
1665 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); | ||
1666 | |||
1667 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port( | ||
1668 | struct se_ml_stat_grps *lgrps, char *page) | ||
1669 | { | ||
1670 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1671 | struct se_lun_acl, ml_stat_grps); | ||
1672 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1673 | struct se_dev_entry *deve; | ||
1674 | struct se_portal_group *tpg; | ||
1675 | ssize_t ret; | ||
1676 | |||
1677 | spin_lock_irq(&nacl->device_list_lock); | ||
1678 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1679 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1680 | spin_unlock_irq(&nacl->device_list_lock); | ||
1681 | return -ENODEV; | ||
1682 | } | ||
1683 | tpg = nacl->se_tpg; | ||
1684 | /* scsiPortIndex */ | ||
1685 | ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
1686 | spin_unlock_irq(&nacl->device_list_lock); | ||
1687 | return ret; | ||
1688 | } | ||
1689 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); | ||
1690 | |||
1691 | static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( | ||
1692 | struct se_ml_stat_grps *lgrps, char *page) | ||
1693 | { | ||
1694 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1695 | struct se_lun_acl, ml_stat_grps); | ||
1696 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1697 | struct se_session *se_sess; | ||
1698 | struct se_portal_group *tpg; | ||
1699 | ssize_t ret; | ||
1700 | |||
1701 | spin_lock_irq(&nacl->nacl_sess_lock); | ||
1702 | se_sess = nacl->nacl_sess; | ||
1703 | if (!se_sess) { | ||
1704 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1705 | return -ENODEV; | ||
1706 | } | ||
1707 | |||
1708 | tpg = nacl->se_tpg; | ||
1709 | /* scsiAttIntrPortIndex */ | ||
1710 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1711 | TPG_TFO(tpg)->sess_get_index(se_sess)); | ||
1712 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1713 | return ret; | ||
1714 | } | ||
1715 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx); | ||
1716 | |||
1717 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( | ||
1718 | struct se_ml_stat_grps *lgrps, char *page) | ||
1719 | { | ||
1720 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1721 | struct se_lun_acl, ml_stat_grps); | ||
1722 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1723 | struct se_dev_entry *deve; | ||
1724 | ssize_t ret; | ||
1725 | |||
1726 | spin_lock_irq(&nacl->device_list_lock); | ||
1727 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1728 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1729 | spin_unlock_irq(&nacl->device_list_lock); | ||
1730 | return -ENODEV; | ||
1731 | } | ||
1732 | /* scsiAttIntrPortAuthIntrIdx */ | ||
1733 | ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); | ||
1734 | spin_unlock_irq(&nacl->device_list_lock); | ||
1735 | return ret; | ||
1736 | } | ||
1737 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); | ||
1738 | |||
1739 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( | ||
1740 | struct se_ml_stat_grps *lgrps, char *page) | ||
1741 | { | ||
1742 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1743 | struct se_lun_acl, ml_stat_grps); | ||
1744 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1745 | struct se_session *se_sess; | ||
1746 | struct se_portal_group *tpg; | ||
1747 | ssize_t ret; | ||
1748 | unsigned char buf[64]; | ||
1749 | |||
1750 | spin_lock_irq(&nacl->nacl_sess_lock); | ||
1751 | se_sess = nacl->nacl_sess; | ||
1752 | if (!se_sess) { | ||
1753 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1754 | return -ENODEV; | ||
1755 | } | ||
1756 | |||
1757 | tpg = nacl->se_tpg; | ||
1758 | /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */ | ||
1759 | memset(buf, 0, 64); | ||
1760 | if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) | ||
1761 | TPG_TFO(tpg)->sess_get_initiator_sid(se_sess, | ||
1762 | (unsigned char *)&buf[0], 64); | ||
1763 | |||
1764 | ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf); | ||
1765 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1766 | return ret; | ||
1767 | } | ||
1768 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident); | ||
1769 | |||
1770 | CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps, | ||
1771 | scsi_att_intr_port_group); | ||
1772 | |||
1773 | static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = { | ||
1774 | &target_stat_scsi_att_intr_port_inst.attr, | ||
1775 | &target_stat_scsi_att_intr_port_dev.attr, | ||
1776 | &target_stat_scsi_att_intr_port_port.attr, | ||
1777 | &target_stat_scsi_att_intr_port_indx.attr, | ||
1778 | &target_stat_scsi_att_intr_port_port_auth_indx.attr, | ||
1779 | &target_stat_scsi_att_intr_port_port_ident.attr, | ||
1780 | NULL, | ||
1781 | }; | ||
1782 | |||
1783 | static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = { | ||
1784 | .show_attribute = target_stat_scsi_att_intr_port_attr_show, | ||
1785 | .store_attribute = target_stat_scsi_att_intr_port_attr_store, | ||
1786 | }; | ||
1787 | |||
1788 | static struct config_item_type target_stat_scsi_att_intr_port_cit = { | ||
1789 | .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops, | ||
1790 | .ct_attrs = target_stat_scsi_ath_intr_port_attrs, | ||
1791 | .ct_owner = THIS_MODULE, | ||
1792 | }; | ||
1793 | |||
1794 | /* | ||
1795 | * Called from target_core_fabric_configfs.c:target_fabric_make_mappedlun() to setup | ||
1796 | * the target MappedLUN statistics groups + configfs CITs located in target_core_stat.c | ||
1797 | */ | ||
1798 | void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl) | ||
1799 | { | ||
1800 | struct config_group *ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
1801 | |||
1802 | config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_auth_intr_group, | ||
1803 | "scsi_auth_intr", &target_stat_scsi_auth_intr_cit); | ||
1804 | config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_att_intr_port_group, | ||
1805 | "scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit); | ||
1806 | |||
1807 | ml_stat_grp->default_groups[0] = &ML_STAT_GRPS(lacl)->scsi_auth_intr_group; | ||
1808 | ml_stat_grp->default_groups[1] = &ML_STAT_GRPS(lacl)->scsi_att_intr_port_group; | ||
1809 | ml_stat_grp->default_groups[2] = NULL; | ||
1810 | } | ||
diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h new file mode 100644 index 000000000000..86c252f9ea47 --- /dev/null +++ b/drivers/target/target_core_stat.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef TARGET_CORE_STAT_H | ||
2 | #define TARGET_CORE_STAT_H | ||
3 | |||
4 | extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); | ||
5 | extern void target_stat_setup_port_default_groups(struct se_lun *); | ||
6 | extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); | ||
7 | |||
8 | #endif /*** TARGET_CORE_STAT_H ***/ | ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 39ac190080e2..b9d3501bdd91 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -227,8 +227,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd, | |||
227 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); | 227 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); |
228 | static void transport_stop_all_task_timers(struct se_cmd *cmd); | 228 | static void transport_stop_all_task_timers(struct se_cmd *cmd); |
229 | 229 | ||
230 | int transport_emulate_control_cdb(struct se_task *task); | ||
231 | |||
232 | int init_se_global(void) | 230 | int init_se_global(void) |
233 | { | 231 | { |
234 | struct se_global *global; | 232 | struct se_global *global; |
@@ -721,7 +719,7 @@ static int transport_cmd_check_stop( | |||
721 | cmd->se_lun = NULL; | 719 | cmd->se_lun = NULL; |
722 | /* | 720 | /* |
723 | * Some fabric modules like tcm_loop can release | 721 | * Some fabric modules like tcm_loop can release |
724 | * their internally allocated I/O refrence now and | 722 | * their internally allocated I/O reference now and |
725 | * struct se_cmd now. | 723 | * struct se_cmd now. |
726 | */ | 724 | */ |
727 | if (CMD_TFO(cmd)->check_stop_free != NULL) { | 725 | if (CMD_TFO(cmd)->check_stop_free != NULL) { |
@@ -1622,7 +1620,7 @@ struct se_device *transport_add_device_to_core_hba( | |||
1622 | const char *inquiry_prod, | 1620 | const char *inquiry_prod, |
1623 | const char *inquiry_rev) | 1621 | const char *inquiry_rev) |
1624 | { | 1622 | { |
1625 | int ret = 0, force_pt; | 1623 | int force_pt; |
1626 | struct se_device *dev; | 1624 | struct se_device *dev; |
1627 | 1625 | ||
1628 | dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); | 1626 | dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); |
@@ -1739,9 +1737,8 @@ struct se_device *transport_add_device_to_core_hba( | |||
1739 | } | 1737 | } |
1740 | scsi_dump_inquiry(dev); | 1738 | scsi_dump_inquiry(dev); |
1741 | 1739 | ||
1740 | return dev; | ||
1742 | out: | 1741 | out: |
1743 | if (!ret) | ||
1744 | return dev; | ||
1745 | kthread_stop(dev->process_thread); | 1742 | kthread_stop(dev->process_thread); |
1746 | 1743 | ||
1747 | spin_lock(&hba->device_lock); | 1744 | spin_lock(&hba->device_lock); |
@@ -2032,7 +2029,7 @@ int transport_generic_handle_data( | |||
2032 | * If the received CDB has aleady been ABORTED by the generic | 2029 | * If the received CDB has aleady been ABORTED by the generic |
2033 | * target engine, we now call transport_check_aborted_status() | 2030 | * target engine, we now call transport_check_aborted_status() |
2034 | * to queue any delated TASK_ABORTED status for the received CDB to the | 2031 | * to queue any delated TASK_ABORTED status for the received CDB to the |
2035 | * fabric module as we are expecting no futher incoming DATA OUT | 2032 | * fabric module as we are expecting no further incoming DATA OUT |
2036 | * sequences at this point. | 2033 | * sequences at this point. |
2037 | */ | 2034 | */ |
2038 | if (transport_check_aborted_status(cmd, 1) != 0) | 2035 | if (transport_check_aborted_status(cmd, 1) != 0) |
@@ -2504,7 +2501,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) | |||
2504 | if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) | 2501 | if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) |
2505 | return 1; | 2502 | return 1; |
2506 | /* | 2503 | /* |
2507 | * Check for the existance of HEAD_OF_QUEUE, and if true return 1 | 2504 | * Check for the existence of HEAD_OF_QUEUE, and if true return 1 |
2508 | * to allow the passed struct se_cmd list of tasks to the front of the list. | 2505 | * to allow the passed struct se_cmd list of tasks to the front of the list. |
2509 | */ | 2506 | */ |
2510 | if (cmd->sam_task_attr == TASK_ATTR_HOQ) { | 2507 | if (cmd->sam_task_attr == TASK_ATTR_HOQ) { |
@@ -2550,7 +2547,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) | |||
2550 | if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) { | 2547 | if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) { |
2551 | /* | 2548 | /* |
2552 | * Otherwise, add cmd w/ tasks to delayed cmd queue that | 2549 | * Otherwise, add cmd w/ tasks to delayed cmd queue that |
2553 | * will be drained upon competion of HEAD_OF_QUEUE task. | 2550 | * will be drained upon completion of HEAD_OF_QUEUE task. |
2554 | */ | 2551 | */ |
2555 | spin_lock(&SE_DEV(cmd)->delayed_cmd_lock); | 2552 | spin_lock(&SE_DEV(cmd)->delayed_cmd_lock); |
2556 | cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; | 2553 | cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; |
@@ -2592,7 +2589,7 @@ static int transport_execute_tasks(struct se_cmd *cmd) | |||
2592 | } | 2589 | } |
2593 | /* | 2590 | /* |
2594 | * Call transport_cmd_check_stop() to see if a fabric exception | 2591 | * Call transport_cmd_check_stop() to see if a fabric exception |
2595 | * has occured that prevents execution. | 2592 | * has occurred that prevents execution. |
2596 | */ | 2593 | */ |
2597 | if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) { | 2594 | if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) { |
2598 | /* | 2595 | /* |
@@ -3112,7 +3109,7 @@ static int transport_generic_cmd_sequencer( | |||
3112 | if (ret != 0) { | 3109 | if (ret != 0) { |
3113 | cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; | 3110 | cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; |
3114 | /* | 3111 | /* |
3115 | * Set SCSI additional sense code (ASC) to 'LUN Not Accessable'; | 3112 | * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; |
3116 | * The ALUA additional sense code qualifier (ASCQ) is determined | 3113 | * The ALUA additional sense code qualifier (ASCQ) is determined |
3117 | * by the ALUA primary or secondary access state.. | 3114 | * by the ALUA primary or secondary access state.. |
3118 | */ | 3115 | */ |
@@ -3870,7 +3867,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) | |||
3870 | } | 3867 | } |
3871 | } | 3868 | } |
3872 | /* | 3869 | /* |
3873 | * Check for a callback, used by amoungst other things | 3870 | * Check for a callback, used by amongst other things |
3874 | * XDWRITE_READ_10 emulation. | 3871 | * XDWRITE_READ_10 emulation. |
3875 | */ | 3872 | */ |
3876 | if (cmd->transport_complete_callback) | 3873 | if (cmd->transport_complete_callback) |
@@ -4359,11 +4356,9 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4359 | printk(KERN_ERR "Unable to allocate struct se_mem\n"); | 4356 | printk(KERN_ERR "Unable to allocate struct se_mem\n"); |
4360 | goto out; | 4357 | goto out; |
4361 | } | 4358 | } |
4362 | INIT_LIST_HEAD(&se_mem->se_list); | ||
4363 | se_mem->se_len = (length > dma_size) ? dma_size : length; | ||
4364 | 4359 | ||
4365 | /* #warning FIXME Allocate contigous pages for struct se_mem elements */ | 4360 | /* #warning FIXME Allocate contigous pages for struct se_mem elements */ |
4366 | se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0); | 4361 | se_mem->se_page = alloc_pages(GFP_KERNEL, 0); |
4367 | if (!(se_mem->se_page)) { | 4362 | if (!(se_mem->se_page)) { |
4368 | printk(KERN_ERR "alloc_pages() failed\n"); | 4363 | printk(KERN_ERR "alloc_pages() failed\n"); |
4369 | goto out; | 4364 | goto out; |
@@ -4374,6 +4369,8 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4374 | printk(KERN_ERR "kmap_atomic() failed\n"); | 4369 | printk(KERN_ERR "kmap_atomic() failed\n"); |
4375 | goto out; | 4370 | goto out; |
4376 | } | 4371 | } |
4372 | INIT_LIST_HEAD(&se_mem->se_list); | ||
4373 | se_mem->se_len = (length > dma_size) ? dma_size : length; | ||
4377 | memset(buf, 0, se_mem->se_len); | 4374 | memset(buf, 0, se_mem->se_len); |
4378 | kunmap_atomic(buf, KM_IRQ0); | 4375 | kunmap_atomic(buf, KM_IRQ0); |
4379 | 4376 | ||
@@ -4392,10 +4389,13 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4392 | 4389 | ||
4393 | return 0; | 4390 | return 0; |
4394 | out: | 4391 | out: |
4392 | if (se_mem) | ||
4393 | __free_pages(se_mem->se_page, 0); | ||
4394 | kmem_cache_free(se_mem_cache, se_mem); | ||
4395 | return -1; | 4395 | return -1; |
4396 | } | 4396 | } |
4397 | 4397 | ||
4398 | extern u32 transport_calc_sg_num( | 4398 | u32 transport_calc_sg_num( |
4399 | struct se_task *task, | 4399 | struct se_task *task, |
4400 | struct se_mem *in_se_mem, | 4400 | struct se_mem *in_se_mem, |
4401 | u32 task_offset) | 4401 | u32 task_offset) |
@@ -5834,31 +5834,26 @@ int transport_generic_do_tmr(struct se_cmd *cmd) | |||
5834 | int ret; | 5834 | int ret; |
5835 | 5835 | ||
5836 | switch (tmr->function) { | 5836 | switch (tmr->function) { |
5837 | case ABORT_TASK: | 5837 | case TMR_ABORT_TASK: |
5838 | ref_cmd = tmr->ref_cmd; | 5838 | ref_cmd = tmr->ref_cmd; |
5839 | tmr->response = TMR_FUNCTION_REJECTED; | 5839 | tmr->response = TMR_FUNCTION_REJECTED; |
5840 | break; | 5840 | break; |
5841 | case ABORT_TASK_SET: | 5841 | case TMR_ABORT_TASK_SET: |
5842 | case CLEAR_ACA: | 5842 | case TMR_CLEAR_ACA: |
5843 | case CLEAR_TASK_SET: | 5843 | case TMR_CLEAR_TASK_SET: |
5844 | tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; | 5844 | tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; |
5845 | break; | 5845 | break; |
5846 | case LUN_RESET: | 5846 | case TMR_LUN_RESET: |
5847 | ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); | 5847 | ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); |
5848 | tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : | 5848 | tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : |
5849 | TMR_FUNCTION_REJECTED; | 5849 | TMR_FUNCTION_REJECTED; |
5850 | break; | 5850 | break; |
5851 | #if 0 | 5851 | case TMR_TARGET_WARM_RESET: |
5852 | case TARGET_WARM_RESET: | ||
5853 | transport_generic_host_reset(dev->se_hba); | ||
5854 | tmr->response = TMR_FUNCTION_REJECTED; | 5852 | tmr->response = TMR_FUNCTION_REJECTED; |
5855 | break; | 5853 | break; |
5856 | case TARGET_COLD_RESET: | 5854 | case TMR_TARGET_COLD_RESET: |
5857 | transport_generic_host_reset(dev->se_hba); | ||
5858 | transport_generic_cold_reset(dev->se_hba); | ||
5859 | tmr->response = TMR_FUNCTION_REJECTED; | 5855 | tmr->response = TMR_FUNCTION_REJECTED; |
5860 | break; | 5856 | break; |
5861 | #endif | ||
5862 | default: | 5857 | default: |
5863 | printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", | 5858 | printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", |
5864 | tmr->function); | 5859 | tmr->function); |
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index a2ef346087e8..df355176a377 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c | |||
@@ -247,7 +247,7 @@ void core_scsi3_ua_for_check_condition( | |||
247 | } | 247 | } |
248 | /* | 248 | /* |
249 | * Otherwise for the default 00b, release the UNIT ATTENTION | 249 | * Otherwise for the default 00b, release the UNIT ATTENTION |
250 | * condition. Return the ASC/ASCQ of the higest priority UA | 250 | * condition. Return the ASC/ASCQ of the highest priority UA |
251 | * (head of the list) in the outgoing CHECK_CONDITION + sense. | 251 | * (head of the list) in the outgoing CHECK_CONDITION + sense. |
252 | */ | 252 | */ |
253 | if (head) { | 253 | if (head) { |
@@ -304,7 +304,7 @@ int core_scsi3_ua_clear_for_request_sense( | |||
304 | * matching struct se_lun. | 304 | * matching struct se_lun. |
305 | * | 305 | * |
306 | * Once the returning ASC/ASCQ values are set, we go ahead and | 306 | * Once the returning ASC/ASCQ values are set, we go ahead and |
307 | * release all of the Unit Attention conditions for the assoicated | 307 | * release all of the Unit Attention conditions for the associated |
308 | * struct se_lun. | 308 | * struct se_lun. |
309 | */ | 309 | */ |
310 | spin_lock(&deve->ua_lock); | 310 | spin_lock(&deve->ua_lock); |