]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/s390/scsi/zfcp_ccw.c
Merge branch 'doc-subdirs' of git://git.kernel.org/pub/scm/linux/kernel/git/rdunlap...
[linux-2.6-omap-h63xx.git] / drivers / s390 / scsi / zfcp_ccw.c
1 /*
2  * zfcp device driver
3  *
4  * Registration and callback for the s390 common I/O layer.
5  *
6  * Copyright IBM Corporation 2002, 2008
7  */
8
9 #include "zfcp_ext.h"
10
11 /**
12  * zfcp_ccw_probe - probe function of zfcp driver
13  * @ccw_device: pointer to belonging ccw device
14  *
15  * This function gets called by the common i/o layer and sets up the initial
16  * data structures for each fcp adapter, which was detected by the system.
17  * Also the sysfs files for this adapter will be created by this function.
18  * In addition the nameserver port will be added to the ports of the adapter
19  * and its sysfs representation will be created too.
20  */
21 static int zfcp_ccw_probe(struct ccw_device *ccw_device)
22 {
23         int retval = 0;
24
25         down(&zfcp_data.config_sema);
26         if (zfcp_adapter_enqueue(ccw_device)) {
27                 dev_err(&ccw_device->dev,
28                         "Setting up data structures for the "
29                         "FCP adapter failed\n");
30                 retval = -EINVAL;
31         }
32         up(&zfcp_data.config_sema);
33         return retval;
34 }
35
36 /**
37  * zfcp_ccw_remove - remove function of zfcp driver
38  * @ccw_device: pointer to belonging ccw device
39  *
40  * This function gets called by the common i/o layer and removes an adapter
41  * from the system. Task of this function is to get rid of all units and
42  * ports that belong to this adapter. And in addition all resources of this
43  * adapter will be freed too.
44  */
45 static void zfcp_ccw_remove(struct ccw_device *ccw_device)
46 {
47         struct zfcp_adapter *adapter;
48         struct zfcp_port *port, *p;
49         struct zfcp_unit *unit, *u;
50         LIST_HEAD(unit_remove_lh);
51         LIST_HEAD(port_remove_lh);
52
53         ccw_device_set_offline(ccw_device);
54         down(&zfcp_data.config_sema);
55         adapter = dev_get_drvdata(&ccw_device->dev);
56
57         write_lock_irq(&zfcp_data.config_lock);
58         list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
59                 list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
60                         list_move(&unit->list, &unit_remove_lh);
61                         atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
62                                         &unit->status);
63                 }
64                 list_move(&port->list, &port_remove_lh);
65                 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
66         }
67         atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
68         write_unlock_irq(&zfcp_data.config_lock);
69
70         list_for_each_entry_safe(port, p, &port_remove_lh, list) {
71                 list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
72                         if (atomic_read(&unit->status) &
73                             ZFCP_STATUS_UNIT_REGISTERED)
74                                 scsi_remove_device(unit->device);
75                         zfcp_unit_dequeue(unit);
76                 }
77                 zfcp_port_dequeue(port);
78         }
79         wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
80         zfcp_adapter_dequeue(adapter);
81
82         up(&zfcp_data.config_sema);
83 }
84
85 /**
86  * zfcp_ccw_set_online - set_online function of zfcp driver
87  * @ccw_device: pointer to belonging ccw device
88  *
89  * This function gets called by the common i/o layer and sets an adapter
90  * into state online. Setting an fcp device online means that it will be
91  * registered with the SCSI stack, that the QDIO queues will be set up
92  * and that the adapter will be opened (asynchronously).
93  */
94 static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
95 {
96         struct zfcp_adapter *adapter;
97         int retval;
98
99         down(&zfcp_data.config_sema);
100         adapter = dev_get_drvdata(&ccw_device->dev);
101
102         retval = zfcp_erp_thread_setup(adapter);
103         if (retval)
104                 goto out;
105
106         retval = zfcp_adapter_scsi_register(adapter);
107         if (retval)
108                 goto out_scsi_register;
109
110         /* initialize request counter */
111         BUG_ON(!zfcp_reqlist_isempty(adapter));
112         adapter->req_no = 0;
113
114         zfcp_erp_modify_adapter_status(adapter, 10, NULL,
115                                        ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
116         zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 85,
117                                 NULL);
118         zfcp_erp_wait(adapter);
119         up(&zfcp_data.config_sema);
120         flush_work(&adapter->scan_work);
121         return 0;
122
123  out_scsi_register:
124         zfcp_erp_thread_kill(adapter);
125  out:
126         up(&zfcp_data.config_sema);
127         return retval;
128 }
129
130 /**
131  * zfcp_ccw_set_offline - set_offline function of zfcp driver
132  * @ccw_device: pointer to belonging ccw device
133  *
134  * This function gets called by the common i/o layer and sets an adapter
135  * into state offline.
136  */
137 static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
138 {
139         struct zfcp_adapter *adapter;
140
141         down(&zfcp_data.config_sema);
142         adapter = dev_get_drvdata(&ccw_device->dev);
143         zfcp_erp_adapter_shutdown(adapter, 0, 86, NULL);
144         zfcp_erp_wait(adapter);
145         zfcp_erp_thread_kill(adapter);
146         up(&zfcp_data.config_sema);
147         return 0;
148 }
149
150 /**
151  * zfcp_ccw_notify - ccw notify function
152  * @ccw_device: pointer to belonging ccw device
153  * @event: indicates if adapter was detached or attached
154  *
155  * This function gets called by the common i/o layer if an adapter has gone
156  * or reappeared.
157  */
158 static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
159 {
160         struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
161
162         switch (event) {
163         case CIO_GONE:
164                 dev_warn(&adapter->ccw_device->dev,
165                          "The FCP device has been detached\n");
166                 zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL);
167                 break;
168         case CIO_NO_PATH:
169                 dev_warn(&adapter->ccw_device->dev,
170                          "The CHPID for the FCP device is offline\n");
171                 zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL);
172                 break;
173         case CIO_OPER:
174                 dev_info(&adapter->ccw_device->dev,
175                          "The FCP device is operational again\n");
176                 zfcp_erp_modify_adapter_status(adapter, 11, NULL,
177                                                ZFCP_STATUS_COMMON_RUNNING,
178                                                ZFCP_SET);
179                 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
180                                         89, NULL);
181                 break;
182         }
183         return 1;
184 }
185
186 /**
187  * zfcp_ccw_shutdown - handle shutdown from cio
188  * @cdev: device for adapter to shutdown.
189  */
190 static void zfcp_ccw_shutdown(struct ccw_device *cdev)
191 {
192         struct zfcp_adapter *adapter;
193
194         down(&zfcp_data.config_sema);
195         adapter = dev_get_drvdata(&cdev->dev);
196         zfcp_erp_adapter_shutdown(adapter, 0, 90, NULL);
197         zfcp_erp_wait(adapter);
198         up(&zfcp_data.config_sema);
199 }
200
201 static struct ccw_device_id zfcp_ccw_device_id[] = {
202         { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
203         { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */
204         {},
205 };
206
207 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
208
209 static struct ccw_driver zfcp_ccw_driver = {
210         .owner       = THIS_MODULE,
211         .name        = "zfcp",
212         .ids         = zfcp_ccw_device_id,
213         .probe       = zfcp_ccw_probe,
214         .remove      = zfcp_ccw_remove,
215         .set_online  = zfcp_ccw_set_online,
216         .set_offline = zfcp_ccw_set_offline,
217         .notify      = zfcp_ccw_notify,
218         .shutdown    = zfcp_ccw_shutdown,
219 };
220
221 /**
222  * zfcp_ccw_register - ccw register function
223  *
224  * Registers the driver at the common i/o layer. This function will be called
225  * at module load time/system start.
226  */
227 int __init zfcp_ccw_register(void)
228 {
229         return ccw_driver_register(&zfcp_ccw_driver);
230 }
231
232 /**
233  * zfcp_get_adapter_by_busid - find zfcp_adapter struct
234  * @busid: bus id string of zfcp adapter to find
235  */
236 struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid)
237 {
238         struct ccw_device *ccw_device;
239         struct zfcp_adapter *adapter = NULL;
240
241         ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
242         if (ccw_device) {
243                 adapter = dev_get_drvdata(&ccw_device->dev);
244                 put_device(&ccw_device->dev);
245         }
246         return adapter;
247 }