diff options
author | Narsimhulu Musini <nmusini@cisco.com> | 2015-05-29 04:04:01 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Odin.com> | 2015-06-19 19:57:51 -0400 |
commit | c8806b6c9e824f47726f2a9b7fbbe7ebf19306fa (patch) | |
tree | 3bad521e56f6d4d2c5db184b2cce213593667acc /drivers/scsi/snic/snic_disc.c | |
parent | 8d2b21db49f1b8bfc882586932bdb3f707420b43 (diff) |
snic: driver for Cisco SCSI HBA
Cisco has developed a new PCI HBA interface called sNIC, which stands for
SCSI NIC. This is a new storage feature supported on specialized network
adapter. The new PCI function provides a uniform host interface and abstracts
backend storage.
[jejb: fix up checkpatch errors]
Signed-off-by: Narsimhulu Musini <nmusini@cisco.com>
Signed-off-by: Sesidhar Baddela <sebaddel@cisco.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
Diffstat (limited to 'drivers/scsi/snic/snic_disc.c')
-rw-r--r-- | drivers/scsi/snic/snic_disc.c | 551 |
1 files changed, 551 insertions, 0 deletions
diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c new file mode 100644 index 000000000000..5f6321759ad9 --- /dev/null +++ b/drivers/scsi/snic/snic_disc.c | |||
@@ -0,0 +1,551 @@ | |||
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 | |||
114 | pa = pci_map_single(snic->pdev, buf, buf_len, PCI_DMA_FROMDEVICE); | ||
115 | if (pci_dma_mapping_error(snic->pdev, pa)) { | ||
116 | kfree(buf); | ||
117 | snic_req_free(snic, rqi); | ||
118 | SNIC_HOST_ERR(snic->shost, | ||
119 | "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n", | ||
120 | buf); | ||
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) { | ||
141 | pci_unmap_single(snic->pdev, pa, buf_len, PCI_DMA_FROMDEVICE); | ||
142 | kfree(buf); | ||
143 | rqi->sge_va = 0; | ||
144 | snic_release_untagged_req(snic, rqi); | ||
145 | SNIC_HOST_ERR(snic->shost, "Queuing Report Tgts Failed.\n"); | ||
146 | |||
147 | goto error; | ||
148 | } | ||
149 | |||
150 | SNIC_DISC_DBG(snic->shost, "Report Targets Issued.\n"); | ||
151 | |||
152 | return ret; | ||
153 | |||
154 | error: | ||
155 | SNIC_HOST_ERR(snic->shost, | ||
156 | "Queuing Report Targets Failed, err = %d\n", | ||
157 | ret); | ||
158 | return ret; | ||
159 | } /* end of snic_queue_report_tgt_req */ | ||
160 | |||
161 | /* call into SML */ | ||
162 | static void | ||
163 | snic_scsi_scan_tgt(struct work_struct *work) | ||
164 | { | ||
165 | struct snic_tgt *tgt = container_of(work, struct snic_tgt, scan_work); | ||
166 | struct Scsi_Host *shost = dev_to_shost(&tgt->dev); | ||
167 | unsigned long flags; | ||
168 | |||
169 | SNIC_HOST_INFO(shost, "Scanning Target id 0x%x\n", tgt->id); | ||
170 | scsi_scan_target(&tgt->dev, | ||
171 | tgt->channel, | ||
172 | tgt->scsi_tgt_id, | ||
173 | SCAN_WILD_CARD, | ||
174 | 1); | ||
175 | |||
176 | spin_lock_irqsave(shost->host_lock, flags); | ||
177 | tgt->flags &= ~SNIC_TGT_SCAN_PENDING; | ||
178 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
179 | } /* end of snic_scsi_scan_tgt */ | ||
180 | |||
181 | /* | ||
182 | * snic_tgt_lookup : | ||
183 | */ | ||
184 | static struct snic_tgt * | ||
185 | snic_tgt_lookup(struct snic *snic, struct snic_tgt_id *tgtid) | ||
186 | { | ||
187 | struct list_head *cur, *nxt; | ||
188 | struct snic_tgt *tgt = NULL; | ||
189 | |||
190 | list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { | ||
191 | tgt = list_entry(cur, struct snic_tgt, list); | ||
192 | if (tgt->id == le32_to_cpu(tgtid->tgt_id)) | ||
193 | return tgt; | ||
194 | tgt = NULL; | ||
195 | } | ||
196 | |||
197 | return tgt; | ||
198 | } /* end of snic_tgt_lookup */ | ||
199 | |||
200 | /* | ||
201 | * snic_tgt_dev_release : Called on dropping last ref for snic_tgt object | ||
202 | */ | ||
203 | void | ||
204 | snic_tgt_dev_release(struct device *dev) | ||
205 | { | ||
206 | struct snic_tgt *tgt = dev_to_tgt(dev); | ||
207 | |||
208 | SNIC_HOST_INFO(snic_tgt_to_shost(tgt), | ||
209 | "Target Device ID %d (%s) Permanently Deleted.\n", | ||
210 | tgt->id, | ||
211 | dev_name(dev)); | ||
212 | |||
213 | SNIC_BUG_ON(!list_empty(&tgt->list)); | ||
214 | kfree(tgt); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * snic_tgt_del : work function to delete snic_tgt | ||
219 | */ | ||
220 | static void | ||
221 | snic_tgt_del(struct work_struct *work) | ||
222 | { | ||
223 | struct snic_tgt *tgt = container_of(work, struct snic_tgt, del_work); | ||
224 | struct Scsi_Host *shost = snic_tgt_to_shost(tgt); | ||
225 | |||
226 | if (tgt->flags & SNIC_TGT_SCAN_PENDING) | ||
227 | scsi_flush_work(shost); | ||
228 | |||
229 | /* Block IOs on child devices, stops new IOs */ | ||
230 | scsi_target_block(&tgt->dev); | ||
231 | |||
232 | /* Cleanup IOs */ | ||
233 | snic_tgt_scsi_abort_io(tgt); | ||
234 | |||
235 | /* Unblock IOs now, to flush if there are any. */ | ||
236 | scsi_target_unblock(&tgt->dev, SDEV_TRANSPORT_OFFLINE); | ||
237 | |||
238 | /* Delete SCSI Target and sdevs */ | ||
239 | scsi_remove_target(&tgt->dev); /* ?? */ | ||
240 | device_del(&tgt->dev); | ||
241 | put_device(&tgt->dev); | ||
242 | } /* end of snic_tgt_del */ | ||
243 | |||
244 | /* snic_tgt_create: checks for existence of snic_tgt, if it doesn't | ||
245 | * it creates one. | ||
246 | */ | ||
247 | static struct snic_tgt * | ||
248 | snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid) | ||
249 | { | ||
250 | struct snic_tgt *tgt = NULL; | ||
251 | unsigned long flags; | ||
252 | int ret; | ||
253 | |||
254 | tgt = snic_tgt_lookup(snic, tgtid); | ||
255 | if (tgt) { | ||
256 | /* update the information if required */ | ||
257 | return tgt; | ||
258 | } | ||
259 | |||
260 | tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); | ||
261 | if (!tgt) { | ||
262 | SNIC_HOST_ERR(snic->shost, "Failure to allocate snic_tgt.\n"); | ||
263 | ret = -ENOMEM; | ||
264 | |||
265 | return tgt; | ||
266 | } | ||
267 | |||
268 | INIT_LIST_HEAD(&tgt->list); | ||
269 | tgt->id = le32_to_cpu(tgtid->tgt_id); | ||
270 | tgt->channel = 0; | ||
271 | |||
272 | SNIC_BUG_ON(le16_to_cpu(tgtid->tgt_type) > SNIC_TGT_SAN); | ||
273 | tgt->tdata.typ = le16_to_cpu(tgtid->tgt_type); | ||
274 | |||
275 | /* | ||
276 | * Plugging into SML Device Tree | ||
277 | */ | ||
278 | tgt->tdata.disc_id = 0; | ||
279 | tgt->state = SNIC_TGT_STAT_INIT; | ||
280 | device_initialize(&tgt->dev); | ||
281 | tgt->dev.parent = get_device(&snic->shost->shost_gendev); | ||
282 | tgt->dev.release = snic_tgt_dev_release; | ||
283 | INIT_WORK(&tgt->scan_work, snic_scsi_scan_tgt); | ||
284 | INIT_WORK(&tgt->del_work, snic_tgt_del); | ||
285 | switch (tgt->tdata.typ) { | ||
286 | case SNIC_TGT_DAS: | ||
287 | dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", | ||
288 | snic->shost->host_no, tgt->channel, tgt->id); | ||
289 | break; | ||
290 | |||
291 | case SNIC_TGT_SAN: | ||
292 | dev_set_name(&tgt->dev, "snic_san_tgt:%d:%d-%d", | ||
293 | snic->shost->host_no, tgt->channel, tgt->id); | ||
294 | break; | ||
295 | |||
296 | default: | ||
297 | SNIC_HOST_INFO(snic->shost, "Target type Unknown Detected.\n"); | ||
298 | dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d", | ||
299 | snic->shost->host_no, tgt->channel, tgt->id); | ||
300 | break; | ||
301 | } | ||
302 | |||
303 | spin_lock_irqsave(snic->shost->host_lock, flags); | ||
304 | list_add_tail(&tgt->list, &snic->disc.tgt_list); | ||
305 | tgt->scsi_tgt_id = snic->disc.nxt_tgt_id++; | ||
306 | tgt->state = SNIC_TGT_STAT_ONLINE; | ||
307 | spin_unlock_irqrestore(snic->shost->host_lock, flags); | ||
308 | |||
309 | SNIC_HOST_INFO(snic->shost, | ||
310 | "Tgt %d, type = %s detected. Adding..\n", | ||
311 | tgt->id, snic_tgt_type_to_str(tgt->tdata.typ)); | ||
312 | |||
313 | ret = device_add(&tgt->dev); | ||
314 | if (ret) { | ||
315 | SNIC_HOST_ERR(snic->shost, | ||
316 | "Snic Tgt: device_add, with err = %d\n", | ||
317 | ret); | ||
318 | |||
319 | put_device(&snic->shost->shost_gendev); | ||
320 | kfree(tgt); | ||
321 | tgt = NULL; | ||
322 | |||
323 | return tgt; | ||
324 | } | ||
325 | |||
326 | SNIC_HOST_INFO(snic->shost, "Scanning %s.\n", dev_name(&tgt->dev)); | ||
327 | |||
328 | scsi_queue_work(snic->shost, &tgt->scan_work); | ||
329 | |||
330 | return tgt; | ||
331 | } /* end of snic_tgt_create */ | ||
332 | |||
333 | /* Handler for discovery */ | ||
334 | void | ||
335 | snic_handle_tgt_disc(struct work_struct *work) | ||
336 | { | ||
337 | struct snic *snic = container_of(work, struct snic, tgt_work); | ||
338 | struct snic_tgt_id *tgtid = NULL; | ||
339 | struct snic_tgt *tgt = NULL; | ||
340 | unsigned long flags; | ||
341 | int i; | ||
342 | |||
343 | spin_lock_irqsave(&snic->snic_lock, flags); | ||
344 | if (snic->in_remove) { | ||
345 | spin_unlock_irqrestore(&snic->snic_lock, flags); | ||
346 | kfree(snic->disc.rtgt_info); | ||
347 | |||
348 | return; | ||
349 | } | ||
350 | spin_unlock_irqrestore(&snic->snic_lock, flags); | ||
351 | |||
352 | mutex_lock(&snic->disc.mutex); | ||
353 | /* Discover triggered during disc in progress */ | ||
354 | if (snic->disc.req_cnt) { | ||
355 | snic->disc.state = SNIC_DISC_DONE; | ||
356 | snic->disc.req_cnt = 0; | ||
357 | mutex_unlock(&snic->disc.mutex); | ||
358 | kfree(snic->disc.rtgt_info); | ||
359 | snic->disc.rtgt_info = NULL; | ||
360 | |||
361 | SNIC_HOST_INFO(snic->shost, "tgt_disc: Discovery restart.\n"); | ||
362 | /* Start Discovery Again */ | ||
363 | snic_disc_start(snic); | ||
364 | |||
365 | return; | ||
366 | } | ||
367 | |||
368 | tgtid = (struct snic_tgt_id *)snic->disc.rtgt_info; | ||
369 | |||
370 | SNIC_BUG_ON(snic->disc.rtgt_cnt == 0 || tgtid == NULL); | ||
371 | |||
372 | for (i = 0; i < snic->disc.rtgt_cnt; i++) { | ||
373 | tgt = snic_tgt_create(snic, &tgtid[i]); | ||
374 | if (!tgt) { | ||
375 | int buf_sz = snic->disc.rtgt_cnt * sizeof(*tgtid); | ||
376 | |||
377 | SNIC_HOST_ERR(snic->shost, "Failed to create tgt.\n"); | ||
378 | snic_hex_dump("rpt_tgt_rsp", (char *)tgtid, buf_sz); | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | snic->disc.rtgt_info = NULL; | ||
384 | snic->disc.state = SNIC_DISC_DONE; | ||
385 | mutex_unlock(&snic->disc.mutex); | ||
386 | |||
387 | SNIC_HOST_INFO(snic->shost, "Discovery Completed.\n"); | ||
388 | |||
389 | kfree(tgtid); | ||
390 | } /* end of snic_handle_tgt_disc */ | ||
391 | |||
392 | |||
393 | int | ||
394 | snic_report_tgt_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq) | ||
395 | { | ||
396 | |||
397 | u8 typ, cmpl_stat; | ||
398 | u32 cmnd_id, hid, tgt_cnt = 0; | ||
399 | ulong ctx; | ||
400 | struct snic_req_info *rqi = NULL; | ||
401 | struct snic_tgt_id *tgtid; | ||
402 | int i, ret = 0; | ||
403 | |||
404 | snic_io_hdr_dec(&fwreq->hdr, &typ, &cmpl_stat, &cmnd_id, &hid, &ctx); | ||
405 | rqi = (struct snic_req_info *) ctx; | ||
406 | tgtid = (struct snic_tgt_id *) rqi->sge_va; | ||
407 | |||
408 | tgt_cnt = le32_to_cpu(fwreq->u.rpt_tgts_cmpl.tgt_cnt); | ||
409 | if (tgt_cnt == 0) { | ||
410 | SNIC_HOST_ERR(snic->shost, "No Targets Found on this host.\n"); | ||
411 | ret = 1; | ||
412 | |||
413 | goto end; | ||
414 | } | ||
415 | |||
416 | /* printing list of targets here */ | ||
417 | SNIC_HOST_INFO(snic->shost, "Target Count = %d\n", tgt_cnt); | ||
418 | |||
419 | SNIC_BUG_ON(tgt_cnt > snic->fwinfo.max_tgts); | ||
420 | |||
421 | for (i = 0; i < tgt_cnt; i++) | ||
422 | SNIC_HOST_INFO(snic->shost, | ||
423 | "Tgt id = 0x%x\n", | ||
424 | le32_to_cpu(tgtid[i].tgt_id)); | ||
425 | |||
426 | /* | ||
427 | * Queue work for further processing, | ||
428 | * Response Buffer Memory is freed after creating targets | ||
429 | */ | ||
430 | snic->disc.rtgt_cnt = tgt_cnt; | ||
431 | snic->disc.rtgt_info = (u8 *) tgtid; | ||
432 | queue_work(snic_glob->event_q, &snic->tgt_work); | ||
433 | ret = 0; | ||
434 | |||
435 | end: | ||
436 | /* Unmap Response Buffer */ | ||
437 | snic_pci_unmap_rsp_buf(snic, rqi); | ||
438 | if (ret) | ||
439 | kfree(tgtid); | ||
440 | |||
441 | rqi->sge_va = 0; | ||
442 | snic_release_untagged_req(snic, rqi); | ||
443 | |||
444 | return ret; | ||
445 | } /* end of snic_report_tgt_cmpl_handler */ | ||
446 | |||
447 | /* Discovery init fn */ | ||
448 | void | ||
449 | snic_disc_init(struct snic_disc *disc) | ||
450 | { | ||
451 | INIT_LIST_HEAD(&disc->tgt_list); | ||
452 | mutex_init(&disc->mutex); | ||
453 | disc->disc_id = 0; | ||
454 | disc->nxt_tgt_id = 0; | ||
455 | disc->state = SNIC_DISC_INIT; | ||
456 | disc->req_cnt = 0; | ||
457 | disc->rtgt_cnt = 0; | ||
458 | disc->rtgt_info = NULL; | ||
459 | disc->cb = NULL; | ||
460 | } /* end of snic_disc_init */ | ||
461 | |||
462 | /* Discovery, uninit fn */ | ||
463 | void | ||
464 | snic_disc_term(struct snic *snic) | ||
465 | { | ||
466 | struct snic_disc *disc = &snic->disc; | ||
467 | |||
468 | mutex_lock(&disc->mutex); | ||
469 | if (disc->req_cnt) { | ||
470 | disc->req_cnt = 0; | ||
471 | SNIC_SCSI_DBG(snic->shost, "Terminating Discovery.\n"); | ||
472 | } | ||
473 | mutex_unlock(&disc->mutex); | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * snic_disc_start: Discovery Start ... | ||
478 | */ | ||
479 | int | ||
480 | snic_disc_start(struct snic *snic) | ||
481 | { | ||
482 | struct snic_disc *disc = &snic->disc; | ||
483 | int ret = 0; | ||
484 | |||
485 | SNIC_SCSI_DBG(snic->shost, "Discovery Start.\n"); | ||
486 | |||
487 | mutex_lock(&disc->mutex); | ||
488 | if (disc->state == SNIC_DISC_PENDING) { | ||
489 | disc->req_cnt++; | ||
490 | mutex_unlock(&disc->mutex); | ||
491 | |||
492 | return ret; | ||
493 | } | ||
494 | disc->state = SNIC_DISC_PENDING; | ||
495 | mutex_unlock(&disc->mutex); | ||
496 | |||
497 | ret = snic_queue_report_tgt_req(snic); | ||
498 | if (ret) | ||
499 | SNIC_HOST_INFO(snic->shost, "Discovery Failed, err=%d.\n", ret); | ||
500 | |||
501 | return ret; | ||
502 | } /* end of snic_disc_start */ | ||
503 | |||
504 | /* | ||
505 | * snic_disc_work : | ||
506 | */ | ||
507 | void | ||
508 | snic_handle_disc(struct work_struct *work) | ||
509 | { | ||
510 | struct snic *snic = container_of(work, struct snic, disc_work); | ||
511 | int ret = 0; | ||
512 | |||
513 | SNIC_HOST_INFO(snic->shost, "disc_work: Discovery\n"); | ||
514 | |||
515 | ret = snic_disc_start(snic); | ||
516 | if (ret) | ||
517 | goto disc_err; | ||
518 | |||
519 | disc_err: | ||
520 | SNIC_HOST_ERR(snic->shost, | ||
521 | "disc_work: Discovery Failed w/ err = %d\n", | ||
522 | ret); | ||
523 | } /* end of snic_disc_work */ | ||
524 | |||
525 | /* | ||
526 | * snic_tgt_del_all : cleanup all snic targets | ||
527 | * Called on unbinding the interface | ||
528 | */ | ||
529 | void | ||
530 | snic_tgt_del_all(struct snic *snic) | ||
531 | { | ||
532 | struct snic_tgt *tgt = NULL; | ||
533 | struct list_head *cur, *nxt; | ||
534 | unsigned long flags; | ||
535 | |||
536 | mutex_lock(&snic->disc.mutex); | ||
537 | spin_lock_irqsave(snic->shost->host_lock, flags); | ||
538 | |||
539 | list_for_each_safe(cur, nxt, &snic->disc.tgt_list) { | ||
540 | tgt = list_entry(cur, struct snic_tgt, list); | ||
541 | tgt->state = SNIC_TGT_STAT_DEL; | ||
542 | list_del_init(&tgt->list); | ||
543 | SNIC_HOST_INFO(snic->shost, "Tgt %d q'ing for del\n", tgt->id); | ||
544 | queue_work(snic_glob->event_q, &tgt->del_work); | ||
545 | tgt = NULL; | ||
546 | } | ||
547 | spin_unlock_irqrestore(snic->shost->host_lock, flags); | ||
548 | |||
549 | scsi_flush_work(snic->shost); | ||
550 | mutex_unlock(&snic->disc.mutex); | ||
551 | } /* end of snic_tgt_del_all */ | ||