Commit | Line | Data |
---|---|---|
c8806b6c NM |
1 | /* |
2 | * Copyright 2014 Cisco Systems, Inc. All rights reserved. | |
3 | * | |
4 | * This program is free software; you may redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; version 2 of the License. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
15 | * SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <linux/errno.h> | |
19 | #include <linux/mempool.h> | |
20 | ||
21 | #include <scsi/scsi_tcq.h> | |
22 | ||
23 | #include "snic_disc.h" | |
24 | #include "snic.h" | |
25 | #include "snic_io.h" | |
26 | ||
27 | ||
28 | /* snic target types */ | |
29 | static const char * const snic_tgt_type_str[] = { | |
30 | [SNIC_TGT_DAS] = "DAS", | |
31 | [SNIC_TGT_SAN] = "SAN", | |
32 | }; | |
33 | ||
34 | static inline const char * | |
35 | snic_tgt_type_to_str(int typ) | |
36 | { | |
37 | return ((typ > SNIC_TGT_NONE && typ <= SNIC_TGT_SAN) ? | |
38 | snic_tgt_type_str[typ] : "Unknown"); | |
39 | } | |
40 | ||
41 | static const char * const snic_tgt_state_str[] = { | |
42 | [SNIC_TGT_STAT_INIT] = "INIT", | |
43 | [SNIC_TGT_STAT_ONLINE] = "ONLINE", | |
44 | [SNIC_TGT_STAT_OFFLINE] = "OFFLINE", | |
45 | [SNIC_TGT_STAT_DEL] = "DELETION IN PROGRESS", | |
46 | }; | |
47 | ||
48 | const char * | |
49 | snic_tgt_state_to_str(int state) | |
50 | { | |
51 | return ((state >= SNIC_TGT_STAT_INIT && state <= SNIC_TGT_STAT_DEL) ? | |
52 | snic_tgt_state_str[state] : "UNKNOWN"); | |
53 | } | |
54 | ||
55 | /* | |
56 | * Initiate report_tgt req desc | |
57 | */ | |
58 | static void | |
59 | snic_report_tgt_init(struct snic_host_req *req, u32 hid, u8 *buf, u32 len, | |
60 | dma_addr_t rsp_buf_pa, ulong ctx) | |
61 | { | |
62 | struct snic_sg_desc *sgd = NULL; | |
63 | ||
64 | ||
65 | snic_io_hdr_enc(&req->hdr, SNIC_REQ_REPORT_TGTS, 0, SCSI_NO_TAG, hid, | |
66 | 1, ctx); | |
67 | ||
68 | req->u.rpt_tgts.sg_cnt = cpu_to_le16(1); | |
69 | sgd = req_to_sgl(req); | |
70 | sgd[0].addr = cpu_to_le64(rsp_buf_pa); | |
71 | sgd[0].len = cpu_to_le32(len); | |
72 | sgd[0]._resvd = 0; | |
73 | req->u.rpt_tgts.sg_addr = cpu_to_le64((ulong)sgd); | |
74 | } | |
75 | ||
76 | /* | |
77 | * snic_queue_report_tgt_req: Queues report target request. | |
78 | */ | |
79 | static int | |
80 | snic_queue_report_tgt_req(struct snic *snic) | |
81 | { | |
82 | struct snic_req_info *rqi = NULL; | |
83 | u32 ntgts, buf_len = 0; | |
84 | u8 *buf = NULL; | |
85 | dma_addr_t pa = 0; | |
86 | int ret = 0; | |
87 | ||
88 | rqi = snic_req_init(snic, 1); | |
89 | if (!rqi) { | |
90 | ret = -ENOMEM; | |
91 | goto error; | |
92 | } | |
93 | ||
94 | if (snic->fwinfo.max_tgts) | |
95 | ntgts = min_t(u32, snic->fwinfo.max_tgts, snic->shost->max_id); | |
96 | else | |
97 | ntgts = snic->shost->max_id; | |
98 | ||
99 | /* Allocate Response Buffer */ | |
100 | SNIC_BUG_ON(ntgts == 0); | |
101 | buf_len = ntgts * sizeof(struct snic_tgt_id) + SNIC_SG_DESC_ALIGN; | |
102 | ||
103 | buf = kzalloc(buf_len, GFP_KERNEL|GFP_DMA); | |
104 | if (!buf) { | |
105 | snic_req_free(snic, rqi); | |
106 | SNIC_HOST_ERR(snic->shost, "Resp Buf Alloc Failed.\n"); | |
107 | ||
108 | ret = -ENOMEM; | |
109 | goto error; | |
110 | } | |
111 | ||
112 | SNIC_BUG_ON((((unsigned long)buf) % SNIC_SG_DESC_ALIGN) != 0); | |
113 | ||
cecfed31 CH |
114 | pa = dma_map_single(&snic->pdev->dev, buf, buf_len, DMA_FROM_DEVICE); |
115 | if (dma_mapping_error(&snic->pdev->dev, pa)) { | |
c8806b6c NM |
116 | SNIC_HOST_ERR(snic->shost, |
117 | "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n", | |
118 | buf); | |
2a6a20ea JT |
119 | kfree(buf); |
120 | snic_req_free(snic, rqi); | |
c8806b6c NM |
121 | ret = -EINVAL; |
122 | ||
123 | goto error; | |
124 | } | |
125 | ||
126 | ||
127 | SNIC_BUG_ON(pa == 0); | |
128 | rqi->sge_va = (ulong) buf; | |
129 | ||
130 | snic_report_tgt_init(rqi->req, | |
131 | snic->config.hid, | |
132 | buf, | |
133 | buf_len, | |
134 | pa, | |
135 | (ulong)rqi); | |
136 | ||
137 | snic_handle_untagged_req(snic, rqi); | |
138 | ||
139 | ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len); | |
140 | if (ret) { | |
cecfed31 CH |
141 | dma_unmap_single(&snic->pdev->dev, pa, buf_len, |
142 | DMA_FROM_DEVICE); | |
c8806b6c NM |
143 | kfree(buf); |
144 | rqi->sge_va = 0; | |
145 | snic_release_untagged_req(snic, rqi); | |
146 | SNIC_HOST_ERR(snic->shost, "Queuing Report Tgts Failed.\n"); | |
147 | ||
148 | goto error; | |
149 | } | |
150 | ||
151 | SNIC_DISC_DBG(snic->shost, "Report Targets Issued.\n"); | |
152 | ||
153 | return ret; | |
154 | ||
155 | error: | |
156 | SNIC_HOST_ERR(snic->shost, | |
157 | "Queuing Report Targets Failed, err = %d\n", | |
158 | ret); | |
159 | return ret; | |
160 | } /* end of snic_queue_report_tgt_req */ | |
161 | ||
162 | /* call into SML */ | |
163 | static void | |
164 | snic_scsi_scan_tgt(struct work_struct *work) | |
165 | { | |
166 | struct snic_tgt *tgt = container_of(work, struct snic_tgt, scan_work); | |
167 | struct Scsi_Host *shost = dev_to_shost(&tgt->dev); | |
168 | unsigned long flags; | |
169 | ||
170 | SNIC_HOST_INFO(shost, "Scanning Target id 0x%x\n", tgt->id); | |
171 | scsi_scan_target(&tgt->dev, | |
172 | tgt->channel, | |
173 | tgt->scsi_tgt_id, | |
174 | SCAN_WILD_CARD, | |
1d645088 | 175 | SCSI_SCAN_RESCAN); |
c8806b6c NM |
176 | |
177 | spin_lock_irqsave(shost->host_lock, flags); | |
178 | tgt->flags &= ~SNIC_TGT_SCAN_PENDING; | |
179 | spin_unlock_irqrestore(shost->host_lock, flags); | |
180 | } /* end of snic_scsi_scan_tgt */ | |
181 | ||
182 | /* | |
183 | * snic_tgt_lookup : | |
184 | */ | |
185 | static struct snic_tgt * | |
186 | snic_tgt_lookup(struct snic *snic, struct snic_tgt_id *tgtid) | |
187 | { | |
188 | struct list_head *cur, *nxt; | |
189 | struct snic_tgt *tgt = NULL; | |
190 | ||
191 | list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { | |
192 | tgt = list_entry(cur, struct snic_tgt, list); | |
193 | if (tgt->id == le32_to_cpu(tgtid->tgt_id)) | |
194 | return tgt; | |
195 | tgt = NULL; | |
196 | } | |
197 | ||
198 | return tgt; | |
199 | } /* end of snic_tgt_lookup */ | |
200 | ||
201 | /* | |
202 | * snic_tgt_dev_release : Called on dropping last ref for snic_tgt object | |
203 | */ | |
204 | void | |
205 | snic_tgt_dev_release(struct device *dev) | |
206 | { | |
207 | struct snic_tgt *tgt = dev_to_tgt(dev); | |
208 | ||
209 | SNIC_HOST_INFO(snic_tgt_to_shost(tgt), | |
210 | "Target Device ID %d (%s) Permanently Deleted.\n", | |
211 | tgt->id, | |
212 | dev_name(dev)); | |
213 | ||
214 | SNIC_BUG_ON(!list_empty(&tgt->list)); | |
215 | kfree(tgt); | |
216 | } | |
217 | ||
218 | /* | |
219 | * snic_tgt_del : work function to delete snic_tgt | |
220 | */ | |
221 | static void | |
222 | snic_tgt_del(struct work_struct *work) | |
223 | { | |
224 | struct snic_tgt *tgt = container_of(work, struct snic_tgt, del_work); | |
225 | struct Scsi_Host *shost = snic_tgt_to_shost(tgt); | |
226 | ||
227 | if (tgt->flags & SNIC_TGT_SCAN_PENDING) | |
228 | scsi_flush_work(shost); | |
229 | ||
230 | /* Block IOs on child devices, stops new IOs */ | |
231 | scsi_target_block(&tgt->dev); | |
232 | ||
233 | /* Cleanup IOs */ | |
234 | snic_tgt_scsi_abort_io(tgt); | |
235 | ||
236 | /* Unblock IOs now, to flush if there are any. */ | |
237 | scsi_target_unblock(&tgt->dev, SDEV_TRANSPORT_OFFLINE); | |
238 | ||
239 | /* Delete SCSI Target and sdevs */ | |
240 | scsi_remove_target(&tgt->dev); /* ?? */ | |
241 | device_del(&tgt->dev); | |
242 | put_device(&tgt->dev); | |
243 | } /* end of snic_tgt_del */ | |
244 | ||
245 | /* snic_tgt_create: checks for existence of snic_tgt, if it doesn't | |
246 | * it creates one. | |
247 | */ | |
248 | static struct snic_tgt * | |
249 | snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) | |
250 | { | |
251 | struct snic_tgt *tgt = NULL; | |
252 | unsigned long flags; | |
253 | int ret; | |
254 | ||
255 | tgt = snic_tgt_lookup(snic, tgtid); | |
256 | if (tgt) { | |
257 | /* update the information if required */ | |
258 | return tgt; | |
259 | } | |
260 | ||
261 | tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); | |
262 | if (!tgt) { | |
263 | SNIC_HOST_ERR(snic->shost, "Failure to allocate snic_tgt.\n"); | |
264 | ret = -ENOMEM; | |
265 | ||
266 | return tgt; | |
267 | } | |
268 | ||
269 | INIT_LIST_HEAD(&tgt->list); | |
270 | tgt->id = le32_to_cpu(tgtid->tgt_id); | |
271 | tgt->channel = 0; | |
272 | ||
273 | SNIC_BUG_ON(le16_to_cpu(tgtid->tgt_type) > SNIC_TGT_SAN); | |
274 | tgt->tdata.typ = le16_to_cpu(tgtid->tgt_type); | |
275 | ||
276 | /* | |
277 | * Plugging into SML Device Tree | |
278 | */ | |
279 | tgt->tdata.disc_id = 0; | |
280 | tgt->state = SNIC_TGT_STAT_INIT; | |
281 | device_initialize(&tgt->dev); | |
282 | tgt->dev.parent = get_device(&snic->shost->shost_gendev); | |
283 | tgt->dev.release = snic_tgt_dev_release; | |
284 | INIT_WORK(&tgt->scan_work, snic_scsi_scan_tgt); | |
285 | INIT_WORK(&tgt->del_work, snic_tgt_del); | |
286 | switch (tgt->tdata.typ) { | |
287 | case SNIC_TGT_DAS: | |
288 | dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", | |
289 | snic->shost->host_no, tgt->channel, tgt->id); | |
290 | break; | |
291 | ||
292 | case SNIC_TGT_SAN: | |
293 | dev_set_name(&tgt->dev, "snic_san_tgt:%d:%d-%d", | |
294 | snic->shost->host_no, tgt->channel, tgt->id); | |
295 | break; | |
296 | ||
297 | default: | |
298 | SNIC_HOST_INFO(snic->shost, "Target type Unknown Detected.\n"); | |
299 | dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", | |
300 | snic->shost->host_no, tgt->channel, tgt->id); | |
301 | break; | |
302 | } | |
303 | ||
304 | spin_lock_irqsave(snic->shost->host_lock, flags); | |
305 | list_add_tail(&tgt->list, &snic->disc.tgt_list); | |
306 | tgt->scsi_tgt_id = snic->disc.nxt_tgt_id++; | |
307 | tgt->state = SNIC_TGT_STAT_ONLINE; | |
308 | spin_unlock_irqrestore(snic->shost->host_lock, flags); | |
309 | ||
310 | SNIC_HOST_INFO(snic->shost, | |
311 | "Tgt %d, type = %s detected. Adding..\n", | |
312 | tgt->id, snic_tgt_type_to_str(tgt->tdata.typ)); | |
313 | ||
314 | ret = device_add(&tgt->dev); | |
315 | if (ret) { | |
316 | SNIC_HOST_ERR(snic->shost, | |
317 | "Snic Tgt: device_add, with err = %d\n", | |
318 | ret); | |
319 | ||
320 | put_device(&snic->shost->shost_gendev); | |
321 | kfree(tgt); | |
322 | tgt = NULL; | |
323 | ||
324 | return tgt; | |
325 | } | |
326 | ||
327 | SNIC_HOST_INFO(snic->shost, "Scanning %s.\n", dev_name(&tgt->dev)); | |
328 | ||
329 | scsi_queue_work(snic->shost, &tgt->scan_work); | |
330 | ||
331 | return tgt; | |
332 | } /* end of snic_tgt_create */ | |
333 | ||
334 | /* Handler for discovery */ | |
335 | void | |
336 | snic_handle_tgt_disc(struct work_struct *work) | |
337 | { | |
338 | struct snic *snic = container_of(work, struct snic, tgt_work); | |
339 | struct snic_tgt_id *tgtid = NULL; | |
340 | struct snic_tgt *tgt = NULL; | |
341 | unsigned long flags; | |
342 | int i; | |
343 | ||
344 | spin_lock_irqsave(&snic->snic_lock, flags); | |
345 | if (snic->in_remove) { | |
346 | spin_unlock_irqrestore(&snic->snic_lock, flags); | |
347 | kfree(snic->disc.rtgt_info); | |
348 | ||
349 | return; | |
350 | } | |
351 | spin_unlock_irqrestore(&snic->snic_lock, flags); | |
352 | ||
353 | mutex_lock(&snic->disc.mutex); | |
354 | /* Discover triggered during disc in progress */ | |
355 | if (snic->disc.req_cnt) { | |
356 | snic->disc.state = SNIC_DISC_DONE; | |
357 | snic->disc.req_cnt = 0; | |
358 | mutex_unlock(&snic->disc.mutex); | |
359 | kfree(snic->disc.rtgt_info); | |
360 | snic->disc.rtgt_info = NULL; | |
361 | ||
362 | SNIC_HOST_INFO(snic->shost, "tgt_disc: Discovery restart.\n"); | |
363 | /* Start Discovery Again */ | |
364 | snic_disc_start(snic); | |
365 | ||
366 | return; | |
367 | } | |
368 | ||
369 | tgtid = (struct snic_tgt_id *)snic->disc.rtgt_info; | |
370 | ||
371 | SNIC_BUG_ON(snic->disc.rtgt_cnt == 0 || tgtid == NULL); | |
372 | ||
373 | for (i = 0; i < snic->disc.rtgt_cnt; i++) { | |
374 | tgt = snic_tgt_create(snic, &tgtid[i]); | |
375 | if (!tgt) { | |
376 | int buf_sz = snic->disc.rtgt_cnt * sizeof(*tgtid); | |
377 | ||
378 | SNIC_HOST_ERR(snic->shost, "Failed to create tgt.\n"); | |
379 | snic_hex_dump("rpt_tgt_rsp", (char *)tgtid, buf_sz); | |
380 | break; | |
381 | } | |
382 | } | |
383 | ||
384 | snic->disc.rtgt_info = NULL; | |
385 | snic->disc.state = SNIC_DISC_DONE; | |
386 | mutex_unlock(&snic->disc.mutex); | |
387 | ||
388 | SNIC_HOST_INFO(snic->shost, "Discovery Completed.\n"); | |
389 | ||
390 | kfree(tgtid); | |
391 | } /* end of snic_handle_tgt_disc */ | |
392 | ||
393 | ||
394 | int | |
395 | snic_report_tgt_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) | |
396 | { | |
397 | ||
398 | u8 typ, cmpl_stat; | |
399 | u32 cmnd_id, hid, tgt_cnt = 0; | |
400 | ulong ctx; | |
401 | struct snic_req_info *rqi = NULL; | |
402 | struct snic_tgt_id *tgtid; | |
403 | int i, ret = 0; | |
404 | ||
405 | snic_io_hdr_dec(&fwreq->hdr, &typ, &cmpl_stat, &cmnd_id, &hid, &ctx); | |
406 | rqi = (struct snic_req_info *) ctx; | |
407 | tgtid = (struct snic_tgt_id *) rqi->sge_va; | |
408 | ||
409 | tgt_cnt = le32_to_cpu(fwreq->u.rpt_tgts_cmpl.tgt_cnt); | |
410 | if (tgt_cnt == 0) { | |
411 | SNIC_HOST_ERR(snic->shost, "No Targets Found on this host.\n"); | |
412 | ret = 1; | |
413 | ||
414 | goto end; | |
415 | } | |
416 | ||
417 | /* printing list of targets here */ | |
418 | SNIC_HOST_INFO(snic->shost, "Target Count = %d\n", tgt_cnt); | |
419 | ||
420 | SNIC_BUG_ON(tgt_cnt > snic->fwinfo.max_tgts); | |
421 | ||
422 | for (i = 0; i < tgt_cnt; i++) | |
423 | SNIC_HOST_INFO(snic->shost, | |
424 | "Tgt id = 0x%x\n", | |
425 | le32_to_cpu(tgtid[i].tgt_id)); | |
426 | ||
427 | /* | |
428 | * Queue work for further processing, | |
429 | * Response Buffer Memory is freed after creating targets | |
430 | */ | |
431 | snic->disc.rtgt_cnt = tgt_cnt; | |
432 | snic->disc.rtgt_info = (u8 *) tgtid; | |
433 | queue_work(snic_glob->event_q, &snic->tgt_work); | |
434 | ret = 0; | |
435 | ||
436 | end: | |
437 | /* Unmap Response Buffer */ | |
438 | snic_pci_unmap_rsp_buf(snic, rqi); | |
439 | if (ret) | |
440 | kfree(tgtid); | |
441 | ||
442 | rqi->sge_va = 0; | |
443 | snic_release_untagged_req(snic, rqi); | |
444 | ||
445 | return ret; | |
446 | } /* end of snic_report_tgt_cmpl_handler */ | |
447 | ||
448 | /* Discovery init fn */ | |
449 | void | |
450 | snic_disc_init(struct snic_disc *disc) | |
451 | { | |
452 | INIT_LIST_HEAD(&disc->tgt_list); | |
453 | mutex_init(&disc->mutex); | |
454 | disc->disc_id = 0; | |
455 | disc->nxt_tgt_id = 0; | |
456 | disc->state = SNIC_DISC_INIT; | |
457 | disc->req_cnt = 0; | |
458 | disc->rtgt_cnt = 0; | |
459 | disc->rtgt_info = NULL; | |
460 | disc->cb = NULL; | |
461 | } /* end of snic_disc_init */ | |
462 | ||
463 | /* Discovery, uninit fn */ | |
464 | void | |
465 | snic_disc_term(struct snic *snic) | |
466 | { | |
467 | struct snic_disc *disc = &snic->disc; | |
468 | ||
469 | mutex_lock(&disc->mutex); | |
470 | if (disc->req_cnt) { | |
471 | disc->req_cnt = 0; | |
472 | SNIC_SCSI_DBG(snic->shost, "Terminating Discovery.\n"); | |
473 | } | |
474 | mutex_unlock(&disc->mutex); | |
475 | } | |
476 | ||
477 | /* | |
478 | * snic_disc_start: Discovery Start ... | |
479 | */ | |
480 | int | |
481 | snic_disc_start(struct snic *snic) | |
482 | { | |
483 | struct snic_disc *disc = &snic->disc; | |
58fcf920 | 484 | unsigned long flags; |
c8806b6c NM |
485 | int ret = 0; |
486 | ||
487 | SNIC_SCSI_DBG(snic->shost, "Discovery Start.\n"); | |
488 | ||
58fcf920 NM |
489 | spin_lock_irqsave(&snic->snic_lock, flags); |
490 | if (snic->in_remove) { | |
491 | spin_unlock_irqrestore(&snic->snic_lock, flags); | |
492 | SNIC_ERR("snic driver removal in progress ...\n"); | |
493 | ret = 0; | |
494 | ||
495 | return ret; | |
496 | } | |
497 | spin_unlock_irqrestore(&snic->snic_lock, flags); | |
498 | ||
c8806b6c NM |
499 | mutex_lock(&disc->mutex); |
500 | if (disc->state == SNIC_DISC_PENDING) { | |
501 | disc->req_cnt++; | |
502 | mutex_unlock(&disc->mutex); | |
503 | ||
504 | return ret; | |
505 | } | |
506 | disc->state = SNIC_DISC_PENDING; | |
507 | mutex_unlock(&disc->mutex); | |
508 | ||
509 | ret = snic_queue_report_tgt_req(snic); | |
510 | if (ret) | |
511 | SNIC_HOST_INFO(snic->shost, "Discovery Failed, err=%d.\n", ret); | |
512 | ||
513 | return ret; | |
514 | } /* end of snic_disc_start */ | |
515 | ||
516 | /* | |
517 | * snic_disc_work : | |
518 | */ | |
519 | void | |
520 | snic_handle_disc(struct work_struct *work) | |
521 | { | |
522 | struct snic *snic = container_of(work, struct snic, disc_work); | |
523 | int ret = 0; | |
524 | ||
525 | SNIC_HOST_INFO(snic->shost, "disc_work: Discovery\n"); | |
526 | ||
527 | ret = snic_disc_start(snic); | |
528 | if (ret) | |
529 | goto disc_err; | |
530 | ||
531 | disc_err: | |
532 | SNIC_HOST_ERR(snic->shost, | |
533 | "disc_work: Discovery Failed w/ err = %d\n", | |
534 | ret); | |
535 | } /* end of snic_disc_work */ | |
536 | ||
537 | /* | |
538 | * snic_tgt_del_all : cleanup all snic targets | |
539 | * Called on unbinding the interface | |
540 | */ | |
541 | void | |
542 | snic_tgt_del_all(struct snic *snic) | |
543 | { | |
544 | struct snic_tgt *tgt = NULL; | |
545 | struct list_head *cur, *nxt; | |
546 | unsigned long flags; | |
547 | ||
58fcf920 NM |
548 | scsi_flush_work(snic->shost); |
549 | ||
c8806b6c NM |
550 | mutex_lock(&snic->disc.mutex); |
551 | spin_lock_irqsave(snic->shost->host_lock, flags); | |
552 | ||
553 | list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { | |
554 | tgt = list_entry(cur, struct snic_tgt, list); | |
555 | tgt->state = SNIC_TGT_STAT_DEL; | |
556 | list_del_init(&tgt->list); | |
557 | SNIC_HOST_INFO(snic->shost, "Tgt %d q'ing for del\n", tgt->id); | |
558 | queue_work(snic_glob->event_q, &tgt->del_work); | |
559 | tgt = NULL; | |
560 | } | |
561 | spin_unlock_irqrestore(snic->shost->host_lock, flags); | |
c8806b6c | 562 | mutex_unlock(&snic->disc.mutex); |
58fcf920 NM |
563 | |
564 | flush_workqueue(snic_glob->event_q); | |
c8806b6c | 565 | } /* end of snic_tgt_del_all */ |