blob: 3df1c9b8ae6b7e07118575ebbf24a59124644b01 [file] [log] [blame]
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001/*******************************************************************************
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>
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -070034
35#include <target/target_core_base.h>
36#include <target/target_core_transport.h>
37#include <target/target_core_fabric_ops.h>
38#include <target/target_core_fabric_configfs.h>
39#include <target/target_core_fabric_lib.h>
40#include <target/target_core_configfs.h>
41#include <target/target_core_device.h>
42#include <target/target_core_tpg.h>
43#include <target/target_core_tmr.h>
44
45#include "tcm_loop.h"
46
47#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev)
48
49/* Local pointer to allocated TCM configfs fabric module */
50static struct target_fabric_configfs *tcm_loop_fabric_configfs;
51
52static struct kmem_cache *tcm_loop_cmd_cache;
53
54static int tcm_loop_hba_no_cnt;
55
56/*
57 * Allocate a tcm_loop cmd descriptor from target_core_mod code
58 *
59 * Can be called from interrupt context in tcm_loop_queuecommand() below
60 */
61static struct se_cmd *tcm_loop_allocate_core_cmd(
62 struct tcm_loop_hba *tl_hba,
63 struct se_portal_group *se_tpg,
64 struct scsi_cmnd *sc)
65{
66 struct se_cmd *se_cmd;
67 struct se_session *se_sess;
68 struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus;
69 struct tcm_loop_cmd *tl_cmd;
70 int sam_task_attr;
71
72 if (!tl_nexus) {
73 scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus"
74 " does not exist\n");
75 set_host_byte(sc, DID_ERROR);
76 return NULL;
77 }
78 se_sess = tl_nexus->se_sess;
79
80 tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC);
81 if (!tl_cmd) {
Andy Grover6708bb22011-06-08 10:36:43 -070082 pr_err("Unable to allocate struct tcm_loop_cmd\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -070083 set_host_byte(sc, DID_ERROR);
84 return NULL;
85 }
86 se_cmd = &tl_cmd->tl_se_cmd;
87 /*
88 * Save the pointer to struct scsi_cmnd *sc
89 */
90 tl_cmd->sc = sc;
91 /*
92 * Locate the SAM Task Attr from struct scsi_cmnd *
93 */
94 if (sc->device->tagged_supported) {
95 switch (sc->tag) {
96 case HEAD_OF_QUEUE_TAG:
Nicholas Bellinger61db1802011-05-19 20:19:14 -070097 sam_task_attr = MSG_HEAD_TAG;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -070098 break;
99 case ORDERED_QUEUE_TAG:
Nicholas Bellinger61db1802011-05-19 20:19:14 -0700100 sam_task_attr = MSG_ORDERED_TAG;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700101 break;
102 default:
Nicholas Bellinger61db1802011-05-19 20:19:14 -0700103 sam_task_attr = MSG_SIMPLE_TAG;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700104 break;
105 }
106 } else
Nicholas Bellinger61db1802011-05-19 20:19:14 -0700107 sam_task_attr = MSG_SIMPLE_TAG;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700108
109 /*
110 * Initialize struct se_cmd descriptor from target_core_mod infrastructure
111 */
112 transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
113 scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr,
114 &tl_cmd->tl_sense_buf[0]);
115
116 /*
117 * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi
118 */
119 if (scsi_bidi_cmnd(sc))
Andy Grovera1d8b492011-05-02 17:12:10 -0700120 se_cmd->t_tasks_bidi = 1;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700121 /*
122 * Locate the struct se_lun pointer and attach it to struct se_cmd
123 */
Andy Grover59511462011-07-19 10:26:37 +0000124 if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700125 kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
126 set_host_byte(sc, DID_NO_CONNECT);
127 return NULL;
128 }
129
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700130 return se_cmd;
131}
132
133/*
134 * Called by struct target_core_fabric_ops->new_cmd_map()
135 *
136 * Always called in process context. A non zero return value
137 * here will signal to handle an exception based on the return code.
138 */
139static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
140{
141 struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
142 struct tcm_loop_cmd, tl_se_cmd);
143 struct scsi_cmnd *sc = tl_cmd->sc;
Andy Grover59511462011-07-19 10:26:37 +0000144 struct scatterlist *sgl_bidi = NULL;
145 u32 sgl_bidi_count = 0;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700146 int ret;
147 /*
148 * Allocate the necessary tasks to complete the received CDB+data
149 */
Andy Grover59511462011-07-19 10:26:37 +0000150 ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
151 if (ret == -ENOMEM) {
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700152 /* Out of Resources */
153 return PYX_TRANSPORT_LU_COMM_FAILURE;
Andy Grover59511462011-07-19 10:26:37 +0000154 } else if (ret == -EINVAL) {
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700155 /*
156 * Handle case for SAM_STAT_RESERVATION_CONFLICT
157 */
158 if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
159 return PYX_TRANSPORT_RESERVATION_CONFLICT;
160 /*
161 * Otherwise, return SAM_STAT_CHECK_CONDITION and return
162 * sense data.
163 */
164 return PYX_TRANSPORT_USE_SENSE_REASON;
165 }
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700166
Andy Grover59511462011-07-19 10:26:37 +0000167 /*
168 * For BIDI commands, pass in the extra READ buffer
169 * to transport_generic_map_mem_to_cmd() below..
170 */
Andy Grovera1d8b492011-05-02 17:12:10 -0700171 if (se_cmd->t_tasks_bidi) {
Andy Grover59511462011-07-19 10:26:37 +0000172 struct scsi_data_buffer *sdb = scsi_in(sc);
173
174 sgl_bidi = sdb->table.sgl;
175 sgl_bidi_count = sdb->table.nents;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700176 }
Nicholas Bellinger8cd79f22011-10-24 13:35:37 -0700177 /*
178 * Because some userspace code via scsi-generic do not memset their
179 * associated read buffers, go ahead and do that here for type
180 * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently
181 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
182 * by target core in transport_generic_allocate_tasks() ->
183 * transport_generic_cmd_sequencer().
184 */
185 if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
186 se_cmd->data_direction == DMA_FROM_DEVICE) {
187 struct scatterlist *sg = scsi_sglist(sc);
188 unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
189
190 if (buf != NULL) {
191 memset(buf, 0, sg->length);
192 kunmap(sg_page(sg));
193 }
194 }
Andy Grover59511462011-07-19 10:26:37 +0000195
Andy Groverec98f782011-07-20 19:28:46 +0000196 /* Tell the core about our preallocated memory */
Andy Grover59511462011-07-19 10:26:37 +0000197 ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
198 scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700199 if (ret < 0)
200 return PYX_TRANSPORT_LU_COMM_FAILURE;
201
202 return 0;
203}
204
205/*
206 * Called from struct target_core_fabric_ops->check_stop_free()
207 */
Nicholas Bellinger88dd9e22011-11-02 03:33:16 -0700208static int tcm_loop_check_stop_free(struct se_cmd *se_cmd)
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700209{
210 /*
211 * Do not release struct se_cmd's containing a valid TMR
212 * pointer. These will be released directly in tcm_loop_device_reset()
213 * with transport_generic_free_cmd().
214 */
215 if (se_cmd->se_tmr_req)
Nicholas Bellinger88dd9e22011-11-02 03:33:16 -0700216 return 0;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700217 /*
218 * Release the struct se_cmd, which will make a callback to release
219 * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
220 */
Christoph Hellwig82f1c8a2011-09-13 23:09:01 +0200221 transport_generic_free_cmd(se_cmd, 0);
Nicholas Bellinger88dd9e22011-11-02 03:33:16 -0700222 return 1;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700223}
224
Christoph Hellwig35462972011-05-31 23:56:57 -0400225static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700226{
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
233static 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
240static int tcm_loop_driver_probe(struct device *);
241static int tcm_loop_driver_remove(struct device *);
242
243static int pseudo_lld_bus_match(struct device *dev,
244 struct device_driver *dev_driver)
245{
246 return 1;
247}
248
249static 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
256static 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 */
263struct 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 */
269static 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 */
294static 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
Andy Grover6708bb22011-06-08 10:36:43 -0700303 pr_debug("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700304 " 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];
Nicholas Bellinger0a020432011-10-10 19:44:05 -0700312 /*
313 * Ensure that this tl_tpg reference from the incoming sc->device->id
314 * has already been configured via tcm_loop_make_naa_tpg().
315 */
316 if (!tl_tpg->tl_hba) {
317 set_host_byte(sc, DID_NO_CONNECT);
318 sc->scsi_done(sc);
319 return 0;
320 }
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700321 se_tpg = &tl_tpg->tl_se_tpg;
322 /*
323 * Determine the SAM Task Attribute and allocate tl_cmd and
324 * tl_cmd->tl_se_cmd from TCM infrastructure
325 */
326 se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc);
327 if (!se_cmd) {
328 sc->scsi_done(sc);
329 return 0;
330 }
331 /*
332 * Queue up the newly allocated to be processed in TCM thread context.
333 */
334 transport_generic_handle_cdb_map(se_cmd);
335 return 0;
336}
337
338/*
339 * Called from SCSI EH process context to issue a LUN_RESET TMR
340 * to struct scsi_device
341 */
342static int tcm_loop_device_reset(struct scsi_cmnd *sc)
343{
344 struct se_cmd *se_cmd = NULL;
345 struct se_portal_group *se_tpg;
346 struct se_session *se_sess;
347 struct tcm_loop_cmd *tl_cmd = NULL;
348 struct tcm_loop_hba *tl_hba;
349 struct tcm_loop_nexus *tl_nexus;
350 struct tcm_loop_tmr *tl_tmr = NULL;
351 struct tcm_loop_tpg *tl_tpg;
352 int ret = FAILED;
353 /*
354 * Locate the tcm_loop_hba_t pointer
355 */
356 tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
357 /*
358 * Locate the tl_nexus and se_sess pointers
359 */
360 tl_nexus = tl_hba->tl_nexus;
361 if (!tl_nexus) {
Andy Grover6708bb22011-06-08 10:36:43 -0700362 pr_err("Unable to perform device reset without"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700363 " active I_T Nexus\n");
364 return FAILED;
365 }
366 se_sess = tl_nexus->se_sess;
367 /*
368 * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id
369 */
370 tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
371 se_tpg = &tl_tpg->tl_se_tpg;
372
373 tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL);
374 if (!tl_cmd) {
Andy Grover6708bb22011-06-08 10:36:43 -0700375 pr_err("Unable to allocate memory for tl_cmd\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700376 return FAILED;
377 }
378
379 tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL);
380 if (!tl_tmr) {
Andy Grover6708bb22011-06-08 10:36:43 -0700381 pr_err("Unable to allocate memory for tl_tmr\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700382 goto release;
383 }
384 init_waitqueue_head(&tl_tmr->tl_tmr_wait);
385
386 se_cmd = &tl_cmd->tl_se_cmd;
387 /*
388 * Initialize struct se_cmd descriptor from target_core_mod infrastructure
389 */
390 transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0,
Nicholas Bellinger61db1802011-05-19 20:19:14 -0700391 DMA_NONE, MSG_SIMPLE_TAG,
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700392 &tl_cmd->tl_sense_buf[0]);
393 /*
394 * Allocate the LUN_RESET TMR
395 */
Andy Grover59511462011-07-19 10:26:37 +0000396 se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
Roland Dreierdd503a52011-10-06 09:56:16 -0700397 TMR_LUN_RESET, GFP_KERNEL);
Dan Carpenter552523d2011-06-15 09:41:33 -0700398 if (IS_ERR(se_cmd->se_tmr_req))
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700399 goto release;
400 /*
401 * Locate the underlying TCM struct se_lun from sc->device->lun
402 */
Andy Grover59511462011-07-19 10:26:37 +0000403 if (transport_lookup_tmr_lun(se_cmd, sc->device->lun) < 0)
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700404 goto release;
405 /*
406 * Queue the TMR to TCM Core and sleep waiting for tcm_loop_queue_tm_rsp()
407 * to wake us up.
408 */
409 transport_generic_handle_tmr(se_cmd);
410 wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete));
411 /*
412 * The TMR LUN_RESET has completed, check the response status and
413 * then release allocations.
414 */
415 ret = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
416 SUCCESS : FAILED;
417release:
418 if (se_cmd)
Christoph Hellwig82f1c8a2011-09-13 23:09:01 +0200419 transport_generic_free_cmd(se_cmd, 1);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700420 else
421 kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
422 kfree(tl_tmr);
423 return ret;
424}
425
426static int tcm_loop_slave_alloc(struct scsi_device *sd)
427{
428 set_bit(QUEUE_FLAG_BIDI, &sd->request_queue->queue_flags);
429 return 0;
430}
431
432static int tcm_loop_slave_configure(struct scsi_device *sd)
433{
434 return 0;
435}
436
437static struct scsi_host_template tcm_loop_driver_template = {
438 .proc_info = tcm_loop_proc_info,
439 .proc_name = "tcm_loopback",
440 .name = "TCM_Loopback",
441 .queuecommand = tcm_loop_queuecommand,
442 .change_queue_depth = tcm_loop_change_queue_depth,
443 .eh_device_reset_handler = tcm_loop_device_reset,
444 .can_queue = TL_SCSI_CAN_QUEUE,
445 .this_id = -1,
446 .sg_tablesize = TL_SCSI_SG_TABLESIZE,
447 .cmd_per_lun = TL_SCSI_CMD_PER_LUN,
448 .max_sectors = TL_SCSI_MAX_SECTORS,
449 .use_clustering = DISABLE_CLUSTERING,
450 .slave_alloc = tcm_loop_slave_alloc,
451 .slave_configure = tcm_loop_slave_configure,
452 .module = THIS_MODULE,
453};
454
455static int tcm_loop_driver_probe(struct device *dev)
456{
457 struct tcm_loop_hba *tl_hba;
458 struct Scsi_Host *sh;
459 int error;
460
461 tl_hba = to_tcm_loop_hba(dev);
462
463 sh = scsi_host_alloc(&tcm_loop_driver_template,
464 sizeof(struct tcm_loop_hba));
465 if (!sh) {
Andy Grover6708bb22011-06-08 10:36:43 -0700466 pr_err("Unable to allocate struct scsi_host\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700467 return -ENODEV;
468 }
469 tl_hba->sh = sh;
470
471 /*
472 * Assign the struct tcm_loop_hba pointer to struct Scsi_Host->hostdata
473 */
474 *((struct tcm_loop_hba **)sh->hostdata) = tl_hba;
475 /*
476 * Setup single ID, Channel and LUN for now..
477 */
478 sh->max_id = 2;
479 sh->max_lun = 0;
480 sh->max_channel = 0;
481 sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN;
482
483 error = scsi_add_host(sh, &tl_hba->dev);
484 if (error) {
Andy Grover6708bb22011-06-08 10:36:43 -0700485 pr_err("%s: scsi_add_host failed\n", __func__);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700486 scsi_host_put(sh);
487 return -ENODEV;
488 }
489 return 0;
490}
491
492static int tcm_loop_driver_remove(struct device *dev)
493{
494 struct tcm_loop_hba *tl_hba;
495 struct Scsi_Host *sh;
496
497 tl_hba = to_tcm_loop_hba(dev);
498 sh = tl_hba->sh;
499
500 scsi_remove_host(sh);
501 scsi_host_put(sh);
502 return 0;
503}
504
505static void tcm_loop_release_adapter(struct device *dev)
506{
507 struct tcm_loop_hba *tl_hba = to_tcm_loop_hba(dev);
508
509 kfree(tl_hba);
510}
511
512/*
513 * Called from tcm_loop_make_scsi_hba() in tcm_loop_configfs.c
514 */
515static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host_id)
516{
517 int ret;
518
519 tl_hba->dev.bus = &tcm_loop_lld_bus;
520 tl_hba->dev.parent = tcm_loop_primary;
521 tl_hba->dev.release = &tcm_loop_release_adapter;
522 dev_set_name(&tl_hba->dev, "tcm_loop_adapter_%d", tcm_loop_host_id);
523
524 ret = device_register(&tl_hba->dev);
525 if (ret) {
Andy Grover6708bb22011-06-08 10:36:43 -0700526 pr_err("device_register() failed for"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700527 " tl_hba->dev: %d\n", ret);
528 return -ENODEV;
529 }
530
531 return 0;
532}
533
534/*
535 * Called from tcm_loop_fabric_init() in tcl_loop_fabric.c to load the emulated
536 * tcm_loop SCSI bus.
537 */
538static int tcm_loop_alloc_core_bus(void)
539{
540 int ret;
541
542 tcm_loop_primary = root_device_register("tcm_loop_0");
543 if (IS_ERR(tcm_loop_primary)) {
Andy Grover6708bb22011-06-08 10:36:43 -0700544 pr_err("Unable to allocate tcm_loop_primary\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700545 return PTR_ERR(tcm_loop_primary);
546 }
547
548 ret = bus_register(&tcm_loop_lld_bus);
549 if (ret) {
Andy Grover6708bb22011-06-08 10:36:43 -0700550 pr_err("bus_register() failed for tcm_loop_lld_bus\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700551 goto dev_unreg;
552 }
553
554 ret = driver_register(&tcm_loop_driverfs);
555 if (ret) {
Andy Grover6708bb22011-06-08 10:36:43 -0700556 pr_err("driver_register() failed for"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700557 "tcm_loop_driverfs\n");
558 goto bus_unreg;
559 }
560
Andy Grover6708bb22011-06-08 10:36:43 -0700561 pr_debug("Initialized TCM Loop Core Bus\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700562 return ret;
563
564bus_unreg:
565 bus_unregister(&tcm_loop_lld_bus);
566dev_unreg:
567 root_device_unregister(tcm_loop_primary);
568 return ret;
569}
570
571static void tcm_loop_release_core_bus(void)
572{
573 driver_unregister(&tcm_loop_driverfs);
574 bus_unregister(&tcm_loop_lld_bus);
575 root_device_unregister(tcm_loop_primary);
576
Andy Grover6708bb22011-06-08 10:36:43 -0700577 pr_debug("Releasing TCM Loop Core BUS\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700578}
579
580static char *tcm_loop_get_fabric_name(void)
581{
582 return "loopback";
583}
584
585static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg)
586{
587 struct tcm_loop_tpg *tl_tpg =
588 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
589 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
590 /*
591 * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba()
592 * time based on the protocol dependent prefix of the passed configfs group.
593 *
594 * Based upon tl_proto_id, TCM_Loop emulates the requested fabric
595 * ProtocolID using target_core_fabric_lib.c symbols.
596 */
597 switch (tl_hba->tl_proto_id) {
598 case SCSI_PROTOCOL_SAS:
599 return sas_get_fabric_proto_ident(se_tpg);
600 case SCSI_PROTOCOL_FCP:
601 return fc_get_fabric_proto_ident(se_tpg);
602 case SCSI_PROTOCOL_ISCSI:
603 return iscsi_get_fabric_proto_ident(se_tpg);
604 default:
Andy Grover6708bb22011-06-08 10:36:43 -0700605 pr_err("Unknown tl_proto_id: 0x%02x, using"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700606 " SAS emulation\n", tl_hba->tl_proto_id);
607 break;
608 }
609
610 return sas_get_fabric_proto_ident(se_tpg);
611}
612
613static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg)
614{
615 struct tcm_loop_tpg *tl_tpg =
616 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
617 /*
618 * Return the passed NAA identifier for the SAS Target Port
619 */
620 return &tl_tpg->tl_hba->tl_wwn_address[0];
621}
622
623static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg)
624{
625 struct tcm_loop_tpg *tl_tpg =
626 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
627 /*
628 * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83
629 * to represent the SCSI Target Port.
630 */
631 return tl_tpg->tl_tpgt;
632}
633
634static u32 tcm_loop_get_default_depth(struct se_portal_group *se_tpg)
635{
636 return 1;
637}
638
639static u32 tcm_loop_get_pr_transport_id(
640 struct se_portal_group *se_tpg,
641 struct se_node_acl *se_nacl,
642 struct t10_pr_registration *pr_reg,
643 int *format_code,
644 unsigned char *buf)
645{
646 struct tcm_loop_tpg *tl_tpg =
647 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
648 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
649
650 switch (tl_hba->tl_proto_id) {
651 case SCSI_PROTOCOL_SAS:
652 return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
653 format_code, buf);
654 case SCSI_PROTOCOL_FCP:
655 return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
656 format_code, buf);
657 case SCSI_PROTOCOL_ISCSI:
658 return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
659 format_code, buf);
660 default:
Andy Grover6708bb22011-06-08 10:36:43 -0700661 pr_err("Unknown tl_proto_id: 0x%02x, using"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700662 " SAS emulation\n", tl_hba->tl_proto_id);
663 break;
664 }
665
666 return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
667 format_code, buf);
668}
669
670static u32 tcm_loop_get_pr_transport_id_len(
671 struct se_portal_group *se_tpg,
672 struct se_node_acl *se_nacl,
673 struct t10_pr_registration *pr_reg,
674 int *format_code)
675{
676 struct tcm_loop_tpg *tl_tpg =
677 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
678 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
679
680 switch (tl_hba->tl_proto_id) {
681 case SCSI_PROTOCOL_SAS:
682 return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
683 format_code);
684 case SCSI_PROTOCOL_FCP:
685 return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
686 format_code);
687 case SCSI_PROTOCOL_ISCSI:
688 return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
689 format_code);
690 default:
Andy Grover6708bb22011-06-08 10:36:43 -0700691 pr_err("Unknown tl_proto_id: 0x%02x, using"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700692 " SAS emulation\n", tl_hba->tl_proto_id);
693 break;
694 }
695
696 return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
697 format_code);
698}
699
700/*
701 * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
702 * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
703 */
704static char *tcm_loop_parse_pr_out_transport_id(
705 struct se_portal_group *se_tpg,
706 const char *buf,
707 u32 *out_tid_len,
708 char **port_nexus_ptr)
709{
710 struct tcm_loop_tpg *tl_tpg =
711 (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
712 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
713
714 switch (tl_hba->tl_proto_id) {
715 case SCSI_PROTOCOL_SAS:
716 return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
717 port_nexus_ptr);
718 case SCSI_PROTOCOL_FCP:
719 return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
720 port_nexus_ptr);
721 case SCSI_PROTOCOL_ISCSI:
722 return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
723 port_nexus_ptr);
724 default:
Andy Grover6708bb22011-06-08 10:36:43 -0700725 pr_err("Unknown tl_proto_id: 0x%02x, using"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700726 " SAS emulation\n", tl_hba->tl_proto_id);
727 break;
728 }
729
730 return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
731 port_nexus_ptr);
732}
733
734/*
735 * Returning (1) here allows for target_core_mod struct se_node_acl to be generated
736 * based upon the incoming fabric dependent SCSI Initiator Port
737 */
738static int tcm_loop_check_demo_mode(struct se_portal_group *se_tpg)
739{
740 return 1;
741}
742
743static int tcm_loop_check_demo_mode_cache(struct se_portal_group *se_tpg)
744{
745 return 0;
746}
747
748/*
749 * Allow I_T Nexus full READ-WRITE access without explict Initiator Node ACLs for
750 * local virtual Linux/SCSI LLD passthrough into VM hypervisor guest
751 */
752static int tcm_loop_check_demo_mode_write_protect(struct se_portal_group *se_tpg)
753{
754 return 0;
755}
756
757/*
758 * Because TCM_Loop does not use explict ACLs and MappedLUNs, this will
759 * never be called for TCM_Loop by target_core_fabric_configfs.c code.
760 * It has been added here as a nop for target_fabric_tf_ops_check()
761 */
762static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg)
763{
764 return 0;
765}
766
767static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl(
768 struct se_portal_group *se_tpg)
769{
770 struct tcm_loop_nacl *tl_nacl;
771
772 tl_nacl = kzalloc(sizeof(struct tcm_loop_nacl), GFP_KERNEL);
773 if (!tl_nacl) {
Andy Grover6708bb22011-06-08 10:36:43 -0700774 pr_err("Unable to allocate struct tcm_loop_nacl\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700775 return NULL;
776 }
777
778 return &tl_nacl->se_node_acl;
779}
780
781static void tcm_loop_tpg_release_fabric_acl(
782 struct se_portal_group *se_tpg,
783 struct se_node_acl *se_nacl)
784{
785 struct tcm_loop_nacl *tl_nacl = container_of(se_nacl,
786 struct tcm_loop_nacl, se_node_acl);
787
788 kfree(tl_nacl);
789}
790
791static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg)
792{
793 return 1;
794}
795
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700796static int tcm_loop_is_state_remove(struct se_cmd *se_cmd)
797{
798 /*
799 * Assume struct scsi_cmnd is not in remove state..
800 */
801 return 0;
802}
803
804static int tcm_loop_sess_logged_in(struct se_session *se_sess)
805{
806 /*
807 * Assume that TL Nexus is always active
808 */
809 return 1;
810}
811
812static u32 tcm_loop_sess_get_index(struct se_session *se_sess)
813{
814 return 1;
815}
816
817static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl)
818{
819 return;
820}
821
822static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd)
823{
824 return 1;
825}
826
827static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd)
828{
829 struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
830 struct tcm_loop_cmd, tl_se_cmd);
831
832 return tl_cmd->sc_cmd_state;
833}
834
835static int tcm_loop_shutdown_session(struct se_session *se_sess)
836{
837 return 0;
838}
839
840static void tcm_loop_close_session(struct se_session *se_sess)
841{
842 return;
843};
844
845static void tcm_loop_stop_session(
846 struct se_session *se_sess,
847 int sess_sleep,
848 int conn_sleep)
849{
850 return;
851}
852
853static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess)
854{
855 return;
856}
857
858static int tcm_loop_write_pending(struct se_cmd *se_cmd)
859{
860 /*
861 * Since Linux/SCSI has already sent down a struct scsi_cmnd
862 * sc->sc_data_direction of DMA_TO_DEVICE with struct scatterlist array
863 * memory, and memory has already been mapped to struct se_cmd->t_mem_list
864 * format with transport_generic_map_mem_to_cmd().
865 *
866 * We now tell TCM to add this WRITE CDB directly into the TCM storage
867 * object execution queue.
868 */
869 transport_generic_process_write(se_cmd);
870 return 0;
871}
872
873static int tcm_loop_write_pending_status(struct se_cmd *se_cmd)
874{
875 return 0;
876}
877
878static int tcm_loop_queue_data_in(struct se_cmd *se_cmd)
879{
880 struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
881 struct tcm_loop_cmd, tl_se_cmd);
882 struct scsi_cmnd *sc = tl_cmd->sc;
883
Andy Grover6708bb22011-06-08 10:36:43 -0700884 pr_debug("tcm_loop_queue_data_in() called for scsi_cmnd: %p"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700885 " cdb: 0x%02x\n", sc, sc->cmnd[0]);
886
887 sc->result = SAM_STAT_GOOD;
888 set_host_byte(sc, DID_OK);
889 sc->scsi_done(sc);
890 return 0;
891}
892
893static int tcm_loop_queue_status(struct se_cmd *se_cmd)
894{
895 struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
896 struct tcm_loop_cmd, tl_se_cmd);
897 struct scsi_cmnd *sc = tl_cmd->sc;
898
Andy Grover6708bb22011-06-08 10:36:43 -0700899 pr_debug("tcm_loop_queue_status() called for scsi_cmnd: %p"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700900 " cdb: 0x%02x\n", sc, sc->cmnd[0]);
901
902 if (se_cmd->sense_buffer &&
903 ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
904 (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
905
Andy Grover59511462011-07-19 10:26:37 +0000906 memcpy(sc->sense_buffer, se_cmd->sense_buffer,
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700907 SCSI_SENSE_BUFFERSIZE);
908 sc->result = SAM_STAT_CHECK_CONDITION;
909 set_driver_byte(sc, DRIVER_SENSE);
910 } else
911 sc->result = se_cmd->scsi_status;
912
913 set_host_byte(sc, DID_OK);
914 sc->scsi_done(sc);
915 return 0;
916}
917
918static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
919{
920 struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
921 struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr;
922 /*
923 * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead
924 * and wake up the wait_queue_head_t in tcm_loop_device_reset()
925 */
926 atomic_set(&tl_tmr->tmr_complete, 1);
927 wake_up(&tl_tmr->tl_tmr_wait);
928 return 0;
929}
930
931static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
932{
933 return 0;
934}
935
936static u16 tcm_loop_get_fabric_sense_len(void)
937{
938 return 0;
939}
940
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700941static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
942{
943 switch (tl_hba->tl_proto_id) {
944 case SCSI_PROTOCOL_SAS:
945 return "SAS";
946 case SCSI_PROTOCOL_FCP:
947 return "FCP";
948 case SCSI_PROTOCOL_ISCSI:
949 return "iSCSI";
950 default:
951 break;
952 }
953
954 return "Unknown";
955}
956
957/* Start items for tcm_loop_port_cit */
958
959static int tcm_loop_port_link(
960 struct se_portal_group *se_tpg,
961 struct se_lun *lun)
962{
963 struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
964 struct tcm_loop_tpg, tl_se_tpg);
965 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
966
967 atomic_inc(&tl_tpg->tl_tpg_port_count);
968 smp_mb__after_atomic_inc();
969 /*
970 * Add Linux/SCSI struct scsi_device by HCTL
971 */
972 scsi_add_device(tl_hba->sh, 0, tl_tpg->tl_tpgt, lun->unpacked_lun);
973
Andy Grover6708bb22011-06-08 10:36:43 -0700974 pr_debug("TCM_Loop_ConfigFS: Port Link Successful\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700975 return 0;
976}
977
978static void tcm_loop_port_unlink(
979 struct se_portal_group *se_tpg,
980 struct se_lun *se_lun)
981{
982 struct scsi_device *sd;
983 struct tcm_loop_hba *tl_hba;
984 struct tcm_loop_tpg *tl_tpg;
985
986 tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg);
987 tl_hba = tl_tpg->tl_hba;
988
989 sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt,
990 se_lun->unpacked_lun);
991 if (!sd) {
Andy Grover6708bb22011-06-08 10:36:43 -0700992 pr_err("Unable to locate struct scsi_device for %d:%d:"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -0700993 "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun);
994 return;
995 }
996 /*
997 * Remove Linux/SCSI struct scsi_device by HCTL
998 */
999 scsi_remove_device(sd);
1000 scsi_device_put(sd);
1001
1002 atomic_dec(&tl_tpg->tl_tpg_port_count);
1003 smp_mb__after_atomic_dec();
1004
Andy Grover6708bb22011-06-08 10:36:43 -07001005 pr_debug("TCM_Loop_ConfigFS: Port Unlink Successful\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001006}
1007
1008/* End items for tcm_loop_port_cit */
1009
1010/* Start items for tcm_loop_nexus_cit */
1011
1012static int tcm_loop_make_nexus(
1013 struct tcm_loop_tpg *tl_tpg,
1014 const char *name)
1015{
1016 struct se_portal_group *se_tpg;
1017 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
1018 struct tcm_loop_nexus *tl_nexus;
Dan Carpenter552523d2011-06-15 09:41:33 -07001019 int ret = -ENOMEM;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001020
1021 if (tl_tpg->tl_hba->tl_nexus) {
Andy Grover6708bb22011-06-08 10:36:43 -07001022 pr_debug("tl_tpg->tl_hba->tl_nexus already exists\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001023 return -EEXIST;
1024 }
1025 se_tpg = &tl_tpg->tl_se_tpg;
1026
1027 tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL);
1028 if (!tl_nexus) {
Andy Grover6708bb22011-06-08 10:36:43 -07001029 pr_err("Unable to allocate struct tcm_loop_nexus\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001030 return -ENOMEM;
1031 }
1032 /*
1033 * Initialize the struct se_session pointer
1034 */
1035 tl_nexus->se_sess = transport_init_session();
Dan Carpenter552523d2011-06-15 09:41:33 -07001036 if (IS_ERR(tl_nexus->se_sess)) {
1037 ret = PTR_ERR(tl_nexus->se_sess);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001038 goto out;
Dan Carpenter552523d2011-06-15 09:41:33 -07001039 }
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001040 /*
1041 * Since we are running in 'demo mode' this call with generate a
1042 * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI
1043 * Initiator port name of the passed configfs group 'name'.
1044 */
1045 tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
1046 se_tpg, (unsigned char *)name);
1047 if (!tl_nexus->se_sess->se_node_acl) {
1048 transport_free_session(tl_nexus->se_sess);
1049 goto out;
1050 }
1051 /*
1052 * Now, register the SAS I_T Nexus as active with the call to
1053 * transport_register_session()
1054 */
1055 __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
Andy Grover59511462011-07-19 10:26:37 +00001056 tl_nexus->se_sess, tl_nexus);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001057 tl_tpg->tl_hba->tl_nexus = tl_nexus;
Andy Grover6708bb22011-06-08 10:36:43 -07001058 pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001059 " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba),
1060 name);
1061 return 0;
1062
1063out:
1064 kfree(tl_nexus);
Dan Carpenter552523d2011-06-15 09:41:33 -07001065 return ret;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001066}
1067
1068static int tcm_loop_drop_nexus(
1069 struct tcm_loop_tpg *tpg)
1070{
1071 struct se_session *se_sess;
1072 struct tcm_loop_nexus *tl_nexus;
1073 struct tcm_loop_hba *tl_hba = tpg->tl_hba;
1074
1075 tl_nexus = tpg->tl_hba->tl_nexus;
1076 if (!tl_nexus)
1077 return -ENODEV;
1078
1079 se_sess = tl_nexus->se_sess;
1080 if (!se_sess)
1081 return -ENODEV;
1082
1083 if (atomic_read(&tpg->tl_tpg_port_count)) {
Andy Grover6708bb22011-06-08 10:36:43 -07001084 pr_err("Unable to remove TCM_Loop I_T Nexus with"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001085 " active TPG port count: %d\n",
1086 atomic_read(&tpg->tl_tpg_port_count));
1087 return -EPERM;
1088 }
1089
Andy Grover6708bb22011-06-08 10:36:43 -07001090 pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001091 " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba),
1092 tl_nexus->se_sess->se_node_acl->initiatorname);
1093 /*
1094 * Release the SCSI I_T Nexus to the emulated SAS Target Port
1095 */
1096 transport_deregister_session(tl_nexus->se_sess);
1097 tpg->tl_hba->tl_nexus = NULL;
1098 kfree(tl_nexus);
1099 return 0;
1100}
1101
1102/* End items for tcm_loop_nexus_cit */
1103
1104static ssize_t tcm_loop_tpg_show_nexus(
1105 struct se_portal_group *se_tpg,
1106 char *page)
1107{
1108 struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
1109 struct tcm_loop_tpg, tl_se_tpg);
1110 struct tcm_loop_nexus *tl_nexus;
1111 ssize_t ret;
1112
1113 tl_nexus = tl_tpg->tl_hba->tl_nexus;
1114 if (!tl_nexus)
1115 return -ENODEV;
1116
1117 ret = snprintf(page, PAGE_SIZE, "%s\n",
1118 tl_nexus->se_sess->se_node_acl->initiatorname);
1119
1120 return ret;
1121}
1122
1123static ssize_t tcm_loop_tpg_store_nexus(
1124 struct se_portal_group *se_tpg,
1125 const char *page,
1126 size_t count)
1127{
1128 struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
1129 struct tcm_loop_tpg, tl_se_tpg);
1130 struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
1131 unsigned char i_port[TL_WWN_ADDR_LEN], *ptr, *port_ptr;
1132 int ret;
1133 /*
1134 * Shutdown the active I_T nexus if 'NULL' is passed..
1135 */
1136 if (!strncmp(page, "NULL", 4)) {
1137 ret = tcm_loop_drop_nexus(tl_tpg);
1138 return (!ret) ? count : ret;
1139 }
1140 /*
1141 * Otherwise make sure the passed virtual Initiator port WWN matches
1142 * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call
1143 * tcm_loop_make_nexus()
1144 */
Dan Carpenter60d645a2011-06-15 10:03:05 -07001145 if (strlen(page) >= TL_WWN_ADDR_LEN) {
Andy Grover6708bb22011-06-08 10:36:43 -07001146 pr_err("Emulated NAA Sas Address: %s, exceeds"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001147 " max: %d\n", page, TL_WWN_ADDR_LEN);
1148 return -EINVAL;
1149 }
1150 snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page);
1151
1152 ptr = strstr(i_port, "naa.");
1153 if (ptr) {
1154 if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) {
Andy Grover6708bb22011-06-08 10:36:43 -07001155 pr_err("Passed SAS Initiator Port %s does not"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001156 " match target port protoid: %s\n", i_port,
1157 tcm_loop_dump_proto_id(tl_hba));
1158 return -EINVAL;
1159 }
1160 port_ptr = &i_port[0];
1161 goto check_newline;
1162 }
1163 ptr = strstr(i_port, "fc.");
1164 if (ptr) {
1165 if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) {
Andy Grover6708bb22011-06-08 10:36:43 -07001166 pr_err("Passed FCP Initiator Port %s does not"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001167 " match target port protoid: %s\n", i_port,
1168 tcm_loop_dump_proto_id(tl_hba));
1169 return -EINVAL;
1170 }
1171 port_ptr = &i_port[3]; /* Skip over "fc." */
1172 goto check_newline;
1173 }
1174 ptr = strstr(i_port, "iqn.");
1175 if (ptr) {
1176 if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) {
Andy Grover6708bb22011-06-08 10:36:43 -07001177 pr_err("Passed iSCSI Initiator Port %s does not"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001178 " match target port protoid: %s\n", i_port,
1179 tcm_loop_dump_proto_id(tl_hba));
1180 return -EINVAL;
1181 }
1182 port_ptr = &i_port[0];
1183 goto check_newline;
1184 }
Andy Grover6708bb22011-06-08 10:36:43 -07001185 pr_err("Unable to locate prefix for emulated Initiator Port:"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001186 " %s\n", i_port);
1187 return -EINVAL;
1188 /*
1189 * Clear any trailing newline for the NAA WWN
1190 */
1191check_newline:
1192 if (i_port[strlen(i_port)-1] == '\n')
1193 i_port[strlen(i_port)-1] = '\0';
1194
1195 ret = tcm_loop_make_nexus(tl_tpg, port_ptr);
1196 if (ret < 0)
1197 return ret;
1198
1199 return count;
1200}
1201
1202TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR);
1203
1204static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
1205 &tcm_loop_tpg_nexus.attr,
1206 NULL,
1207};
1208
1209/* Start items for tcm_loop_naa_cit */
1210
1211struct se_portal_group *tcm_loop_make_naa_tpg(
1212 struct se_wwn *wwn,
1213 struct config_group *group,
1214 const char *name)
1215{
1216 struct tcm_loop_hba *tl_hba = container_of(wwn,
1217 struct tcm_loop_hba, tl_hba_wwn);
1218 struct tcm_loop_tpg *tl_tpg;
1219 char *tpgt_str, *end_ptr;
1220 int ret;
1221 unsigned short int tpgt;
1222
1223 tpgt_str = strstr(name, "tpgt_");
1224 if (!tpgt_str) {
Andy Grover6708bb22011-06-08 10:36:43 -07001225 pr_err("Unable to locate \"tpgt_#\" directory"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001226 " group\n");
1227 return ERR_PTR(-EINVAL);
1228 }
1229 tpgt_str += 5; /* Skip ahead of "tpgt_" */
1230 tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
1231
Dan Carpenter12f09cc2011-04-02 14:32:47 -07001232 if (tpgt >= TL_TPGS_PER_HBA) {
Andy Grover6708bb22011-06-08 10:36:43 -07001233 pr_err("Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001234 " %u\n", tpgt, TL_TPGS_PER_HBA);
1235 return ERR_PTR(-EINVAL);
1236 }
1237 tl_tpg = &tl_hba->tl_hba_tpgs[tpgt];
1238 tl_tpg->tl_hba = tl_hba;
1239 tl_tpg->tl_tpgt = tpgt;
1240 /*
1241 * Register the tl_tpg as a emulated SAS TCM Target Endpoint
1242 */
1243 ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops,
Andy Grover59511462011-07-19 10:26:37 +00001244 wwn, &tl_tpg->tl_se_tpg, tl_tpg,
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001245 TRANSPORT_TPG_TYPE_NORMAL);
1246 if (ret < 0)
1247 return ERR_PTR(-ENOMEM);
1248
Andy Grover6708bb22011-06-08 10:36:43 -07001249 pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001250 " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
1251 config_item_name(&wwn->wwn_group.cg_item), tpgt);
1252
1253 return &tl_tpg->tl_se_tpg;
1254}
1255
1256void tcm_loop_drop_naa_tpg(
1257 struct se_portal_group *se_tpg)
1258{
1259 struct se_wwn *wwn = se_tpg->se_tpg_wwn;
1260 struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
1261 struct tcm_loop_tpg, tl_se_tpg);
1262 struct tcm_loop_hba *tl_hba;
1263 unsigned short tpgt;
1264
1265 tl_hba = tl_tpg->tl_hba;
1266 tpgt = tl_tpg->tl_tpgt;
1267 /*
1268 * Release the I_T Nexus for the Virtual SAS link if present
1269 */
1270 tcm_loop_drop_nexus(tl_tpg);
1271 /*
1272 * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint
1273 */
1274 core_tpg_deregister(se_tpg);
1275
Nicholas Bellinger0a020432011-10-10 19:44:05 -07001276 tl_tpg->tl_hba = NULL;
1277 tl_tpg->tl_tpgt = 0;
1278
Andy Grover6708bb22011-06-08 10:36:43 -07001279 pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001280 " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
1281 config_item_name(&wwn->wwn_group.cg_item), tpgt);
1282}
1283
1284/* End items for tcm_loop_naa_cit */
1285
1286/* Start items for tcm_loop_cit */
1287
1288struct se_wwn *tcm_loop_make_scsi_hba(
1289 struct target_fabric_configfs *tf,
1290 struct config_group *group,
1291 const char *name)
1292{
1293 struct tcm_loop_hba *tl_hba;
1294 struct Scsi_Host *sh;
1295 char *ptr;
1296 int ret, off = 0;
1297
1298 tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL);
1299 if (!tl_hba) {
Andy Grover6708bb22011-06-08 10:36:43 -07001300 pr_err("Unable to allocate struct tcm_loop_hba\n");
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001301 return ERR_PTR(-ENOMEM);
1302 }
1303 /*
1304 * Determine the emulated Protocol Identifier and Target Port Name
1305 * based on the incoming configfs directory name.
1306 */
1307 ptr = strstr(name, "naa.");
1308 if (ptr) {
1309 tl_hba->tl_proto_id = SCSI_PROTOCOL_SAS;
1310 goto check_len;
1311 }
1312 ptr = strstr(name, "fc.");
1313 if (ptr) {
1314 tl_hba->tl_proto_id = SCSI_PROTOCOL_FCP;
1315 off = 3; /* Skip over "fc." */
1316 goto check_len;
1317 }
1318 ptr = strstr(name, "iqn.");
Jesper Juhla57b5d32011-06-28 00:30:17 +02001319 if (!ptr) {
Andy Grover6708bb22011-06-08 10:36:43 -07001320 pr_err("Unable to locate prefix for emulated Target "
Jesper Juhla57b5d32011-06-28 00:30:17 +02001321 "Port: %s\n", name);
1322 ret = -EINVAL;
1323 goto out;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001324 }
Jesper Juhla57b5d32011-06-28 00:30:17 +02001325 tl_hba->tl_proto_id = SCSI_PROTOCOL_ISCSI;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001326
1327check_len:
Dan Carpenter60d645a2011-06-15 10:03:05 -07001328 if (strlen(name) >= TL_WWN_ADDR_LEN) {
Andy Grover6708bb22011-06-08 10:36:43 -07001329 pr_err("Emulated NAA %s Address: %s, exceeds"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001330 " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba),
1331 TL_WWN_ADDR_LEN);
Jesper Juhla57b5d32011-06-28 00:30:17 +02001332 ret = -EINVAL;
1333 goto out;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001334 }
1335 snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]);
1336
1337 /*
1338 * Call device_register(tl_hba->dev) to register the emulated
1339 * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after
1340 * device_register() callbacks in tcm_loop_driver_probe()
1341 */
1342 ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt);
1343 if (ret)
1344 goto out;
1345
1346 sh = tl_hba->sh;
1347 tcm_loop_hba_no_cnt++;
Andy Grover6708bb22011-06-08 10:36:43 -07001348 pr_debug("TCM_Loop_ConfigFS: Allocated emulated Target"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001349 " %s Address: %s at Linux/SCSI Host ID: %d\n",
1350 tcm_loop_dump_proto_id(tl_hba), name, sh->host_no);
1351
1352 return &tl_hba->tl_hba_wwn;
1353out:
1354 kfree(tl_hba);
1355 return ERR_PTR(ret);
1356}
1357
1358void tcm_loop_drop_scsi_hba(
1359 struct se_wwn *wwn)
1360{
1361 struct tcm_loop_hba *tl_hba = container_of(wwn,
1362 struct tcm_loop_hba, tl_hba_wwn);
1363 int host_no = tl_hba->sh->host_no;
1364 /*
1365 * Call device_unregister() on the original tl_hba->dev.
1366 * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will
1367 * release *tl_hba;
1368 */
1369 device_unregister(&tl_hba->dev);
1370
Andy Grover6708bb22011-06-08 10:36:43 -07001371 pr_debug("TCM_Loop_ConfigFS: Deallocated emulated Target"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001372 " SAS Address: %s at Linux/SCSI Host ID: %d\n",
1373 config_item_name(&wwn->wwn_group.cg_item), host_no);
1374}
1375
1376/* Start items for tcm_loop_cit */
1377static ssize_t tcm_loop_wwn_show_attr_version(
1378 struct target_fabric_configfs *tf,
1379 char *page)
1380{
1381 return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION);
1382}
1383
1384TF_WWN_ATTR_RO(tcm_loop, version);
1385
1386static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
1387 &tcm_loop_wwn_version.attr,
1388 NULL,
1389};
1390
1391/* End items for tcm_loop_cit */
1392
1393static int tcm_loop_register_configfs(void)
1394{
1395 struct target_fabric_configfs *fabric;
1396 struct config_group *tf_cg;
1397 int ret;
1398 /*
1399 * Set the TCM Loop HBA counter to zero
1400 */
1401 tcm_loop_hba_no_cnt = 0;
1402 /*
1403 * Register the top level struct config_item_type with TCM core
1404 */
1405 fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
Andy Grovere3d6f902011-07-19 08:55:10 +00001406 if (IS_ERR(fabric)) {
Andy Grover6708bb22011-06-08 10:36:43 -07001407 pr_err("tcm_loop_register_configfs() failed!\n");
Andy Grovere3d6f902011-07-19 08:55:10 +00001408 return PTR_ERR(fabric);
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001409 }
1410 /*
1411 * Setup the fabric API of function pointers used by target_core_mod
1412 */
1413 fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
1414 fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
1415 fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
1416 fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
1417 fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
1418 fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
1419 fabric->tf_ops.tpg_get_pr_transport_id_len =
1420 &tcm_loop_get_pr_transport_id_len;
1421 fabric->tf_ops.tpg_parse_pr_out_transport_id =
1422 &tcm_loop_parse_pr_out_transport_id;
1423 fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
1424 fabric->tf_ops.tpg_check_demo_mode_cache =
1425 &tcm_loop_check_demo_mode_cache;
1426 fabric->tf_ops.tpg_check_demo_mode_write_protect =
1427 &tcm_loop_check_demo_mode_write_protect;
1428 fabric->tf_ops.tpg_check_prod_mode_write_protect =
1429 &tcm_loop_check_prod_mode_write_protect;
1430 /*
1431 * The TCM loopback fabric module runs in demo-mode to a local
1432 * virtual SCSI device, so fabric dependent initator ACLs are
1433 * not required.
1434 */
1435 fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
1436 fabric->tf_ops.tpg_release_fabric_acl =
1437 &tcm_loop_tpg_release_fabric_acl;
1438 fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index;
1439 /*
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001440 * Used for setting up remaining TCM resources in process context
1441 */
1442 fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map;
1443 fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
Christoph Hellwig35462972011-05-31 23:56:57 -04001444 fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001445 fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
1446 fabric->tf_ops.close_session = &tcm_loop_close_session;
1447 fabric->tf_ops.stop_session = &tcm_loop_stop_session;
1448 fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0;
1449 fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in;
1450 fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
1451 fabric->tf_ops.sess_get_initiator_sid = NULL;
1452 fabric->tf_ops.write_pending = &tcm_loop_write_pending;
1453 fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status;
1454 /*
1455 * Not used for TCM loopback
1456 */
1457 fabric->tf_ops.set_default_node_attributes =
1458 &tcm_loop_set_default_node_attributes;
1459 fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag;
1460 fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001461 fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
1462 fabric->tf_ops.queue_status = &tcm_loop_queue_status;
1463 fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
1464 fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len;
1465 fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len;
1466 fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove;
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001467
1468 tf_cg = &fabric->tf_group;
1469 /*
1470 * Setup function pointers for generic logic in target_core_fabric_configfs.c
1471 */
1472 fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba;
1473 fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba;
1474 fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg;
1475 fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg;
1476 /*
1477 * fabric_post_link() and fabric_pre_unlink() are used for
1478 * registration and release of TCM Loop Virtual SCSI LUNs.
1479 */
1480 fabric->tf_ops.fabric_post_link = &tcm_loop_port_link;
1481 fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink;
1482 fabric->tf_ops.fabric_make_np = NULL;
1483 fabric->tf_ops.fabric_drop_np = NULL;
1484 /*
1485 * Setup default attribute lists for various fabric->tf_cit_tmpl
1486 */
1487 TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs;
1488 TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs;
1489 TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
1490 TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
1491 TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
1492 /*
1493 * Once fabric->tf_ops has been setup, now register the fabric for
1494 * use within TCM
1495 */
1496 ret = target_fabric_configfs_register(fabric);
1497 if (ret < 0) {
Andy Grover6708bb22011-06-08 10:36:43 -07001498 pr_err("target_fabric_configfs_register() for"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001499 " TCM_Loop failed!\n");
1500 target_fabric_configfs_free(fabric);
1501 return -1;
1502 }
1503 /*
1504 * Setup our local pointer to *fabric.
1505 */
1506 tcm_loop_fabric_configfs = fabric;
Andy Grover6708bb22011-06-08 10:36:43 -07001507 pr_debug("TCM_LOOP[0] - Set fabric ->"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001508 " tcm_loop_fabric_configfs\n");
1509 return 0;
1510}
1511
1512static void tcm_loop_deregister_configfs(void)
1513{
1514 if (!tcm_loop_fabric_configfs)
1515 return;
1516
1517 target_fabric_configfs_deregister(tcm_loop_fabric_configfs);
1518 tcm_loop_fabric_configfs = NULL;
Andy Grover6708bb22011-06-08 10:36:43 -07001519 pr_debug("TCM_LOOP[0] - Cleared"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001520 " tcm_loop_fabric_configfs\n");
1521}
1522
1523static int __init tcm_loop_fabric_init(void)
1524{
1525 int ret;
1526
1527 tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache",
1528 sizeof(struct tcm_loop_cmd),
1529 __alignof__(struct tcm_loop_cmd),
1530 0, NULL);
1531 if (!tcm_loop_cmd_cache) {
Andy Grover6708bb22011-06-08 10:36:43 -07001532 pr_debug("kmem_cache_create() for"
Nicholas Bellinger3703b2c2011-03-18 15:39:17 -07001533 " tcm_loop_cmd_cache failed\n");
1534 return -ENOMEM;
1535 }
1536
1537 ret = tcm_loop_alloc_core_bus();
1538 if (ret)
1539 return ret;
1540
1541 ret = tcm_loop_register_configfs();
1542 if (ret) {
1543 tcm_loop_release_core_bus();
1544 return ret;
1545 }
1546
1547 return 0;
1548}
1549
1550static void __exit tcm_loop_fabric_exit(void)
1551{
1552 tcm_loop_deregister_configfs();
1553 tcm_loop_release_core_bus();
1554 kmem_cache_destroy(tcm_loop_cmd_cache);
1555}
1556
1557MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module");
1558MODULE_AUTHOR("Nicholas A. Bellinger <nab@risingtidesystems.com>");
1559MODULE_LICENSE("GPL");
1560module_init(tcm_loop_fabric_init);
1561module_exit(tcm_loop_fabric_exit);