aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_iscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-04-06 22:13:39 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-14 15:05:09 -0400
commit30a6c65236f9d26e3325cae468f330b833a3878c (patch)
tree355519ccc74d4b3984c06d7dcb5852282e47c845 /drivers/scsi/scsi_transport_iscsi.c
parentfd7255f51a13ea915099c7e488001dfbbeb05104 (diff)
[SCSI] iscsi: fix up iscsi eh
The current iscsi_tcp eh is not nicely setup for dm-multipath and performs some extra task management functions when they are not needed. The attached patch: - Fixes the TMF issues. If a session is rebuilt then we do not send aborts. - Fixes the problem where if the host reset fired, we would return SUCCESS even though we had not really done anything yet. This ends up causing problem with scsi_error.c's TUR. - If someone has turned on the userspace nop daemon code to try and detect network problems before the scsi command timeout we can now drop and clean up the session before the scsi command timesout and fires the eh speeding up the time it takes for a command to go from one patch to another. For network problems we fail the command with DID_BUS_BUSY so if failfast is set scsi_decide_disposition fails the command up to dm for it to try on another path. - And we had to add some basic iscsi session block code. Previously if we were trying to repair a session we would retrun a MLQUEUE code in the queuecommand. This worked but it was not the most efficient or pretty thing to do since it would take a while to relogin to the target. For iscsi_tcp/open-iscsi a lot of the iscsi error handler is in userspace the block code is pretty bare. We will be adding to that for qla4xxx. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c152
1 files changed, 143 insertions, 9 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 72a71ebc9d03..e2b67e34d92e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -31,17 +31,17 @@
31#include <scsi/scsi_transport_iscsi.h> 31#include <scsi/scsi_transport_iscsi.h>
32#include <scsi/iscsi_if.h> 32#include <scsi/iscsi_if.h>
33 33
34#define ISCSI_SESSION_ATTRS 10 34#define ISCSI_SESSION_ATTRS 11
35#define ISCSI_CONN_ATTRS 10 35#define ISCSI_CONN_ATTRS 10
36#define ISCSI_HOST_ATTRS 0
36 37
37struct iscsi_internal { 38struct iscsi_internal {
38 struct scsi_transport_template t; 39 struct scsi_transport_template t;
39 struct iscsi_transport *iscsi_transport; 40 struct iscsi_transport *iscsi_transport;
40 struct list_head list; 41 struct list_head list;
41 struct class_device cdev; 42 struct class_device cdev;
42 /* 43
43 * We do not have any private or other attrs. 44 struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
44 */
45 struct transport_container conn_cont; 45 struct transport_container conn_cont;
46 struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1]; 46 struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
47 struct transport_container session_cont; 47 struct transport_container session_cont;
@@ -114,6 +114,24 @@ static struct attribute_group iscsi_transport_group = {
114 .attrs = iscsi_transport_attrs, 114 .attrs = iscsi_transport_attrs,
115}; 115};
116 116
117static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
118 struct class_device *cdev)
119{
120 struct Scsi_Host *shost = dev_to_shost(dev);
121 struct iscsi_host *ihost = shost->shost_data;
122
123 memset(ihost, 0, sizeof(*ihost));
124 INIT_LIST_HEAD(&ihost->sessions);
125 mutex_init(&ihost->mutex);
126 return 0;
127}
128
129static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
130 "iscsi_host",
131 iscsi_setup_host,
132 NULL,
133 NULL);
134
117static DECLARE_TRANSPORT_CLASS(iscsi_session_class, 135static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
118 "iscsi_session", 136 "iscsi_session",
119 NULL, 137 NULL,
@@ -225,6 +243,54 @@ static int iscsi_is_session_dev(const struct device *dev)
225 return dev->release == iscsi_session_release; 243 return dev->release == iscsi_session_release;
226} 244}
227 245
246static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
247 uint id, uint lun)
248{
249 struct iscsi_host *ihost = shost->shost_data;
250 struct iscsi_cls_session *session;
251
252 mutex_lock(&ihost->mutex);
253 list_for_each_entry(session, &ihost->sessions, host_list) {
254 if ((channel == SCAN_WILD_CARD ||
255 channel == session->channel) &&
256 (id == SCAN_WILD_CARD || id == session->target_id))
257 scsi_scan_target(&session->dev, session->channel,
258 session->target_id, lun, 1);
259 }
260 mutex_unlock(&ihost->mutex);
261
262 return 0;
263}
264
265static void session_recovery_timedout(void *data)
266{
267 struct iscsi_cls_session *session = data;
268
269 dev_printk(KERN_INFO, &session->dev, "session recovery timed out "
270 "after %d secs\n", session->recovery_tmo);
271
272 if (session->transport->session_recovery_timedout)
273 session->transport->session_recovery_timedout(session);
274
275 scsi_target_unblock(&session->dev);
276}
277
278void iscsi_unblock_session(struct iscsi_cls_session *session)
279{
280 if (!cancel_delayed_work(&session->recovery_work))
281 flush_scheduled_work();
282 scsi_target_unblock(&session->dev);
283}
284EXPORT_SYMBOL_GPL(iscsi_unblock_session);
285
286void iscsi_block_session(struct iscsi_cls_session *session)
287{
288 scsi_target_block(&session->dev);
289 schedule_delayed_work(&session->recovery_work,
290 session->recovery_tmo * HZ);
291}
292EXPORT_SYMBOL_GPL(iscsi_block_session);
293
228/** 294/**
229 * iscsi_create_session - create iscsi class session 295 * iscsi_create_session - create iscsi class session
230 * @shost: scsi host 296 * @shost: scsi host
@@ -233,8 +299,10 @@ static int iscsi_is_session_dev(const struct device *dev)
233 * This can be called from a LLD or iscsi_transport. 299 * This can be called from a LLD or iscsi_transport.
234 **/ 300 **/
235struct iscsi_cls_session * 301struct iscsi_cls_session *
236iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) 302iscsi_create_session(struct Scsi_Host *shost,
303 struct iscsi_transport *transport, int channel)
237{ 304{
305 struct iscsi_host *ihost;
238 struct iscsi_cls_session *session; 306 struct iscsi_cls_session *session;
239 int err; 307 int err;
240 308
@@ -246,13 +314,22 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
246 if (!session) 314 if (!session)
247 goto module_put; 315 goto module_put;
248 session->transport = transport; 316 session->transport = transport;
317 session->recovery_tmo = 120;
318 INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
319 INIT_LIST_HEAD(&session->host_list);
320 INIT_LIST_HEAD(&session->sess_list);
249 321
250 if (transport->sessiondata_size) 322 if (transport->sessiondata_size)
251 session->dd_data = &session[1]; 323 session->dd_data = &session[1];
252 324
253 /* this is released in the dev's release function */ 325 /* this is released in the dev's release function */
254 scsi_host_get(shost); 326 scsi_host_get(shost);
327 ihost = shost->shost_data;
328
255 session->sid = iscsi_session_nr++; 329 session->sid = iscsi_session_nr++;
330 session->channel = channel;
331 session->target_id = ihost->next_target_id++;
332
256 snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", 333 snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
257 session->sid); 334 session->sid);
258 session->dev.parent = &shost->shost_gendev; 335 session->dev.parent = &shost->shost_gendev;
@@ -265,6 +342,10 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
265 } 342 }
266 transport_register_device(&session->dev); 343 transport_register_device(&session->dev);
267 344
345 mutex_lock(&ihost->mutex);
346 list_add(&session->host_list, &ihost->sessions);
347 mutex_unlock(&ihost->mutex);
348
268 return session; 349 return session;
269 350
270free_session: 351free_session:
@@ -285,6 +366,16 @@ EXPORT_SYMBOL_GPL(iscsi_create_session);
285 **/ 366 **/
286int iscsi_destroy_session(struct iscsi_cls_session *session) 367int iscsi_destroy_session(struct iscsi_cls_session *session)
287{ 368{
369 struct Scsi_Host *shost = iscsi_session_to_shost(session);
370 struct iscsi_host *ihost = shost->shost_data;
371
372 if (!cancel_delayed_work(&session->recovery_work))
373 flush_scheduled_work();
374
375 mutex_lock(&ihost->mutex);
376 list_del(&session->host_list);
377 mutex_unlock(&ihost->mutex);
378
288 transport_unregister_device(&session->dev); 379 transport_unregister_device(&session->dev);
289 device_unregister(&session->dev); 380 device_unregister(&session->dev);
290 return 0; 381 return 0;
@@ -435,7 +526,7 @@ iscsi_transport_create_session(struct scsi_transport_template *scsit,
435 if (scsi_add_host(shost, NULL)) 526 if (scsi_add_host(shost, NULL))
436 goto free_host; 527 goto free_host;
437 528
438 session = iscsi_create_session(shost, transport); 529 session = iscsi_create_session(shost, transport, 0);
439 if (!session) 530 if (!session)
440 goto remove_host; 531 goto remove_host;
441 532
@@ -466,12 +557,13 @@ int iscsi_transport_destroy_session(struct Scsi_Host *shost)
466 struct iscsi_cls_session *session; 557 struct iscsi_cls_session *session;
467 unsigned long flags; 558 unsigned long flags;
468 559
469 scsi_remove_host(shost);
470 session = hostdata_session(shost->hostdata); 560 session = hostdata_session(shost->hostdata);
471 spin_lock_irqsave(&sesslock, flags); 561 spin_lock_irqsave(&sesslock, flags);
472 list_del(&session->sess_list); 562 list_del(&session->sess_list);
473 spin_unlock_irqrestore(&sesslock, flags); 563 spin_unlock_irqrestore(&sesslock, flags);
474 iscsi_destroy_session(session); 564 iscsi_destroy_session(session);
565
566 scsi_remove_host(shost);
475 /* ref from host alloc */ 567 /* ref from host alloc */
476 scsi_host_put(shost); 568 scsi_host_put(shost);
477 return 0; 569 return 0;
@@ -594,6 +686,7 @@ iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb)
594 } 686 }
595 687
596 spin_lock_irqsave(&zone->freelock, flags); 688 spin_lock_irqsave(&zone->freelock, flags);
689 INIT_LIST_HEAD(skb_to_lh(skb));
597 list_add(skb_to_lh(skb), &zone->freequeue); 690 list_add(skb_to_lh(skb), &zone->freequeue);
598 spin_unlock_irqrestore(&zone->freelock, flags); 691 spin_unlock_irqrestore(&zone->freelock, flags);
599 692
@@ -888,6 +981,11 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
888 return -EINVAL; 981 return -EINVAL;
889 982
890 switch (ev->u.set_param.param) { 983 switch (ev->u.set_param.param) {
984 case ISCSI_PARAM_SESS_RECOVERY_TMO:
985 iscsi_copy_param(ev, &value, data);
986 if (value != 0)
987 session->recovery_tmo = value;
988 break;
891 case ISCSI_PARAM_TARGET_NAME: 989 case ISCSI_PARAM_TARGET_NAME:
892 /* this should not change between logins */ 990 /* this should not change between logins */
893 if (session->targetname) 991 if (session->targetname)
@@ -980,7 +1078,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
980 ev->r.retcode = transport->start_conn(conn); 1078 ev->r.retcode = transport->start_conn(conn);
981 else 1079 else
982 err = -EINVAL; 1080 err = -EINVAL;
983
984 break; 1081 break;
985 case ISCSI_UEVENT_STOP_CONN: 1082 case ISCSI_UEVENT_STOP_CONN:
986 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); 1083 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
@@ -1198,6 +1295,7 @@ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
1198 NULL) 1295 NULL)
1199iscsi_priv_session_attr(targetname, "%s"); 1296iscsi_priv_session_attr(targetname, "%s");
1200iscsi_priv_session_attr(tpgt, "%d"); 1297iscsi_priv_session_attr(tpgt, "%d");
1298iscsi_priv_session_attr(recovery_tmo, "%d");
1201 1299
1202#define iscsi_priv_conn_attr_show(field, format) \ 1300#define iscsi_priv_conn_attr_show(field, format) \
1203static ssize_t \ 1301static ssize_t \
@@ -1289,6 +1387,24 @@ static int iscsi_conn_match(struct attribute_container *cont,
1289 return &priv->conn_cont.ac == cont; 1387 return &priv->conn_cont.ac == cont;
1290} 1388}
1291 1389
1390static int iscsi_host_match(struct attribute_container *cont,
1391 struct device *dev)
1392{
1393 struct Scsi_Host *shost;
1394 struct iscsi_internal *priv;
1395
1396 if (!scsi_is_host_device(dev))
1397 return 0;
1398
1399 shost = dev_to_shost(dev);
1400 if (!shost->transportt ||
1401 shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
1402 return 0;
1403
1404 priv = to_iscsi_internal(shost->transportt);
1405 return &priv->t.host_attrs.ac == cont;
1406}
1407
1292struct scsi_transport_template * 1408struct scsi_transport_template *
1293iscsi_register_transport(struct iscsi_transport *tt) 1409iscsi_register_transport(struct iscsi_transport *tt)
1294{ 1410{
@@ -1307,6 +1423,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1307 return NULL; 1423 return NULL;
1308 INIT_LIST_HEAD(&priv->list); 1424 INIT_LIST_HEAD(&priv->list);
1309 priv->iscsi_transport = tt; 1425 priv->iscsi_transport = tt;
1426 priv->t.user_scan = iscsi_user_scan;
1310 1427
1311 priv->cdev.class = &iscsi_transport_class; 1428 priv->cdev.class = &iscsi_transport_class;
1312 snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); 1429 snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
@@ -1318,6 +1435,14 @@ iscsi_register_transport(struct iscsi_transport *tt)
1318 if (err) 1435 if (err)
1319 goto unregister_cdev; 1436 goto unregister_cdev;
1320 1437
1438 /* host parameters */
1439 priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
1440 priv->t.host_attrs.ac.class = &iscsi_host_class.class;
1441 priv->t.host_attrs.ac.match = iscsi_host_match;
1442 priv->t.host_size = sizeof(struct iscsi_host);
1443 priv->host_attrs[0] = NULL;
1444 transport_container_register(&priv->t.host_attrs);
1445
1321 /* connection parameters */ 1446 /* connection parameters */
1322 priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; 1447 priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
1323 priv->conn_cont.ac.class = &iscsi_connection_class.class; 1448 priv->conn_cont.ac.class = &iscsi_connection_class.class;
@@ -1361,6 +1486,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1361 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); 1486 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
1362 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); 1487 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
1363 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); 1488 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
1489 SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
1364 1490
1365 if (tt->param_mask & ISCSI_TARGET_NAME) 1491 if (tt->param_mask & ISCSI_TARGET_NAME)
1366 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); 1492 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
@@ -1408,6 +1534,7 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
1408 1534
1409 transport_container_unregister(&priv->conn_cont); 1535 transport_container_unregister(&priv->conn_cont);
1410 transport_container_unregister(&priv->session_cont); 1536 transport_container_unregister(&priv->session_cont);
1537 transport_container_unregister(&priv->t.host_attrs);
1411 1538
1412 sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group); 1539 sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
1413 class_device_unregister(&priv->cdev); 1540 class_device_unregister(&priv->cdev);
@@ -1451,10 +1578,14 @@ static __init int iscsi_transport_init(void)
1451 if (err) 1578 if (err)
1452 return err; 1579 return err;
1453 1580
1454 err = transport_class_register(&iscsi_connection_class); 1581 err = transport_class_register(&iscsi_host_class);
1455 if (err) 1582 if (err)
1456 goto unregister_transport_class; 1583 goto unregister_transport_class;
1457 1584
1585 err = transport_class_register(&iscsi_connection_class);
1586 if (err)
1587 goto unregister_host_class;
1588
1458 err = transport_class_register(&iscsi_session_class); 1589 err = transport_class_register(&iscsi_session_class);
1459 if (err) 1590 if (err)
1460 goto unregister_conn_class; 1591 goto unregister_conn_class;
@@ -1482,6 +1613,8 @@ unregister_session_class:
1482 transport_class_unregister(&iscsi_session_class); 1613 transport_class_unregister(&iscsi_session_class);
1483unregister_conn_class: 1614unregister_conn_class:
1484 transport_class_unregister(&iscsi_connection_class); 1615 transport_class_unregister(&iscsi_connection_class);
1616unregister_host_class:
1617 transport_class_unregister(&iscsi_host_class);
1485unregister_transport_class: 1618unregister_transport_class:
1486 class_unregister(&iscsi_transport_class); 1619 class_unregister(&iscsi_transport_class);
1487 return err; 1620 return err;
@@ -1494,6 +1627,7 @@ static void __exit iscsi_transport_exit(void)
1494 netlink_unregister_notifier(&iscsi_nl_notifier); 1627 netlink_unregister_notifier(&iscsi_nl_notifier);
1495 transport_class_unregister(&iscsi_connection_class); 1628 transport_class_unregister(&iscsi_connection_class);
1496 transport_class_unregister(&iscsi_session_class); 1629 transport_class_unregister(&iscsi_session_class);
1630 transport_class_unregister(&iscsi_host_class);
1497 class_unregister(&iscsi_transport_class); 1631 class_unregister(&iscsi_transport_class);
1498} 1632}
1499 1633