diff options
Diffstat (limited to 'drivers/target/loopback')
-rw-r--r-- | drivers/target/loopback/tcm_loop.c | 363 | ||||
-rw-r--r-- | drivers/target/loopback/tcm_loop.h | 4 |
2 files changed, 161 insertions, 206 deletions
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index c47ff7f59e57..a9b4eeefe9fc 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c | |||
@@ -44,138 +44,12 @@ | |||
44 | /* Local pointer to allocated TCM configfs fabric module */ | 44 | /* Local pointer to allocated TCM configfs fabric module */ |
45 | static struct target_fabric_configfs *tcm_loop_fabric_configfs; | 45 | static struct target_fabric_configfs *tcm_loop_fabric_configfs; |
46 | 46 | ||
47 | static struct workqueue_struct *tcm_loop_workqueue; | ||
47 | static struct kmem_cache *tcm_loop_cmd_cache; | 48 | static struct kmem_cache *tcm_loop_cmd_cache; |
48 | 49 | ||
49 | static int tcm_loop_hba_no_cnt; | 50 | static int tcm_loop_hba_no_cnt; |
50 | 51 | ||
51 | /* | 52 | static int tcm_loop_queue_status(struct se_cmd *se_cmd); |
52 | * Allocate a tcm_loop cmd descriptor from target_core_mod code | ||
53 | * | ||
54 | * Can be called from interrupt context in tcm_loop_queuecommand() below | ||
55 | */ | ||
56 | static struct se_cmd *tcm_loop_allocate_core_cmd( | ||
57 | struct tcm_loop_hba *tl_hba, | ||
58 | struct se_portal_group *se_tpg, | ||
59 | struct scsi_cmnd *sc) | ||
60 | { | ||
61 | struct se_cmd *se_cmd; | ||
62 | struct se_session *se_sess; | ||
63 | struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; | ||
64 | struct tcm_loop_cmd *tl_cmd; | ||
65 | int sam_task_attr; | ||
66 | |||
67 | if (!tl_nexus) { | ||
68 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" | ||
69 | " does not exist\n"); | ||
70 | set_host_byte(sc, DID_ERROR); | ||
71 | return NULL; | ||
72 | } | ||
73 | se_sess = tl_nexus->se_sess; | ||
74 | |||
75 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); | ||
76 | if (!tl_cmd) { | ||
77 | pr_err("Unable to allocate struct tcm_loop_cmd\n"); | ||
78 | set_host_byte(sc, DID_ERROR); | ||
79 | return NULL; | ||
80 | } | ||
81 | se_cmd = &tl_cmd->tl_se_cmd; | ||
82 | /* | ||
83 | * Save the pointer to struct scsi_cmnd *sc | ||
84 | */ | ||
85 | tl_cmd->sc = sc; | ||
86 | /* | ||
87 | * Locate the SAM Task Attr from struct scsi_cmnd * | ||
88 | */ | ||
89 | if (sc->device->tagged_supported) { | ||
90 | switch (sc->tag) { | ||
91 | case HEAD_OF_QUEUE_TAG: | ||
92 | sam_task_attr = MSG_HEAD_TAG; | ||
93 | break; | ||
94 | case ORDERED_QUEUE_TAG: | ||
95 | sam_task_attr = MSG_ORDERED_TAG; | ||
96 | break; | ||
97 | default: | ||
98 | sam_task_attr = MSG_SIMPLE_TAG; | ||
99 | break; | ||
100 | } | ||
101 | } else | ||
102 | sam_task_attr = MSG_SIMPLE_TAG; | ||
103 | |||
104 | /* | ||
105 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | ||
106 | */ | ||
107 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, | ||
108 | scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, | ||
109 | &tl_cmd->tl_sense_buf[0]); | ||
110 | |||
111 | if (scsi_bidi_cmnd(sc)) | ||
112 | se_cmd->se_cmd_flags |= SCF_BIDI; | ||
113 | |||
114 | /* | ||
115 | * Locate the struct se_lun pointer and attach it to struct se_cmd | ||
116 | */ | ||
117 | if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) { | ||
118 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
119 | set_host_byte(sc, DID_NO_CONNECT); | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | return se_cmd; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Called by struct target_core_fabric_ops->new_cmd_map() | ||
128 | * | ||
129 | * Always called in process context. A non zero return value | ||
130 | * here will signal to handle an exception based on the return code. | ||
131 | */ | ||
132 | static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) | ||
133 | { | ||
134 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
135 | struct tcm_loop_cmd, tl_se_cmd); | ||
136 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
137 | struct scatterlist *sgl_bidi = NULL; | ||
138 | u32 sgl_bidi_count = 0; | ||
139 | int ret; | ||
140 | /* | ||
141 | * Allocate the necessary tasks to complete the received CDB+data | ||
142 | */ | ||
143 | ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd); | ||
144 | if (ret != 0) | ||
145 | return ret; | ||
146 | /* | ||
147 | * For BIDI commands, pass in the extra READ buffer | ||
148 | * to transport_generic_map_mem_to_cmd() below.. | ||
149 | */ | ||
150 | if (se_cmd->se_cmd_flags & SCF_BIDI) { | ||
151 | struct scsi_data_buffer *sdb = scsi_in(sc); | ||
152 | |||
153 | sgl_bidi = sdb->table.sgl; | ||
154 | sgl_bidi_count = sdb->table.nents; | ||
155 | } | ||
156 | /* | ||
157 | * Because some userspace code via scsi-generic do not memset their | ||
158 | * associated read buffers, go ahead and do that here for type | ||
159 | * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently | ||
160 | * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB | ||
161 | * by target core in transport_generic_allocate_tasks() -> | ||
162 | * transport_generic_cmd_sequencer(). | ||
163 | */ | ||
164 | if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && | ||
165 | se_cmd->data_direction == DMA_FROM_DEVICE) { | ||
166 | struct scatterlist *sg = scsi_sglist(sc); | ||
167 | unsigned char *buf = kmap(sg_page(sg)) + sg->offset; | ||
168 | |||
169 | if (buf != NULL) { | ||
170 | memset(buf, 0, sg->length); | ||
171 | kunmap(sg_page(sg)); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* Tell the core about our preallocated memory */ | ||
176 | return transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), | ||
177 | scsi_sg_count(sc), sgl_bidi, sgl_bidi_count); | ||
178 | } | ||
179 | 53 | ||
180 | /* | 54 | /* |
181 | * Called from struct target_core_fabric_ops->check_stop_free() | 55 | * Called from struct target_core_fabric_ops->check_stop_free() |
@@ -187,7 +61,7 @@ static int tcm_loop_check_stop_free(struct se_cmd *se_cmd) | |||
187 | * pointer. These will be released directly in tcm_loop_device_reset() | 61 | * pointer. These will be released directly in tcm_loop_device_reset() |
188 | * with transport_generic_free_cmd(). | 62 | * with transport_generic_free_cmd(). |
189 | */ | 63 | */ |
190 | if (se_cmd->se_tmr_req) | 64 | if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) |
191 | return 0; | 65 | return 0; |
192 | /* | 66 | /* |
193 | * Release the struct se_cmd, which will make a callback to release | 67 | * Release the struct se_cmd, which will make a callback to release |
@@ -263,50 +137,152 @@ static int tcm_loop_change_queue_depth( | |||
263 | } | 137 | } |
264 | 138 | ||
265 | /* | 139 | /* |
266 | * Main entry point from struct scsi_host_template for incoming SCSI CDB+Data | 140 | * Locate the SAM Task Attr from struct scsi_cmnd * |
267 | * from Linux/SCSI subsystem for SCSI low level device drivers (LLDs) | ||
268 | */ | 141 | */ |
269 | static int tcm_loop_queuecommand( | 142 | static int tcm_loop_sam_attr(struct scsi_cmnd *sc) |
270 | struct Scsi_Host *sh, | ||
271 | struct scsi_cmnd *sc) | ||
272 | { | 143 | { |
273 | struct se_cmd *se_cmd; | 144 | if (sc->device->tagged_supported) { |
274 | struct se_portal_group *se_tpg; | 145 | switch (sc->tag) { |
146 | case HEAD_OF_QUEUE_TAG: | ||
147 | return MSG_HEAD_TAG; | ||
148 | case ORDERED_QUEUE_TAG: | ||
149 | return MSG_ORDERED_TAG; | ||
150 | default: | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return MSG_SIMPLE_TAG; | ||
156 | } | ||
157 | |||
158 | static void tcm_loop_submission_work(struct work_struct *work) | ||
159 | { | ||
160 | struct tcm_loop_cmd *tl_cmd = | ||
161 | container_of(work, struct tcm_loop_cmd, work); | ||
162 | struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd; | ||
163 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
164 | struct tcm_loop_nexus *tl_nexus; | ||
275 | struct tcm_loop_hba *tl_hba; | 165 | struct tcm_loop_hba *tl_hba; |
276 | struct tcm_loop_tpg *tl_tpg; | 166 | struct tcm_loop_tpg *tl_tpg; |
167 | struct scatterlist *sgl_bidi = NULL; | ||
168 | u32 sgl_bidi_count = 0; | ||
169 | int ret; | ||
277 | 170 | ||
278 | pr_debug("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x" | ||
279 | " scsi_buf_len: %u\n", sc->device->host->host_no, | ||
280 | sc->device->id, sc->device->channel, sc->device->lun, | ||
281 | sc->cmnd[0], scsi_bufflen(sc)); | ||
282 | /* | ||
283 | * Locate the tcm_loop_hba_t pointer | ||
284 | */ | ||
285 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | 171 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); |
286 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | 172 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; |
173 | |||
287 | /* | 174 | /* |
288 | * Ensure that this tl_tpg reference from the incoming sc->device->id | 175 | * Ensure that this tl_tpg reference from the incoming sc->device->id |
289 | * has already been configured via tcm_loop_make_naa_tpg(). | 176 | * has already been configured via tcm_loop_make_naa_tpg(). |
290 | */ | 177 | */ |
291 | if (!tl_tpg->tl_hba) { | 178 | if (!tl_tpg->tl_hba) { |
292 | set_host_byte(sc, DID_NO_CONNECT); | 179 | set_host_byte(sc, DID_NO_CONNECT); |
293 | sc->scsi_done(sc); | 180 | goto out_done; |
294 | return 0; | ||
295 | } | 181 | } |
296 | se_tpg = &tl_tpg->tl_se_tpg; | 182 | |
183 | tl_nexus = tl_hba->tl_nexus; | ||
184 | if (!tl_nexus) { | ||
185 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" | ||
186 | " does not exist\n"); | ||
187 | set_host_byte(sc, DID_ERROR); | ||
188 | goto out_done; | ||
189 | } | ||
190 | |||
191 | transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo, | ||
192 | tl_nexus->se_sess, | ||
193 | scsi_bufflen(sc), sc->sc_data_direction, | ||
194 | tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]); | ||
195 | |||
196 | if (scsi_bidi_cmnd(sc)) { | ||
197 | struct scsi_data_buffer *sdb = scsi_in(sc); | ||
198 | |||
199 | sgl_bidi = sdb->table.sgl; | ||
200 | sgl_bidi_count = sdb->table.nents; | ||
201 | se_cmd->se_cmd_flags |= SCF_BIDI; | ||
202 | |||
203 | } | ||
204 | |||
205 | if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) { | ||
206 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
207 | set_host_byte(sc, DID_NO_CONNECT); | ||
208 | goto out_done; | ||
209 | } | ||
210 | |||
297 | /* | 211 | /* |
298 | * Determine the SAM Task Attribute and allocate tl_cmd and | 212 | * Because some userspace code via scsi-generic do not memset their |
299 | * tl_cmd->tl_se_cmd from TCM infrastructure | 213 | * associated read buffers, go ahead and do that here for type |
214 | * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently | ||
215 | * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB | ||
216 | * by target core in transport_generic_allocate_tasks() -> | ||
217 | * transport_generic_cmd_sequencer(). | ||
300 | */ | 218 | */ |
301 | se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc); | 219 | if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && |
302 | if (!se_cmd) { | 220 | se_cmd->data_direction == DMA_FROM_DEVICE) { |
221 | struct scatterlist *sg = scsi_sglist(sc); | ||
222 | unsigned char *buf = kmap(sg_page(sg)) + sg->offset; | ||
223 | |||
224 | if (buf != NULL) { | ||
225 | memset(buf, 0, sg->length); | ||
226 | kunmap(sg_page(sg)); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd); | ||
231 | if (ret == -ENOMEM) { | ||
232 | transport_send_check_condition_and_sense(se_cmd, | ||
233 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); | ||
234 | transport_generic_free_cmd(se_cmd, 0); | ||
235 | return; | ||
236 | } else if (ret < 0) { | ||
237 | if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) | ||
238 | tcm_loop_queue_status(se_cmd); | ||
239 | else | ||
240 | transport_send_check_condition_and_sense(se_cmd, | ||
241 | se_cmd->scsi_sense_reason, 0); | ||
242 | transport_generic_free_cmd(se_cmd, 0); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), | ||
247 | scsi_sg_count(sc), sgl_bidi, sgl_bidi_count); | ||
248 | if (ret) { | ||
249 | transport_send_check_condition_and_sense(se_cmd, | ||
250 | se_cmd->scsi_sense_reason, 0); | ||
251 | transport_generic_free_cmd(se_cmd, 0); | ||
252 | return; | ||
253 | } | ||
254 | transport_handle_cdb_direct(se_cmd); | ||
255 | return; | ||
256 | |||
257 | out_done: | ||
258 | sc->scsi_done(sc); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * ->queuecommand can be and usually is called from interrupt context, so | ||
264 | * defer the actual submission to a workqueue. | ||
265 | */ | ||
266 | static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) | ||
267 | { | ||
268 | struct tcm_loop_cmd *tl_cmd; | ||
269 | |||
270 | pr_debug("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x" | ||
271 | " scsi_buf_len: %u\n", sc->device->host->host_no, | ||
272 | sc->device->id, sc->device->channel, sc->device->lun, | ||
273 | sc->cmnd[0], scsi_bufflen(sc)); | ||
274 | |||
275 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); | ||
276 | if (!tl_cmd) { | ||
277 | pr_err("Unable to allocate struct tcm_loop_cmd\n"); | ||
278 | set_host_byte(sc, DID_ERROR); | ||
303 | sc->scsi_done(sc); | 279 | sc->scsi_done(sc); |
304 | return 0; | 280 | return 0; |
305 | } | 281 | } |
306 | /* | 282 | |
307 | * Queue up the newly allocated to be processed in TCM thread context. | 283 | tl_cmd->sc = sc; |
308 | */ | 284 | INIT_WORK(&tl_cmd->work, tcm_loop_submission_work); |
309 | transport_generic_handle_cdb_map(se_cmd); | 285 | queue_work(tcm_loop_workqueue, &tl_cmd->work); |
310 | return 0; | 286 | return 0; |
311 | } | 287 | } |
312 | 288 | ||
@@ -324,7 +300,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) | |||
324 | struct tcm_loop_nexus *tl_nexus; | 300 | struct tcm_loop_nexus *tl_nexus; |
325 | struct tcm_loop_tmr *tl_tmr = NULL; | 301 | struct tcm_loop_tmr *tl_tmr = NULL; |
326 | struct tcm_loop_tpg *tl_tpg; | 302 | struct tcm_loop_tpg *tl_tpg; |
327 | int ret = FAILED; | 303 | int ret = FAILED, rc; |
328 | /* | 304 | /* |
329 | * Locate the tcm_loop_hba_t pointer | 305 | * Locate the tcm_loop_hba_t pointer |
330 | */ | 306 | */ |
@@ -365,12 +341,9 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) | |||
365 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, | 341 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, |
366 | DMA_NONE, MSG_SIMPLE_TAG, | 342 | DMA_NONE, MSG_SIMPLE_TAG, |
367 | &tl_cmd->tl_sense_buf[0]); | 343 | &tl_cmd->tl_sense_buf[0]); |
368 | /* | 344 | |
369 | * Allocate the LUN_RESET TMR | 345 | rc = core_tmr_alloc_req(se_cmd, tl_tmr, TMR_LUN_RESET, GFP_KERNEL); |
370 | */ | 346 | if (rc < 0) |
371 | se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr, | ||
372 | TMR_LUN_RESET, GFP_KERNEL); | ||
373 | if (IS_ERR(se_cmd->se_tmr_req)) | ||
374 | goto release; | 347 | goto release; |
375 | /* | 348 | /* |
376 | * Locate the underlying TCM struct se_lun from sc->device->lun | 349 | * Locate the underlying TCM struct se_lun from sc->device->lun |
@@ -762,22 +735,6 @@ static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) | |||
762 | return 1; | 735 | return 1; |
763 | } | 736 | } |
764 | 737 | ||
765 | static int tcm_loop_is_state_remove(struct se_cmd *se_cmd) | ||
766 | { | ||
767 | /* | ||
768 | * Assume struct scsi_cmnd is not in remove state.. | ||
769 | */ | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int tcm_loop_sess_logged_in(struct se_session *se_sess) | ||
774 | { | ||
775 | /* | ||
776 | * Assume that TL Nexus is always active | ||
777 | */ | ||
778 | return 1; | ||
779 | } | ||
780 | |||
781 | static u32 tcm_loop_sess_get_index(struct se_session *se_sess) | 738 | static u32 tcm_loop_sess_get_index(struct se_session *se_sess) |
782 | { | 739 | { |
783 | return 1; | 740 | return 1; |
@@ -811,19 +768,6 @@ static void tcm_loop_close_session(struct se_session *se_sess) | |||
811 | return; | 768 | return; |
812 | }; | 769 | }; |
813 | 770 | ||
814 | static void tcm_loop_stop_session( | ||
815 | struct se_session *se_sess, | ||
816 | int sess_sleep, | ||
817 | int conn_sleep) | ||
818 | { | ||
819 | return; | ||
820 | } | ||
821 | |||
822 | static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess) | ||
823 | { | ||
824 | return; | ||
825 | } | ||
826 | |||
827 | static int tcm_loop_write_pending(struct se_cmd *se_cmd) | 771 | static int tcm_loop_write_pending(struct se_cmd *se_cmd) |
828 | { | 772 | { |
829 | /* | 773 | /* |
@@ -855,6 +799,9 @@ static int tcm_loop_queue_data_in(struct se_cmd *se_cmd) | |||
855 | 799 | ||
856 | sc->result = SAM_STAT_GOOD; | 800 | sc->result = SAM_STAT_GOOD; |
857 | set_host_byte(sc, DID_OK); | 801 | set_host_byte(sc, DID_OK); |
802 | if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) || | ||
803 | (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)) | ||
804 | scsi_set_resid(sc, se_cmd->residual_count); | ||
858 | sc->scsi_done(sc); | 805 | sc->scsi_done(sc); |
859 | return 0; | 806 | return 0; |
860 | } | 807 | } |
@@ -880,6 +827,9 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd) | |||
880 | sc->result = se_cmd->scsi_status; | 827 | sc->result = se_cmd->scsi_status; |
881 | 828 | ||
882 | set_host_byte(sc, DID_OK); | 829 | set_host_byte(sc, DID_OK); |
830 | if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) || | ||
831 | (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)) | ||
832 | scsi_set_resid(sc, se_cmd->residual_count); | ||
883 | sc->scsi_done(sc); | 833 | sc->scsi_done(sc); |
884 | return 0; | 834 | return 0; |
885 | } | 835 | } |
@@ -1361,7 +1311,6 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = { | |||
1361 | static int tcm_loop_register_configfs(void) | 1311 | static int tcm_loop_register_configfs(void) |
1362 | { | 1312 | { |
1363 | struct target_fabric_configfs *fabric; | 1313 | struct target_fabric_configfs *fabric; |
1364 | struct config_group *tf_cg; | ||
1365 | int ret; | 1314 | int ret; |
1366 | /* | 1315 | /* |
1367 | * Set the TCM Loop HBA counter to zero | 1316 | * Set the TCM Loop HBA counter to zero |
@@ -1407,14 +1356,10 @@ static int tcm_loop_register_configfs(void) | |||
1407 | /* | 1356 | /* |
1408 | * Used for setting up remaining TCM resources in process context | 1357 | * Used for setting up remaining TCM resources in process context |
1409 | */ | 1358 | */ |
1410 | fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map; | ||
1411 | fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; | 1359 | fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; |
1412 | fabric->tf_ops.release_cmd = &tcm_loop_release_cmd; | 1360 | fabric->tf_ops.release_cmd = &tcm_loop_release_cmd; |
1413 | fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; | 1361 | fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; |
1414 | fabric->tf_ops.close_session = &tcm_loop_close_session; | 1362 | fabric->tf_ops.close_session = &tcm_loop_close_session; |
1415 | fabric->tf_ops.stop_session = &tcm_loop_stop_session; | ||
1416 | fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0; | ||
1417 | fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in; | ||
1418 | fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; | 1363 | fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; |
1419 | fabric->tf_ops.sess_get_initiator_sid = NULL; | 1364 | fabric->tf_ops.sess_get_initiator_sid = NULL; |
1420 | fabric->tf_ops.write_pending = &tcm_loop_write_pending; | 1365 | fabric->tf_ops.write_pending = &tcm_loop_write_pending; |
@@ -1431,9 +1376,7 @@ static int tcm_loop_register_configfs(void) | |||
1431 | fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; | 1376 | fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; |
1432 | fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len; | 1377 | fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len; |
1433 | fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len; | 1378 | fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len; |
1434 | fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove; | ||
1435 | 1379 | ||
1436 | tf_cg = &fabric->tf_group; | ||
1437 | /* | 1380 | /* |
1438 | * Setup function pointers for generic logic in target_core_fabric_configfs.c | 1381 | * Setup function pointers for generic logic in target_core_fabric_configfs.c |
1439 | */ | 1382 | */ |
@@ -1490,7 +1433,11 @@ static void tcm_loop_deregister_configfs(void) | |||
1490 | 1433 | ||
1491 | static int __init tcm_loop_fabric_init(void) | 1434 | static int __init tcm_loop_fabric_init(void) |
1492 | { | 1435 | { |
1493 | int ret; | 1436 | int ret = -ENOMEM; |
1437 | |||
1438 | tcm_loop_workqueue = alloc_workqueue("tcm_loop", 0, 0); | ||
1439 | if (!tcm_loop_workqueue) | ||
1440 | goto out; | ||
1494 | 1441 | ||
1495 | tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache", | 1442 | tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache", |
1496 | sizeof(struct tcm_loop_cmd), | 1443 | sizeof(struct tcm_loop_cmd), |
@@ -1499,20 +1446,27 @@ static int __init tcm_loop_fabric_init(void) | |||
1499 | if (!tcm_loop_cmd_cache) { | 1446 | if (!tcm_loop_cmd_cache) { |
1500 | pr_debug("kmem_cache_create() for" | 1447 | pr_debug("kmem_cache_create() for" |
1501 | " tcm_loop_cmd_cache failed\n"); | 1448 | " tcm_loop_cmd_cache failed\n"); |
1502 | return -ENOMEM; | 1449 | goto out_destroy_workqueue; |
1503 | } | 1450 | } |
1504 | 1451 | ||
1505 | ret = tcm_loop_alloc_core_bus(); | 1452 | ret = tcm_loop_alloc_core_bus(); |
1506 | if (ret) | 1453 | if (ret) |
1507 | return ret; | 1454 | goto out_destroy_cache; |
1508 | 1455 | ||
1509 | ret = tcm_loop_register_configfs(); | 1456 | ret = tcm_loop_register_configfs(); |
1510 | if (ret) { | 1457 | if (ret) |
1511 | tcm_loop_release_core_bus(); | 1458 | goto out_release_core_bus; |
1512 | return ret; | ||
1513 | } | ||
1514 | 1459 | ||
1515 | return 0; | 1460 | return 0; |
1461 | |||
1462 | out_release_core_bus: | ||
1463 | tcm_loop_release_core_bus(); | ||
1464 | out_destroy_cache: | ||
1465 | kmem_cache_destroy(tcm_loop_cmd_cache); | ||
1466 | out_destroy_workqueue: | ||
1467 | destroy_workqueue(tcm_loop_workqueue); | ||
1468 | out: | ||
1469 | return ret; | ||
1516 | } | 1470 | } |
1517 | 1471 | ||
1518 | static void __exit tcm_loop_fabric_exit(void) | 1472 | static void __exit tcm_loop_fabric_exit(void) |
@@ -1520,6 +1474,7 @@ static void __exit tcm_loop_fabric_exit(void) | |||
1520 | tcm_loop_deregister_configfs(); | 1474 | tcm_loop_deregister_configfs(); |
1521 | tcm_loop_release_core_bus(); | 1475 | tcm_loop_release_core_bus(); |
1522 | kmem_cache_destroy(tcm_loop_cmd_cache); | 1476 | kmem_cache_destroy(tcm_loop_cmd_cache); |
1477 | destroy_workqueue(tcm_loop_workqueue); | ||
1523 | } | 1478 | } |
1524 | 1479 | ||
1525 | MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module"); | 1480 | MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module"); |
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 15a036441471..7b54893db665 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | #define TCM_LOOP_VERSION "v2.1-rc1" | 1 | #define TCM_LOOP_VERSION "v2.1-rc2" |
2 | #define TL_WWN_ADDR_LEN 256 | 2 | #define TL_WWN_ADDR_LEN 256 |
3 | #define TL_TPGS_PER_HBA 32 | 3 | #define TL_TPGS_PER_HBA 32 |
4 | 4 | ||
@@ -12,9 +12,9 @@ struct tcm_loop_cmd { | |||
12 | u32 sc_cmd_state; | 12 | u32 sc_cmd_state; |
13 | /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ | 13 | /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ |
14 | struct scsi_cmnd *sc; | 14 | struct scsi_cmnd *sc; |
15 | struct list_head *tl_cmd_list; | ||
16 | /* The TCM I/O descriptor that is accessed via container_of() */ | 15 | /* The TCM I/O descriptor that is accessed via container_of() */ |
17 | struct se_cmd tl_se_cmd; | 16 | struct se_cmd tl_se_cmd; |
17 | struct work_struct work; | ||
18 | /* Sense buffer that will be mapped into outgoing status */ | 18 | /* Sense buffer that will be mapped into outgoing status */ |
19 | unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; | 19 | unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; |
20 | }; | 20 | }; |