2 * FiberChannel transport specific attributes exported to sysfs.
4 * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <scsi/scsi_device.h>
23 #include <scsi/scsi_host.h>
24 #include <scsi/scsi_transport.h>
25 #include <scsi/scsi_transport_fc.h>
26 #include "scsi_priv.h"
28 #define FC_PRINTK(x, l, f, a...) printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a)
30 static void transport_class_release(struct class_device *class_dev);
31 static void host_class_release(struct class_device *class_dev);
32 static void fc_timeout_blocked_host(void *data);
33 static void fc_timeout_blocked_tgt(void *data);
35 #define FC_STARGET_NUM_ATTRS 4 /* increase this if you add attributes */
36 #define FC_STARGET_OTHER_ATTRS 0 /* increase this if you add "always on"
38 #define FC_HOST_NUM_ATTRS 1
41 struct scsi_transport_template t;
42 struct fc_function_template *f;
43 /* The actual attributes */
44 struct class_device_attribute private_starget_attrs[
45 FC_STARGET_NUM_ATTRS];
46 /* The array of null terminated pointers to attributes
47 * needed by scsi_sysfs.c */
48 struct class_device_attribute *starget_attrs[
49 FC_STARGET_NUM_ATTRS + FC_STARGET_OTHER_ATTRS + 1];
51 struct class_device_attribute private_host_attrs[FC_HOST_NUM_ATTRS];
52 struct class_device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1];
55 #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
57 struct class fc_transport_class = {
58 .name = "fc_transport",
59 .release = transport_class_release,
62 struct class fc_host_class = {
64 .release = host_class_release,
67 static __init int fc_transport_init(void)
69 int error = class_register(&fc_host_class);
72 return class_register(&fc_transport_class);
75 static void __exit fc_transport_exit(void)
77 class_unregister(&fc_transport_class);
78 class_unregister(&fc_host_class);
81 static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
84 * Set default values easily detected by the midlayer as
85 * failure cases. The scsi lldd is responsible for initializing
86 * all transport attributes to valid values per target.
88 fc_starget_node_name(starget) = -1;
89 fc_starget_port_name(starget) = -1;
90 fc_starget_port_id(starget) = -1;
91 fc_starget_dev_loss_tmo(starget) = -1;
92 INIT_WORK(&fc_starget_dev_loss_work(starget),
93 fc_timeout_blocked_tgt, starget);
97 static void fc_destroy_starget(struct scsi_target *starget)
99 /* Stop the target timer */
100 if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
101 flush_scheduled_work();
104 static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
107 * Set default values easily detected by the midlayer as
108 * failure cases. The scsi lldd is responsible for initializing
109 * all transport attributes to valid values per host.
111 fc_host_link_down_tmo(shost) = -1;
112 INIT_WORK(&fc_host_link_down_work(shost),
113 fc_timeout_blocked_host, shost);
117 static void fc_destroy_host(struct Scsi_Host *shost)
119 /* Stop the host timer */
120 if (cancel_delayed_work(&fc_host_link_down_work(shost)))
121 flush_scheduled_work();
124 static void transport_class_release(struct class_device *class_dev)
126 struct scsi_target *starget = transport_class_to_starget(class_dev);
127 put_device(&starget->dev);
130 static void host_class_release(struct class_device *class_dev)
132 struct Scsi_Host *shost = transport_class_to_shost(class_dev);
133 put_device(&shost->shost_gendev);
138 * Remote Port Attribute Management
141 #define fc_starget_show_function(field, format_string, cast) \
143 show_fc_starget_##field (struct class_device *cdev, char *buf) \
145 struct scsi_target *starget = transport_class_to_starget(cdev); \
146 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
147 struct fc_starget_attrs *tp; \
148 struct fc_internal *i = to_fc_internal(shost->transportt); \
149 tp = (struct fc_starget_attrs *)&starget->starget_data; \
150 if (i->f->get_starget_##field) \
151 i->f->get_starget_##field(starget); \
152 return snprintf(buf, 20, format_string, cast tp->field); \
155 #define fc_starget_store_function(field, format_string) \
157 store_fc_starget_##field(struct class_device *cdev, const char *buf, \
161 struct scsi_target *starget = transport_class_to_starget(cdev); \
162 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
163 struct fc_internal *i = to_fc_internal(shost->transportt); \
165 val = simple_strtoul(buf, NULL, 0); \
166 i->f->set_starget_##field(starget, val); \
170 #define fc_starget_rd_attr(field, format_string) \
171 fc_starget_show_function(field, format_string, ) \
172 static CLASS_DEVICE_ATTR(field, S_IRUGO, \
173 show_fc_starget_##field, NULL)
175 #define fc_starget_rd_attr_cast(field, format_string, cast) \
176 fc_starget_show_function(field, format_string, (cast)) \
177 static CLASS_DEVICE_ATTR(field, S_IRUGO, \
178 show_fc_starget_##field, NULL)
180 #define fc_starget_rw_attr(field, format_string) \
181 fc_starget_show_function(field, format_string, ) \
182 fc_starget_store_function(field, format_string) \
183 static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
184 show_fc_starget_##field, \
185 store_fc_starget_##field)
187 #define SETUP_STARGET_ATTRIBUTE_RD(field) \
188 i->private_starget_attrs[count] = class_device_attr_##field; \
189 i->private_starget_attrs[count].attr.mode = S_IRUGO; \
190 i->private_starget_attrs[count].store = NULL; \
191 i->starget_attrs[count] = &i->private_starget_attrs[count]; \
192 if (i->f->show_starget_##field) \
195 #define SETUP_STARGET_ATTRIBUTE_RW(field) \
196 i->private_starget_attrs[count] = class_device_attr_##field; \
197 if (!i->f->set_starget_##field) { \
198 i->private_starget_attrs[count].attr.mode = S_IRUGO; \
199 i->private_starget_attrs[count].store = NULL; \
201 i->starget_attrs[count] = &i->private_starget_attrs[count]; \
202 if (i->f->show_starget_##field) \
205 /* The FC Tranport Remote Port (Target) Attributes: */
206 fc_starget_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
207 fc_starget_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
208 fc_starget_rd_attr(port_id, "0x%06x\n");
209 fc_starget_rw_attr(dev_loss_tmo, "%d\n");
213 * Host Attribute Management
216 #define fc_host_show_function(field, format_string, cast) \
218 show_fc_host_##field (struct class_device *cdev, char *buf) \
220 struct Scsi_Host *shost = transport_class_to_shost(cdev); \
221 struct fc_host_attrs *tp; \
222 struct fc_internal *i = to_fc_internal(shost->transportt); \
223 tp = (struct fc_host_attrs *)shost->shost_data; \
224 if (i->f->get_host_##field) \
225 i->f->get_host_##field(shost); \
226 return snprintf(buf, 20, format_string, cast tp->field); \
229 #define fc_host_store_function(field, format_string) \
231 store_fc_host_##field(struct class_device *cdev, const char *buf, \
235 struct Scsi_Host *shost = transport_class_to_shost(cdev); \
236 struct fc_internal *i = to_fc_internal(shost->transportt); \
238 val = simple_strtoul(buf, NULL, 0); \
239 i->f->set_host_##field(shost, val); \
243 #define fc_host_rd_attr(field, format_string) \
244 fc_host_show_function(field, format_string, ) \
245 static CLASS_DEVICE_ATTR(host_##field, S_IRUGO, \
246 show_fc_host_##field, NULL)
248 #define fc_host_rd_attr_cast(field, format_string, cast) \
249 fc_host_show_function(field, format_string, (cast)) \
250 static CLASS_DEVICE_ATTR(host_##field, S_IRUGO, \
251 show_fc_host_##field, NULL)
253 #define fc_host_rw_attr(field, format_string) \
254 fc_host_show_function(field, format_string, ) \
255 fc_host_store_function(field, format_string) \
256 static CLASS_DEVICE_ATTR(host_##field, S_IRUGO | S_IWUSR, \
257 show_fc_host_##field, \
258 store_fc_host_##field)
260 #define SETUP_HOST_ATTRIBUTE_RD(field) \
261 i->private_host_attrs[count] = class_device_attr_host_##field; \
262 i->private_host_attrs[count].attr.mode = S_IRUGO; \
263 i->private_host_attrs[count].store = NULL; \
264 i->host_attrs[count] = &i->private_host_attrs[count]; \
265 if (i->f->show_host_##field) \
268 #define SETUP_HOST_ATTRIBUTE_RW(field) \
269 i->private_host_attrs[count] = class_device_attr_host_##field; \
270 if (!i->f->set_host_##field) { \
271 i->private_host_attrs[count].attr.mode = S_IRUGO; \
272 i->private_host_attrs[count].store = NULL; \
274 i->host_attrs[count] = &i->private_host_attrs[count]; \
275 if (i->f->show_host_##field) \
278 /* The FC Tranport Host Attributes: */
279 fc_host_rw_attr(link_down_tmo, "%d\n");
283 struct scsi_transport_template *
284 fc_attach_transport(struct fc_function_template *ft)
286 struct fc_internal *i = kmalloc(sizeof(struct fc_internal),
293 memset(i, 0, sizeof(struct fc_internal));
295 i->t.target_attrs = &i->starget_attrs[0];
296 i->t.target_class = &fc_transport_class;
297 i->t.target_setup = &fc_setup_starget_transport_attrs;
298 i->t.target_destroy = &fc_destroy_starget;
299 i->t.target_size = sizeof(struct fc_starget_attrs);
301 i->t.host_attrs = &i->host_attrs[0];
302 i->t.host_class = &fc_host_class;
303 i->t.host_setup = &fc_setup_host_transport_attrs;
304 i->t.host_destroy = &fc_destroy_host;
305 i->t.host_size = sizeof(struct fc_host_attrs);
310 * setup remote port (target) attributes
312 SETUP_STARGET_ATTRIBUTE_RD(port_id);
313 SETUP_STARGET_ATTRIBUTE_RD(port_name);
314 SETUP_STARGET_ATTRIBUTE_RD(node_name);
315 SETUP_STARGET_ATTRIBUTE_RW(dev_loss_tmo);
317 BUG_ON(count > FC_STARGET_NUM_ATTRS);
319 /* Setup the always-on attributes here */
321 i->starget_attrs[count] = NULL;
324 /* setup host attributes */
326 SETUP_HOST_ATTRIBUTE_RW(link_down_tmo);
328 BUG_ON(count > FC_HOST_NUM_ATTRS);
330 /* Setup the always-on attributes here */
332 i->host_attrs[count] = NULL;
337 EXPORT_SYMBOL(fc_attach_transport);
339 void fc_release_transport(struct scsi_transport_template *t)
341 struct fc_internal *i = to_fc_internal(t);
345 EXPORT_SYMBOL(fc_release_transport);
350 * fc_device_block - called by target functions to block a scsi device
354 static int fc_device_block(struct device *dev, void *data)
356 scsi_internal_device_block(to_scsi_device(dev));
361 * fc_device_unblock - called by target functions to unblock a scsi device
365 static int fc_device_unblock(struct device *dev, void *data)
367 scsi_internal_device_unblock(to_scsi_device(dev));
372 * fc_timeout_blocked_tgt - Timeout handler for blocked scsi targets
373 * that fail to recover in the alloted time.
374 * @data: scsi target that failed to reappear in the alloted time.
376 static void fc_timeout_blocked_tgt(void *data)
378 struct scsi_target *starget = (struct scsi_target *)data;
380 dev_printk(KERN_ERR, &starget->dev,
381 "blocked target time out: target resuming\n");
384 * set the device going again ... if the scsi lld didn't
385 * unblock this device, then IO errors will probably
386 * result if the host still isn't ready.
388 device_for_each_child(&starget->dev, NULL, fc_device_unblock);
392 * fc_target_block - block a target by temporarily putting all its scsi devices
393 * into the SDEV_BLOCK state.
394 * @starget: scsi target managed by this fc scsi lldd.
396 * scsi lldd's with a FC transport call this routine to temporarily stop all
397 * scsi commands to all devices managed by this scsi target. Called
398 * from interrupt or normal process context.
400 * Returns zero if successful or error if not
403 * The timeout and timer types are extracted from the fc transport
404 * attributes from the caller's target pointer. This routine assumes no
405 * locks are held on entry.
408 fc_target_block(struct scsi_target *starget)
410 int timeout = fc_starget_dev_loss_tmo(starget);
411 struct work_struct *work = &fc_starget_dev_loss_work(starget);
413 if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
416 device_for_each_child(&starget->dev, NULL, fc_device_block);
418 /* The scsi lld blocks this target for the timeout period only. */
419 schedule_delayed_work(work, timeout * HZ);
423 EXPORT_SYMBOL(fc_target_block);
426 * fc_target_unblock - unblock a target following a fc_target_block request.
427 * @starget: scsi target managed by this fc scsi lldd.
429 * scsi lld's with a FC transport call this routine to restart IO to all
430 * devices associated with the caller's scsi target following a fc_target_block
431 * request. Called from interrupt or normal process context.
434 * This routine assumes no locks are held on entry.
437 fc_target_unblock(struct scsi_target *starget)
440 * Stop the target timer first. Take no action on the del_timer
441 * failure as the state machine state change will validate the
444 if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
445 flush_scheduled_work();
447 device_for_each_child(&starget->dev, NULL, fc_device_unblock);
449 EXPORT_SYMBOL(fc_target_unblock);
452 * fc_timeout_blocked_host - Timeout handler for blocked scsi hosts
453 * that fail to recover in the alloted time.
454 * @data: scsi host that failed to recover its devices in the alloted
457 static void fc_timeout_blocked_host(void *data)
459 struct Scsi_Host *shost = (struct Scsi_Host *)data;
460 struct scsi_device *sdev;
462 dev_printk(KERN_ERR, &shost->shost_gendev,
463 "blocked host time out: host resuming\n");
465 shost_for_each_device(sdev, shost) {
467 * set the device going again ... if the scsi lld didn't
468 * unblock this device, then IO errors will probably
469 * result if the host still isn't ready.
471 scsi_internal_device_unblock(sdev);
476 * fc_host_block - block all scsi devices managed by the calling host temporarily
477 * by putting each device in the SDEV_BLOCK state.
478 * @shost: scsi host pointer that contains all scsi device siblings.
480 * scsi lld's with a FC transport call this routine to temporarily stop all
481 * scsi commands to all devices managed by this host. Called
482 * from interrupt or normal process context.
484 * Returns zero if successful or error if not
487 * The timeout and timer types are extracted from the fc transport
488 * attributes from the caller's host pointer. This routine assumes no
489 * locks are held on entry.
492 fc_host_block(struct Scsi_Host *shost)
494 struct scsi_device *sdev;
495 int timeout = fc_host_link_down_tmo(shost);
496 struct work_struct *work = &fc_host_link_down_work(shost);
498 if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
501 shost_for_each_device(sdev, shost) {
502 scsi_internal_device_block(sdev);
505 schedule_delayed_work(work, timeout * HZ);
509 EXPORT_SYMBOL(fc_host_block);
512 * fc_host_unblock - unblock all devices managed by this host following a
513 * fc_host_block request.
514 * @shost: scsi host containing all scsi device siblings to unblock.
516 * scsi lld's with a FC transport call this routine to restart IO to all scsi
517 * devices managed by the specified scsi host following an fc_host_block
518 * request. Called from interrupt or normal process context.
521 * This routine assumes no locks are held on entry.
524 fc_host_unblock(struct Scsi_Host *shost)
526 struct scsi_device *sdev;
529 * Stop the host timer first. Take no action on the del_timer
530 * failure as the state machine state change will validate the
533 if (cancel_delayed_work(&fc_host_link_down_work(shost)))
534 flush_scheduled_work();
536 shost_for_each_device(sdev, shost) {
537 scsi_internal_device_unblock(sdev);
540 EXPORT_SYMBOL(fc_host_unblock);
542 MODULE_AUTHOR("Martin Hicks");
543 MODULE_DESCRIPTION("FC Transport Attributes");
544 MODULE_LICENSE("GPL");
546 module_init(fc_transport_init);
547 module_exit(fc_transport_exit);