diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 01:56:22 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 01:56:22 -0400 |
commit | 6f231dda68080759f1aed3769896e94c73099f0f (patch) | |
tree | 45b6ce02fa40e0e9c35526ac6c45950138387516 /drivers/scsi/isci/remote_device.c | |
parent | 59c5f46fbe01a00eedf54a23789634438bb80603 (diff) |
isci: Intel(R) C600 Series Chipset Storage Control Unit Driver
Support for the up to 2x4-port 6Gb/s SAS controllers embedded in the
chipset.
This is a snapshot of the first publicly available version of the driver,
commit 4c1db2d0 in the 'historical' branch.
git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git historical
Signed-off-by: Maciej Trela <maciej.trela@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Edmund Nadolski <edmund.nadolski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 698 |
1 files changed, 698 insertions, 0 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c new file mode 100644 index 00000000000..dbf3c82f619 --- /dev/null +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -0,0 +1,698 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of version 2 of the GNU General Public License as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * BSD LICENSE | ||
25 | * | ||
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
27 | * All rights reserved. | ||
28 | * | ||
29 | * Redistribution and use in source and binary forms, with or without | ||
30 | * modification, are permitted provided that the following conditions | ||
31 | * are met: | ||
32 | * | ||
33 | * * Redistributions of source code must retain the above copyright | ||
34 | * notice, this list of conditions and the following disclaimer. | ||
35 | * * Redistributions in binary form must reproduce the above copyright | ||
36 | * notice, this list of conditions and the following disclaimer in | ||
37 | * the documentation and/or other materials provided with the | ||
38 | * distribution. | ||
39 | * * Neither the name of Intel Corporation nor the names of its | ||
40 | * contributors may be used to endorse or promote products derived | ||
41 | * from this software without specific prior written permission. | ||
42 | * | ||
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
54 | */ | ||
55 | |||
56 | #include "isci.h" | ||
57 | #include "scic_io_request.h" | ||
58 | #include "scic_remote_device.h" | ||
59 | #include "scic_phy.h" | ||
60 | #include "scic_port.h" | ||
61 | #include "port.h" | ||
62 | #include "remote_device.h" | ||
63 | #include "request.h" | ||
64 | #include "task.h" | ||
65 | |||
66 | |||
67 | |||
68 | /** | ||
69 | * isci_remote_device_deconstruct() - This function frees an isci_remote_device. | ||
70 | * @isci_host: This parameter specifies the isci host object. | ||
71 | * @isci_device: This parameter specifies the remote device to be freed. | ||
72 | * | ||
73 | */ | ||
74 | static void isci_remote_device_deconstruct( | ||
75 | struct isci_host *isci_host, | ||
76 | struct isci_remote_device *isci_device) | ||
77 | { | ||
78 | dev_dbg(&isci_host->pdev->dev, | ||
79 | "%s: isci_device = %p\n", __func__, isci_device); | ||
80 | |||
81 | /* There should not be any outstanding io's. All paths to | ||
82 | * here should go through isci_remote_device_nuke_requests. | ||
83 | * If we hit this condition, we will need a way to complete | ||
84 | * io requests in process */ | ||
85 | while (!list_empty(&isci_device->reqs_in_process)) { | ||
86 | |||
87 | dev_err(&isci_host->pdev->dev, | ||
88 | "%s: ** request list not empty! **\n", __func__); | ||
89 | BUG(); | ||
90 | } | ||
91 | |||
92 | /* Remove all related references to this device and free | ||
93 | * the cache object. | ||
94 | */ | ||
95 | scic_remote_device_destruct(isci_device->sci_device_handle); | ||
96 | isci_device->domain_dev->lldd_dev = NULL; | ||
97 | list_del(&isci_device->node); | ||
98 | kmem_cache_free(isci_kmem_cache, isci_device); | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * isci_remote_device_construct() - This function calls the scic remote device | ||
104 | * construct and start functions, it waits on the remote device start | ||
105 | * completion. | ||
106 | * @port: This parameter specifies the isci port with the remote device. | ||
107 | * @isci_device: This parameter specifies the isci remote device | ||
108 | * | ||
109 | * status from the scic calls, the caller to this function should clean up | ||
110 | * resources as appropriate. | ||
111 | */ | ||
112 | static enum sci_status isci_remote_device_construct( | ||
113 | struct isci_port *port, | ||
114 | struct isci_remote_device *isci_device) | ||
115 | { | ||
116 | enum sci_status status = SCI_SUCCESS; | ||
117 | |||
118 | /* let the core do it's common constuction. */ | ||
119 | scic_remote_device_construct(port->sci_port_handle, | ||
120 | isci_device->sci_device_handle); | ||
121 | |||
122 | /* let the core do it's device specific constuction. */ | ||
123 | if (isci_device->domain_dev->parent && | ||
124 | (isci_device->domain_dev->parent->dev_type == EDGE_DEV)) { | ||
125 | int i; | ||
126 | |||
127 | /* struct smp_response_discover discover_response; */ | ||
128 | struct discover_resp discover_response; | ||
129 | struct domain_device *parent = | ||
130 | isci_device->domain_dev->parent; | ||
131 | |||
132 | struct expander_device *parent_ex = &parent->ex_dev; | ||
133 | |||
134 | for (i = 0; i < parent_ex->num_phys; i++) { | ||
135 | |||
136 | struct ex_phy *phy = &parent_ex->ex_phy[i]; | ||
137 | |||
138 | if ((phy->phy_state == PHY_VACANT) || | ||
139 | (phy->phy_state == PHY_NOT_PRESENT)) | ||
140 | continue; | ||
141 | |||
142 | if (SAS_ADDR(phy->attached_sas_addr) | ||
143 | == SAS_ADDR(isci_device->domain_dev->sas_addr)) { | ||
144 | |||
145 | discover_response.attached_dev_type | ||
146 | = phy->attached_dev_type; | ||
147 | discover_response.linkrate | ||
148 | = phy->linkrate; | ||
149 | discover_response.attached_sata_host | ||
150 | = phy->attached_sata_host; | ||
151 | discover_response.attached_sata_dev | ||
152 | = phy->attached_sata_dev; | ||
153 | discover_response.attached_sata_ps | ||
154 | = phy->attached_sata_ps; | ||
155 | discover_response.iproto | ||
156 | = phy->attached_iproto >> 1; | ||
157 | discover_response.tproto | ||
158 | = phy->attached_tproto >> 1; | ||
159 | memcpy( | ||
160 | discover_response.attached_sas_addr, | ||
161 | phy->attached_sas_addr, | ||
162 | SAS_ADDR_SIZE | ||
163 | ); | ||
164 | discover_response.attached_phy_id | ||
165 | = phy->attached_phy_id; | ||
166 | discover_response.change_count | ||
167 | = phy->phy_change_count; | ||
168 | discover_response.routing_attr | ||
169 | = phy->routing_attr; | ||
170 | discover_response.hmin_linkrate | ||
171 | = phy->phy->minimum_linkrate_hw; | ||
172 | discover_response.hmax_linkrate | ||
173 | = phy->phy->maximum_linkrate_hw; | ||
174 | discover_response.pmin_linkrate | ||
175 | = phy->phy->minimum_linkrate; | ||
176 | discover_response.pmax_linkrate | ||
177 | = phy->phy->maximum_linkrate; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | |||
182 | dev_dbg(&port->isci_host->pdev->dev, | ||
183 | "%s: parent->dev_type = EDGE_DEV\n", | ||
184 | __func__); | ||
185 | |||
186 | status = scic_remote_device_ea_construct( | ||
187 | isci_device->sci_device_handle, | ||
188 | (struct smp_response_discover *)&discover_response | ||
189 | ); | ||
190 | |||
191 | } else | ||
192 | status = scic_remote_device_da_construct( | ||
193 | isci_device->sci_device_handle | ||
194 | ); | ||
195 | |||
196 | |||
197 | if (status != SCI_SUCCESS) { | ||
198 | dev_dbg(&port->isci_host->pdev->dev, | ||
199 | "%s: scic_remote_device_da_construct failed - " | ||
200 | "isci_device = %p\n", | ||
201 | __func__, | ||
202 | isci_device); | ||
203 | |||
204 | return status; | ||
205 | } | ||
206 | |||
207 | sci_object_set_association( | ||
208 | isci_device->sci_device_handle, | ||
209 | isci_device | ||
210 | ); | ||
211 | |||
212 | BUG_ON(port->isci_host == NULL); | ||
213 | |||
214 | /* start the device. */ | ||
215 | status = scic_remote_device_start( | ||
216 | isci_device->sci_device_handle, | ||
217 | ISCI_REMOTE_DEVICE_START_TIMEOUT | ||
218 | ); | ||
219 | |||
220 | if (status != SCI_SUCCESS) { | ||
221 | dev_warn(&port->isci_host->pdev->dev, | ||
222 | "%s: scic_remote_device_start failed\n", | ||
223 | __func__); | ||
224 | return status; | ||
225 | } | ||
226 | |||
227 | return status; | ||
228 | } | ||
229 | |||
230 | |||
231 | /** | ||
232 | * isci_remote_device_nuke_requests() - This function terminates all requests | ||
233 | * for a given remote device. | ||
234 | * @isci_device: This parameter specifies the remote device | ||
235 | * | ||
236 | */ | ||
237 | void isci_remote_device_nuke_requests( | ||
238 | struct isci_remote_device *isci_device) | ||
239 | { | ||
240 | DECLARE_COMPLETION_ONSTACK(aborted_task_completion); | ||
241 | struct isci_host *isci_host; | ||
242 | |||
243 | isci_host = isci_device->isci_port->isci_host; | ||
244 | |||
245 | dev_dbg(&isci_host->pdev->dev, | ||
246 | "%s: isci_device = %p\n", __func__, isci_device); | ||
247 | |||
248 | /* Cleanup all requests pending for this device. */ | ||
249 | isci_terminate_pending_requests(isci_host, isci_device, terminating); | ||
250 | |||
251 | dev_dbg(&isci_host->pdev->dev, | ||
252 | "%s: isci_device = %p, done\n", __func__, isci_device); | ||
253 | } | ||
254 | |||
255 | |||
256 | |||
257 | /** | ||
258 | * This function builds the isci_remote_device when a libsas dev_found message | ||
259 | * is received. | ||
260 | * @isci_host: This parameter specifies the isci host object. | ||
261 | * @port: This parameter specifies the isci_port conected to this device. | ||
262 | * | ||
263 | * pointer to new isci_remote_device. | ||
264 | */ | ||
265 | static struct isci_remote_device * | ||
266 | isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port) | ||
267 | { | ||
268 | struct isci_remote_device *isci_device; | ||
269 | struct scic_sds_remote_device *sci_dev; | ||
270 | |||
271 | isci_device = kmem_cache_zalloc(isci_kmem_cache, GFP_KERNEL); | ||
272 | |||
273 | if (!isci_device) { | ||
274 | dev_warn(&isci_host->pdev->dev, "%s: failed\n", __func__); | ||
275 | return NULL; | ||
276 | } | ||
277 | |||
278 | sci_dev = (struct scic_sds_remote_device *) &isci_device[1]; | ||
279 | isci_device->sci_device_handle = sci_dev; | ||
280 | INIT_LIST_HEAD(&isci_device->reqs_in_process); | ||
281 | INIT_LIST_HEAD(&isci_device->node); | ||
282 | isci_device->host_quiesce = false; | ||
283 | |||
284 | spin_lock_init(&isci_device->state_lock); | ||
285 | spin_lock_init(&isci_device->host_quiesce_lock); | ||
286 | isci_remote_device_change_state(isci_device, isci_freed); | ||
287 | |||
288 | return isci_device; | ||
289 | |||
290 | } | ||
291 | /** | ||
292 | * isci_device_set_host_quiesce_lock_state() - This function sets the host I/O | ||
293 | * quiesce lock state for the remote_device object. | ||
294 | * @isci_device,: This parameter points to the isci_remote_device object | ||
295 | * @isci_device: This parameter specifies the new quiesce state. | ||
296 | * | ||
297 | */ | ||
298 | void isci_device_set_host_quiesce_lock_state( | ||
299 | struct isci_remote_device *isci_device, | ||
300 | bool lock_state) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | |||
304 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
305 | "%s: isci_device=%p, lock_state=%d\n", | ||
306 | __func__, isci_device, lock_state); | ||
307 | |||
308 | spin_lock_irqsave(&isci_device->host_quiesce_lock, flags); | ||
309 | isci_device->host_quiesce = lock_state; | ||
310 | spin_unlock_irqrestore(&isci_device->host_quiesce_lock, flags); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * isci_remote_device_ready() - This function is called by the scic when the | ||
315 | * remote device is ready. We mark the isci device as ready and signal the | ||
316 | * waiting proccess. | ||
317 | * @isci_host: This parameter specifies the isci host object. | ||
318 | * @isci_device: This parameter specifies the remote device | ||
319 | * | ||
320 | */ | ||
321 | void isci_remote_device_ready(struct isci_remote_device *isci_device) | ||
322 | { | ||
323 | unsigned long flags; | ||
324 | |||
325 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
326 | "%s: isci_device = %p\n", __func__, isci_device); | ||
327 | |||
328 | /* device ready is actually a "ready for io" state. */ | ||
329 | if ((isci_starting == isci_remote_device_get_state(isci_device)) || | ||
330 | (isci_ready == isci_remote_device_get_state(isci_device))) { | ||
331 | spin_lock_irqsave(&isci_device->isci_port->remote_device_lock, | ||
332 | flags); | ||
333 | isci_remote_device_change_state(isci_device, isci_ready_for_io); | ||
334 | if (isci_device->completion) | ||
335 | complete(isci_device->completion); | ||
336 | spin_unlock_irqrestore( | ||
337 | &isci_device->isci_port->remote_device_lock, | ||
338 | flags); | ||
339 | } | ||
340 | |||
341 | } | ||
342 | |||
343 | /** | ||
344 | * isci_remote_device_not_ready() - This function is called by the scic when | ||
345 | * the remote device is not ready. We mark the isci device as ready (not | ||
346 | * "ready_for_io") and signal the waiting proccess. | ||
347 | * @isci_host: This parameter specifies the isci host object. | ||
348 | * @isci_device: This parameter specifies the remote device | ||
349 | * | ||
350 | */ | ||
351 | void isci_remote_device_not_ready( | ||
352 | struct isci_remote_device *isci_device, | ||
353 | u32 reason_code) | ||
354 | { | ||
355 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
356 | "%s: isci_device = %p\n", __func__, isci_device); | ||
357 | |||
358 | if (reason_code == SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED) | ||
359 | isci_remote_device_change_state(isci_device, isci_stopping); | ||
360 | else | ||
361 | /* device ready is actually a "not ready for io" state. */ | ||
362 | isci_remote_device_change_state(isci_device, isci_ready); | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * isci_remote_device_stop_complete() - This function is called by the scic | ||
367 | * when the remote device stop has completed. We mark the isci device as not | ||
368 | * ready and remove the isci remote device. | ||
369 | * @isci_host: This parameter specifies the isci host object. | ||
370 | * @isci_device: This parameter specifies the remote device. | ||
371 | * @status: This parameter specifies status of the completion. | ||
372 | * | ||
373 | */ | ||
374 | void isci_remote_device_stop_complete( | ||
375 | struct isci_host *isci_host, | ||
376 | struct isci_remote_device *isci_device, | ||
377 | enum sci_status status) | ||
378 | { | ||
379 | struct completion *completion = isci_device->completion; | ||
380 | |||
381 | dev_dbg(&isci_host->pdev->dev, | ||
382 | "%s: complete isci_device = %p, status = 0x%x\n", | ||
383 | __func__, | ||
384 | isci_device, | ||
385 | status); | ||
386 | |||
387 | isci_remote_device_change_state(isci_device, isci_stopped); | ||
388 | |||
389 | /* after stop, we can tear down resources. */ | ||
390 | isci_remote_device_deconstruct(isci_host, isci_device); | ||
391 | |||
392 | /* notify interested parties. */ | ||
393 | if (completion) | ||
394 | complete(completion); | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * isci_remote_device_start_complete() - This function is called by the scic | ||
399 | * when the remote device start has completed | ||
400 | * @isci_host: This parameter specifies the isci host object. | ||
401 | * @isci_device: This parameter specifies the remote device. | ||
402 | * @status: This parameter specifies status of the completion. | ||
403 | * | ||
404 | */ | ||
405 | void isci_remote_device_start_complete( | ||
406 | struct isci_host *isci_host, | ||
407 | struct isci_remote_device *isci_device, | ||
408 | enum sci_status status) | ||
409 | { | ||
410 | |||
411 | |||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * isci_remote_device_stop() - This function is called internally to stop the | ||
417 | * remote device. | ||
418 | * @isci_host: This parameter specifies the isci host object. | ||
419 | * @isci_device: This parameter specifies the remote device. | ||
420 | * | ||
421 | * The status of the scic request to stop. | ||
422 | */ | ||
423 | enum sci_status isci_remote_device_stop( | ||
424 | struct isci_remote_device *isci_device) | ||
425 | { | ||
426 | enum sci_status status; | ||
427 | unsigned long flags; | ||
428 | |||
429 | DECLARE_COMPLETION_ONSTACK(completion); | ||
430 | |||
431 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
432 | "%s: isci_device = %p\n", __func__, isci_device); | ||
433 | |||
434 | isci_remote_device_change_state(isci_device, isci_stopping); | ||
435 | |||
436 | /* We need comfirmation that stop completed. */ | ||
437 | isci_device->completion = &completion; | ||
438 | |||
439 | BUG_ON(isci_device->isci_port == NULL); | ||
440 | BUG_ON(isci_device->isci_port->isci_host == NULL); | ||
441 | |||
442 | spin_lock_irqsave(&isci_device->isci_port->isci_host->scic_lock, flags); | ||
443 | |||
444 | status = scic_remote_device_stop( | ||
445 | isci_device->sci_device_handle, | ||
446 | 50 | ||
447 | ); | ||
448 | |||
449 | spin_unlock_irqrestore(&isci_device->isci_port->isci_host->scic_lock, flags); | ||
450 | |||
451 | /* Wait for the stop complete callback. */ | ||
452 | if (status == SCI_SUCCESS) | ||
453 | wait_for_completion(&completion); | ||
454 | |||
455 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
456 | "%s: isci_device = %p - after completion wait\n", | ||
457 | __func__, isci_device); | ||
458 | |||
459 | isci_device->completion = NULL; | ||
460 | return status; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * isci_remote_device_gone() - This function is called by libsas when a domain | ||
465 | * device is removed. | ||
466 | * @domain_device: This parameter specifies the libsas domain device. | ||
467 | * | ||
468 | */ | ||
469 | void isci_remote_device_gone( | ||
470 | struct domain_device *domain_dev) | ||
471 | { | ||
472 | struct isci_remote_device *isci_device = isci_dev_from_domain_dev( | ||
473 | domain_dev); | ||
474 | |||
475 | dev_err(&isci_device->isci_port->isci_host->pdev->dev, | ||
476 | "%s: domain_device = %p, isci_device = %p, isci_port = %p\n", | ||
477 | __func__, domain_dev, isci_device, isci_device->isci_port); | ||
478 | |||
479 | if (isci_device != NULL) | ||
480 | isci_remote_device_stop(isci_device); | ||
481 | } | ||
482 | |||
483 | |||
484 | /** | ||
485 | * isci_remote_device_found() - This function is called by libsas when a remote | ||
486 | * device is discovered. A remote device object is created and started. the | ||
487 | * function then sleeps until the sci core device started message is | ||
488 | * received. | ||
489 | * @domain_device: This parameter specifies the libsas domain device. | ||
490 | * | ||
491 | * status, zero indicates success. | ||
492 | */ | ||
493 | int isci_remote_device_found(struct domain_device *domain_dev) | ||
494 | { | ||
495 | unsigned long flags; | ||
496 | struct isci_host *isci_host; | ||
497 | struct isci_port *isci_port; | ||
498 | struct isci_phy *isci_phy; | ||
499 | struct asd_sas_port *sas_port; | ||
500 | struct asd_sas_phy *sas_phy; | ||
501 | struct isci_remote_device *isci_device; | ||
502 | enum sci_status status; | ||
503 | DECLARE_COMPLETION_ONSTACK(completion); | ||
504 | |||
505 | isci_host = isci_host_from_sas_ha(domain_dev->port->ha); | ||
506 | |||
507 | dev_dbg(&isci_host->pdev->dev, | ||
508 | "%s: domain_device = %p\n", __func__, domain_dev); | ||
509 | |||
510 | sas_port = domain_dev->port; | ||
511 | sas_phy = list_first_entry(&sas_port->phy_list, struct asd_sas_phy, | ||
512 | port_phy_el); | ||
513 | isci_phy = to_isci_phy(sas_phy); | ||
514 | isci_port = isci_phy->isci_port; | ||
515 | |||
516 | /* we are being called for a device on this port, | ||
517 | * so it has to come up eventually | ||
518 | */ | ||
519 | wait_for_completion(&isci_port->start_complete); | ||
520 | |||
521 | if ((isci_stopping == isci_port_get_state(isci_port)) || | ||
522 | (isci_stopped == isci_port_get_state(isci_port))) | ||
523 | return -ENODEV; | ||
524 | |||
525 | isci_device = isci_remote_device_alloc(isci_host, isci_port); | ||
526 | |||
527 | INIT_LIST_HEAD(&isci_device->node); | ||
528 | domain_dev->lldd_dev = isci_device; | ||
529 | isci_device->domain_dev = domain_dev; | ||
530 | isci_device->isci_port = isci_port; | ||
531 | isci_remote_device_change_state(isci_device, isci_starting); | ||
532 | |||
533 | |||
534 | spin_lock_irqsave(&isci_port->remote_device_lock, flags); | ||
535 | list_add_tail(&isci_device->node, &isci_port->remote_dev_list); | ||
536 | |||
537 | /* for the device ready event. */ | ||
538 | isci_device->completion = &completion; | ||
539 | |||
540 | status = isci_remote_device_construct(isci_port, isci_device); | ||
541 | |||
542 | spin_unlock_irqrestore(&isci_port->remote_device_lock, flags); | ||
543 | |||
544 | /* wait for the device ready callback. */ | ||
545 | wait_for_completion(isci_device->completion); | ||
546 | isci_device->completion = NULL; | ||
547 | |||
548 | dev_dbg(&isci_host->pdev->dev, | ||
549 | "%s: isci_device = %p\n", | ||
550 | __func__, isci_device); | ||
551 | |||
552 | if (status != SCI_SUCCESS) { | ||
553 | |||
554 | spin_lock_irqsave(&isci_port->remote_device_lock, flags); | ||
555 | isci_remote_device_deconstruct( | ||
556 | isci_host, | ||
557 | isci_device | ||
558 | ); | ||
559 | spin_unlock_irqrestore(&isci_port->remote_device_lock, flags); | ||
560 | return -ENODEV; | ||
561 | } | ||
562 | |||
563 | wait_for_completion(&isci_host->start_complete); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | /** | ||
568 | * isci_device_is_reset_pending() - This function will check if there is any | ||
569 | * pending reset condition on the device. | ||
570 | * @request: This parameter is the isci_device object. | ||
571 | * | ||
572 | * true if there is a reset pending for the device. | ||
573 | */ | ||
574 | bool isci_device_is_reset_pending( | ||
575 | struct isci_host *isci_host, | ||
576 | struct isci_remote_device *isci_device) | ||
577 | { | ||
578 | struct isci_request *isci_request; | ||
579 | struct isci_request *tmp_req; | ||
580 | bool reset_is_pending = false; | ||
581 | unsigned long flags; | ||
582 | |||
583 | dev_dbg(&isci_host->pdev->dev, | ||
584 | "%s: isci_device = %p\n", __func__, isci_device); | ||
585 | |||
586 | spin_lock_irqsave(&isci_host->scic_lock, flags); | ||
587 | |||
588 | /* Check for reset on all pending requests. */ | ||
589 | list_for_each_entry_safe(isci_request, tmp_req, | ||
590 | &isci_device->reqs_in_process, dev_node) { | ||
591 | dev_dbg(&isci_host->pdev->dev, | ||
592 | "%s: isci_device = %p request = %p\n", | ||
593 | __func__, isci_device, isci_request); | ||
594 | |||
595 | if (isci_request->ttype == io_task) { | ||
596 | |||
597 | unsigned long flags; | ||
598 | struct sas_task *task = isci_request_access_task( | ||
599 | isci_request); | ||
600 | |||
601 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
602 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) | ||
603 | reset_is_pending = true; | ||
604 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | ||
609 | |||
610 | dev_dbg(&isci_host->pdev->dev, | ||
611 | "%s: isci_device = %p reset_is_pending = %d\n", | ||
612 | __func__, isci_device, reset_is_pending); | ||
613 | |||
614 | return reset_is_pending; | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * isci_device_clear_reset_pending() - This function will clear if any pending | ||
619 | * reset condition flags on the device. | ||
620 | * @request: This parameter is the isci_device object. | ||
621 | * | ||
622 | * true if there is a reset pending for the device. | ||
623 | */ | ||
624 | void isci_device_clear_reset_pending(struct isci_remote_device *isci_device) | ||
625 | { | ||
626 | struct isci_request *isci_request; | ||
627 | struct isci_request *tmp_req; | ||
628 | struct isci_host *isci_host = NULL; | ||
629 | unsigned long flags = 0; | ||
630 | |||
631 | /* FIXME more port gone confusion, and this time it makes the | ||
632 | * locking "fun" | ||
633 | */ | ||
634 | if (isci_device->isci_port != NULL) | ||
635 | isci_host = isci_device->isci_port->isci_host; | ||
636 | |||
637 | /* | ||
638 | * FIXME when the isci_host gets sorted out | ||
639 | * use dev_dbg() | ||
640 | */ | ||
641 | pr_debug("%s: isci_device=%p, isci_host=%p\n", | ||
642 | __func__, isci_device, isci_host); | ||
643 | |||
644 | if (isci_host != NULL) | ||
645 | spin_lock_irqsave(&isci_host->scic_lock, flags); | ||
646 | else | ||
647 | pr_err("%s: isci_device %p; isci_host == NULL!\n", | ||
648 | __func__, isci_device); | ||
649 | |||
650 | /* Clear reset pending on all pending requests. */ | ||
651 | list_for_each_entry_safe(isci_request, tmp_req, | ||
652 | &isci_device->reqs_in_process, dev_node) { | ||
653 | /* | ||
654 | * FIXME when the conditional spinlock is gone | ||
655 | * change to dev_dbg() | ||
656 | */ | ||
657 | pr_debug("%s: isci_device = %p request = %p\n", | ||
658 | __func__, isci_device, isci_request); | ||
659 | |||
660 | if (isci_request->ttype == io_task) { | ||
661 | |||
662 | unsigned long flags2; | ||
663 | struct sas_task *task = isci_request_access_task( | ||
664 | isci_request); | ||
665 | |||
666 | spin_lock_irqsave(&task->task_state_lock, flags2); | ||
667 | task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; | ||
668 | spin_unlock_irqrestore(&task->task_state_lock, flags2); | ||
669 | } | ||
670 | } | ||
671 | |||
672 | if (isci_host != NULL) | ||
673 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * isci_remote_device_change_state() - This function gets the status of the | ||
678 | * remote_device object. | ||
679 | * @isci_device: This parameter points to the isci_remote_device object | ||
680 | * | ||
681 | * status of the object as a isci_status enum. | ||
682 | */ | ||
683 | void isci_remote_device_change_state( | ||
684 | struct isci_remote_device *isci_device, | ||
685 | enum isci_status status) | ||
686 | { | ||
687 | unsigned long flags; | ||
688 | |||
689 | dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, | ||
690 | "%s: isci_device = %p, state = 0x%x", | ||
691 | __func__, | ||
692 | isci_device, | ||
693 | status); | ||
694 | |||
695 | spin_lock_irqsave(&isci_device->state_lock, flags); | ||
696 | isci_device->status = status; | ||
697 | spin_unlock_irqrestore(&isci_device->state_lock, flags); | ||
698 | } | ||