diff options
Diffstat (limited to 'drivers/block/ub.c')
-rw-r--r-- | drivers/block/ub.c | 197 |
1 files changed, 4 insertions, 193 deletions
diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 26aa96eba439..21d0e075c928 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c | |||
@@ -180,6 +180,7 @@ struct ub_dev; | |||
180 | #define UB_DIR_ILLEGAL2 2 | 180 | #define UB_DIR_ILLEGAL2 2 |
181 | #define UB_DIR_WRITE 3 | 181 | #define UB_DIR_WRITE 3 |
182 | 182 | ||
183 | /* P3 */ | ||
183 | #define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ | 184 | #define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ |
184 | (((c)==UB_DIR_READ)? 'r': 'n')) | 185 | (((c)==UB_DIR_READ)? 'r': 'n')) |
185 | 186 | ||
@@ -195,24 +196,11 @@ enum ub_scsi_cmd_state { | |||
195 | UB_CMDST_DONE /* Final state */ | 196 | UB_CMDST_DONE /* Final state */ |
196 | }; | 197 | }; |
197 | 198 | ||
198 | static char *ub_scsi_cmd_stname[] = { | ||
199 | ". ", | ||
200 | "Cmd", | ||
201 | "dat", | ||
202 | "c2s", | ||
203 | "sts", | ||
204 | "clr", | ||
205 | "crs", | ||
206 | "Sen", | ||
207 | "fin" | ||
208 | }; | ||
209 | |||
210 | struct ub_scsi_cmd { | 199 | struct ub_scsi_cmd { |
211 | unsigned char cdb[UB_MAX_CDB_SIZE]; | 200 | unsigned char cdb[UB_MAX_CDB_SIZE]; |
212 | unsigned char cdb_len; | 201 | unsigned char cdb_len; |
213 | 202 | ||
214 | unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ | 203 | unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ |
215 | unsigned char trace_index; | ||
216 | enum ub_scsi_cmd_state state; | 204 | enum ub_scsi_cmd_state state; |
217 | unsigned int tag; | 205 | unsigned int tag; |
218 | struct ub_scsi_cmd *next; | 206 | struct ub_scsi_cmd *next; |
@@ -249,28 +237,6 @@ struct ub_capacity { | |||
249 | }; | 237 | }; |
250 | 238 | ||
251 | /* | 239 | /* |
252 | * The SCSI command tracing structure. | ||
253 | */ | ||
254 | |||
255 | #define SCMD_ST_HIST_SZ 8 | ||
256 | #define SCMD_TRACE_SZ 63 /* Less than 4KB of 61-byte lines */ | ||
257 | |||
258 | struct ub_scsi_cmd_trace { | ||
259 | int hcur; | ||
260 | unsigned int tag; | ||
261 | unsigned int req_size, act_size; | ||
262 | unsigned char op; | ||
263 | unsigned char dir; | ||
264 | unsigned char key, asc, ascq; | ||
265 | char st_hst[SCMD_ST_HIST_SZ]; | ||
266 | }; | ||
267 | |||
268 | struct ub_scsi_trace { | ||
269 | int cur; | ||
270 | struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ]; | ||
271 | }; | ||
272 | |||
273 | /* | ||
274 | * This is a direct take-off from linux/include/completion.h | 240 | * This is a direct take-off from linux/include/completion.h |
275 | * The difference is that I do not wait on this thing, just poll. | 241 | * The difference is that I do not wait on this thing, just poll. |
276 | * When I want to wait (ub_probe), I just use the stock completion. | 242 | * When I want to wait (ub_probe), I just use the stock completion. |
@@ -388,7 +354,6 @@ struct ub_dev { | |||
388 | wait_queue_head_t reset_wait; | 354 | wait_queue_head_t reset_wait; |
389 | 355 | ||
390 | int sg_stat[6]; | 356 | int sg_stat[6]; |
391 | struct ub_scsi_trace tr; | ||
392 | }; | 357 | }; |
393 | 358 | ||
394 | /* | 359 | /* |
@@ -458,137 +423,6 @@ static int ub_qlock_next = 0; | |||
458 | static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */ | 423 | static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */ |
459 | 424 | ||
460 | /* | 425 | /* |
461 | * The SCSI command tracing procedures. | ||
462 | */ | ||
463 | |||
464 | static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | ||
465 | { | ||
466 | int n; | ||
467 | struct ub_scsi_cmd_trace *t; | ||
468 | |||
469 | if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0; | ||
470 | t = &sc->tr.vec[n]; | ||
471 | |||
472 | memset(t, 0, sizeof(struct ub_scsi_cmd_trace)); | ||
473 | t->tag = cmd->tag; | ||
474 | t->op = cmd->cdb[0]; | ||
475 | t->dir = cmd->dir; | ||
476 | t->req_size = cmd->len; | ||
477 | t->st_hst[0] = cmd->state; | ||
478 | |||
479 | sc->tr.cur = n; | ||
480 | cmd->trace_index = n; | ||
481 | } | ||
482 | |||
483 | static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | ||
484 | { | ||
485 | int n; | ||
486 | struct ub_scsi_cmd_trace *t; | ||
487 | |||
488 | t = &sc->tr.vec[cmd->trace_index]; | ||
489 | if (t->tag == cmd->tag) { | ||
490 | if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0; | ||
491 | t->st_hst[n] = cmd->state; | ||
492 | t->hcur = n; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | ||
497 | { | ||
498 | struct ub_scsi_cmd_trace *t; | ||
499 | |||
500 | t = &sc->tr.vec[cmd->trace_index]; | ||
501 | if (t->tag == cmd->tag) | ||
502 | t->act_size = cmd->act_len; | ||
503 | } | ||
504 | |||
505 | static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd, | ||
506 | unsigned char *sense) | ||
507 | { | ||
508 | struct ub_scsi_cmd_trace *t; | ||
509 | |||
510 | t = &sc->tr.vec[cmd->trace_index]; | ||
511 | if (t->tag == cmd->tag) { | ||
512 | t->key = sense[2] & 0x0F; | ||
513 | t->asc = sense[12]; | ||
514 | t->ascq = sense[13]; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, | ||
519 | char *page) | ||
520 | { | ||
521 | struct usb_interface *intf; | ||
522 | struct ub_dev *sc; | ||
523 | struct list_head *p; | ||
524 | struct ub_lun *lun; | ||
525 | int cnt; | ||
526 | unsigned long flags; | ||
527 | int nc, nh; | ||
528 | int i, j; | ||
529 | struct ub_scsi_cmd_trace *t; | ||
530 | |||
531 | intf = to_usb_interface(dev); | ||
532 | sc = usb_get_intfdata(intf); | ||
533 | if (sc == NULL) | ||
534 | return 0; | ||
535 | |||
536 | cnt = 0; | ||
537 | spin_lock_irqsave(sc->lock, flags); | ||
538 | |||
539 | cnt += sprintf(page + cnt, | ||
540 | "poison %d reset %d\n", | ||
541 | atomic_read(&sc->poison), sc->reset); | ||
542 | cnt += sprintf(page + cnt, | ||
543 | "qlen %d qmax %d\n", | ||
544 | sc->cmd_queue.qlen, sc->cmd_queue.qmax); | ||
545 | cnt += sprintf(page + cnt, | ||
546 | "sg %d %d %d %d %d .. %d\n", | ||
547 | sc->sg_stat[0], | ||
548 | sc->sg_stat[1], | ||
549 | sc->sg_stat[2], | ||
550 | sc->sg_stat[3], | ||
551 | sc->sg_stat[4], | ||
552 | sc->sg_stat[5]); | ||
553 | |||
554 | list_for_each (p, &sc->luns) { | ||
555 | lun = list_entry(p, struct ub_lun, link); | ||
556 | cnt += sprintf(page + cnt, | ||
557 | "lun %u changed %d removable %d readonly %d\n", | ||
558 | lun->num, lun->changed, lun->removable, lun->readonly); | ||
559 | } | ||
560 | |||
561 | if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0; | ||
562 | for (j = 0; j < SCMD_TRACE_SZ; j++) { | ||
563 | t = &sc->tr.vec[nc]; | ||
564 | |||
565 | cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op); | ||
566 | if (t->op == REQUEST_SENSE) { | ||
567 | cnt += sprintf(page + cnt, " [sense %x %02x %02x]", | ||
568 | t->key, t->asc, t->ascq); | ||
569 | } else { | ||
570 | cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir)); | ||
571 | cnt += sprintf(page + cnt, " [%5d %5d]", | ||
572 | t->req_size, t->act_size); | ||
573 | } | ||
574 | if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0; | ||
575 | for (i = 0; i < SCMD_ST_HIST_SZ; i++) { | ||
576 | cnt += sprintf(page + cnt, " %s", | ||
577 | ub_scsi_cmd_stname[(int)t->st_hst[nh]]); | ||
578 | if (++nh == SCMD_ST_HIST_SZ) nh = 0; | ||
579 | } | ||
580 | cnt += sprintf(page + cnt, "\n"); | ||
581 | |||
582 | if (++nc == SCMD_TRACE_SZ) nc = 0; | ||
583 | } | ||
584 | |||
585 | spin_unlock_irqrestore(sc->lock, flags); | ||
586 | return cnt; | ||
587 | } | ||
588 | |||
589 | static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */ | ||
590 | |||
591 | /* | ||
592 | * The id allocator. | 426 | * The id allocator. |
593 | * | 427 | * |
594 | * This also stores the host for indexing by minor, which is somewhat dirty. | 428 | * This also stores the host for indexing by minor, which is somewhat dirty. |
@@ -1090,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1090 | add_timer(&sc->work_timer); | 924 | add_timer(&sc->work_timer); |
1091 | 925 | ||
1092 | cmd->state = UB_CMDST_CMD; | 926 | cmd->state = UB_CMDST_CMD; |
1093 | ub_cmdtr_state(sc, cmd); | ||
1094 | return 0; | 927 | return 0; |
1095 | } | 928 | } |
1096 | 929 | ||
@@ -1143,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_dev *sc) | |||
1143 | ub_cmdq_pop(sc); | 976 | ub_cmdq_pop(sc); |
1144 | (*cmd->done)(sc, cmd); | 977 | (*cmd->done)(sc, cmd); |
1145 | } else if (cmd->state == UB_CMDST_INIT) { | 978 | } else if (cmd->state == UB_CMDST_INIT) { |
1146 | ub_cmdtr_new(sc, cmd); | ||
1147 | if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) | 979 | if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) |
1148 | break; | 980 | break; |
1149 | cmd->error = rc; | 981 | cmd->error = rc; |
1150 | cmd->state = UB_CMDST_DONE; | 982 | cmd->state = UB_CMDST_DONE; |
1151 | ub_cmdtr_state(sc, cmd); | ||
1152 | } else { | 983 | } else { |
1153 | if (!ub_is_completed(&sc->work_done)) | 984 | if (!ub_is_completed(&sc->work_done)) |
1154 | break; | 985 | break; |
@@ -1245,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1245 | return; | 1076 | return; |
1246 | } | 1077 | } |
1247 | cmd->state = UB_CMDST_CLEAR; | 1078 | cmd->state = UB_CMDST_CLEAR; |
1248 | ub_cmdtr_state(sc, cmd); | ||
1249 | return; | 1079 | return; |
1250 | case -ESHUTDOWN: /* unplug */ | 1080 | case -ESHUTDOWN: /* unplug */ |
1251 | case -EILSEQ: /* unplug timeout on uhci */ | 1081 | case -EILSEQ: /* unplug timeout on uhci */ |
@@ -1277,7 +1107,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1277 | return; | 1107 | return; |
1278 | } | 1108 | } |
1279 | cmd->state = UB_CMDST_CLR2STS; | 1109 | cmd->state = UB_CMDST_CLR2STS; |
1280 | ub_cmdtr_state(sc, cmd); | ||
1281 | return; | 1110 | return; |
1282 | } | 1111 | } |
1283 | if (urb->status == -EOVERFLOW) { | 1112 | if (urb->status == -EOVERFLOW) { |
@@ -1302,7 +1131,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1302 | if (urb->status != 0 || | 1131 | if (urb->status != 0 || |
1303 | len != cmd->sgv[cmd->current_sg].length) { | 1132 | len != cmd->sgv[cmd->current_sg].length) { |
1304 | cmd->act_len += len; | 1133 | cmd->act_len += len; |
1305 | ub_cmdtr_act_len(sc, cmd); | ||
1306 | 1134 | ||
1307 | cmd->error = -EIO; | 1135 | cmd->error = -EIO; |
1308 | ub_state_stat(sc, cmd); | 1136 | ub_state_stat(sc, cmd); |
@@ -1329,7 +1157,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1329 | } | 1157 | } |
1330 | 1158 | ||
1331 | cmd->act_len += urb->actual_length; | 1159 | cmd->act_len += urb->actual_length; |
1332 | ub_cmdtr_act_len(sc, cmd); | ||
1333 | 1160 | ||
1334 | if (++cmd->current_sg < cmd->nsg) { | 1161 | if (++cmd->current_sg < cmd->nsg) { |
1335 | ub_data_start(sc, cmd); | 1162 | ub_data_start(sc, cmd); |
@@ -1355,7 +1182,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1355 | cmd->error = -EIO; /* A cheap trick... */ | 1182 | cmd->error = -EIO; /* A cheap trick... */ |
1356 | 1183 | ||
1357 | cmd->state = UB_CMDST_CLRRS; | 1184 | cmd->state = UB_CMDST_CLRRS; |
1358 | ub_cmdtr_state(sc, cmd); | ||
1359 | return; | 1185 | return; |
1360 | } | 1186 | } |
1361 | 1187 | ||
@@ -1439,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1439 | return; | 1265 | return; |
1440 | } | 1266 | } |
1441 | cmd->state = UB_CMDST_DONE; | 1267 | cmd->state = UB_CMDST_DONE; |
1442 | ub_cmdtr_state(sc, cmd); | ||
1443 | ub_cmdq_pop(sc); | 1268 | ub_cmdq_pop(sc); |
1444 | (*cmd->done)(sc, cmd); | 1269 | (*cmd->done)(sc, cmd); |
1445 | 1270 | ||
@@ -1494,7 +1319,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1494 | add_timer(&sc->work_timer); | 1319 | add_timer(&sc->work_timer); |
1495 | 1320 | ||
1496 | cmd->state = UB_CMDST_DATA; | 1321 | cmd->state = UB_CMDST_DATA; |
1497 | ub_cmdtr_state(sc, cmd); | ||
1498 | } | 1322 | } |
1499 | 1323 | ||
1500 | /* | 1324 | /* |
@@ -1506,7 +1330,6 @@ static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) | |||
1506 | 1330 | ||
1507 | cmd->error = rc; | 1331 | cmd->error = rc; |
1508 | cmd->state = UB_CMDST_DONE; | 1332 | cmd->state = UB_CMDST_DONE; |
1509 | ub_cmdtr_state(sc, cmd); | ||
1510 | ub_cmdq_pop(sc); | 1333 | ub_cmdq_pop(sc); |
1511 | (*cmd->done)(sc, cmd); | 1334 | (*cmd->done)(sc, cmd); |
1512 | } | 1335 | } |
@@ -1552,7 +1375,6 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1552 | 1375 | ||
1553 | cmd->stat_count = 0; | 1376 | cmd->stat_count = 0; |
1554 | cmd->state = UB_CMDST_STAT; | 1377 | cmd->state = UB_CMDST_STAT; |
1555 | ub_cmdtr_state(sc, cmd); | ||
1556 | } | 1378 | } |
1557 | 1379 | ||
1558 | /* | 1380 | /* |
@@ -1571,7 +1393,6 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1571 | return; | 1393 | return; |
1572 | 1394 | ||
1573 | cmd->state = UB_CMDST_STAT; | 1395 | cmd->state = UB_CMDST_STAT; |
1574 | ub_cmdtr_state(sc, cmd); | ||
1575 | } | 1396 | } |
1576 | 1397 | ||
1577 | /* | 1398 | /* |
@@ -1609,7 +1430,6 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
1609 | scmd->tag = sc->tagcnt++; | 1430 | scmd->tag = sc->tagcnt++; |
1610 | 1431 | ||
1611 | cmd->state = UB_CMDST_SENSE; | 1432 | cmd->state = UB_CMDST_SENSE; |
1612 | ub_cmdtr_state(sc, cmd); | ||
1613 | 1433 | ||
1614 | ub_cmdq_insert(sc, scmd); | 1434 | ub_cmdq_insert(sc, scmd); |
1615 | return; | 1435 | return; |
@@ -1666,11 +1486,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) | |||
1666 | struct ub_scsi_cmd *cmd; | 1486 | struct ub_scsi_cmd *cmd; |
1667 | 1487 | ||
1668 | /* | 1488 | /* |
1669 | * Ignoring scmd->act_len, because the buffer was pre-zeroed. | ||
1670 | */ | ||
1671 | ub_cmdtr_sense(sc, scmd, sense); | ||
1672 | |||
1673 | /* | ||
1674 | * Find the command which triggered the unit attention or a check, | 1489 | * Find the command which triggered the unit attention or a check, |
1675 | * save the sense into it, and advance its state machine. | 1490 | * save the sense into it, and advance its state machine. |
1676 | */ | 1491 | */ |
@@ -1691,6 +1506,9 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) | |||
1691 | return; | 1506 | return; |
1692 | } | 1507 | } |
1693 | 1508 | ||
1509 | /* | ||
1510 | * Ignoring scmd->act_len, because the buffer was pre-zeroed. | ||
1511 | */ | ||
1694 | cmd->key = sense[2] & 0x0F; | 1512 | cmd->key = sense[2] & 0x0F; |
1695 | cmd->asc = sense[12]; | 1513 | cmd->asc = sense[12]; |
1696 | cmd->ascq = sense[13]; | 1514 | cmd->ascq = sense[13]; |
@@ -2413,9 +2231,6 @@ static int ub_probe(struct usb_interface *intf, | |||
2413 | if (ub_get_pipes(sc, sc->dev, intf) != 0) | 2231 | if (ub_get_pipes(sc, sc->dev, intf) != 0) |
2414 | goto err_dev_desc; | 2232 | goto err_dev_desc; |
2415 | 2233 | ||
2416 | if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0) | ||
2417 | goto err_diag; | ||
2418 | |||
2419 | /* | 2234 | /* |
2420 | * At this point, all USB initialization is done, do upper layer. | 2235 | * At this point, all USB initialization is done, do upper layer. |
2421 | * We really hate halfway initialized structures, so from the | 2236 | * We really hate halfway initialized structures, so from the |
@@ -2480,8 +2295,6 @@ static int ub_probe(struct usb_interface *intf, | |||
2480 | } | 2295 | } |
2481 | return 0; | 2296 | return 0; |
2482 | 2297 | ||
2483 | /* device_remove_file(&sc->intf->dev, &dev_attr_diag); */ | ||
2484 | err_diag: | ||
2485 | err_dev_desc: | 2298 | err_dev_desc: |
2486 | usb_set_intfdata(intf, NULL); | 2299 | usb_set_intfdata(intf, NULL); |
2487 | // usb_put_intf(sc->intf); | 2300 | // usb_put_intf(sc->intf); |
@@ -2609,7 +2422,6 @@ static void ub_disconnect(struct usb_interface *intf) | |||
2609 | while ((cmd = ub_cmdq_peek(sc)) != NULL) { | 2422 | while ((cmd = ub_cmdq_peek(sc)) != NULL) { |
2610 | cmd->error = -ENOTCONN; | 2423 | cmd->error = -ENOTCONN; |
2611 | cmd->state = UB_CMDST_DONE; | 2424 | cmd->state = UB_CMDST_DONE; |
2612 | ub_cmdtr_state(sc, cmd); | ||
2613 | ub_cmdq_pop(sc); | 2425 | ub_cmdq_pop(sc); |
2614 | (*cmd->done)(sc, cmd); | 2426 | (*cmd->done)(sc, cmd); |
2615 | cnt++; | 2427 | cnt++; |
@@ -2660,7 +2472,6 @@ static void ub_disconnect(struct usb_interface *intf) | |||
2660 | * and no URBs left in transit. | 2472 | * and no URBs left in transit. |
2661 | */ | 2473 | */ |
2662 | 2474 | ||
2663 | device_remove_file(&sc->intf->dev, &dev_attr_diag); | ||
2664 | usb_set_intfdata(intf, NULL); | 2475 | usb_set_intfdata(intf, NULL); |
2665 | // usb_put_intf(sc->intf); | 2476 | // usb_put_intf(sc->intf); |
2666 | sc->intf = NULL; | 2477 | sc->intf = NULL; |