diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/advansys.c | 504 |
1 files changed, 6 insertions, 498 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 90f05c52be7e..67cdfe6201ce 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -63,11 +63,10 @@ | |||
63 | * has not occurred then print a message and run in polled mode. | 63 | * has not occurred then print a message and run in polled mode. |
64 | * 4. Need to add support for target mode commands, cf. CAM XPT. | 64 | * 4. Need to add support for target mode commands, cf. CAM XPT. |
65 | * 5. check DMA mapping functions for failure | 65 | * 5. check DMA mapping functions for failure |
66 | * 6. Remove internal queueing | 66 | * 6. Use scsi_transport_spi |
67 | * 7. Use scsi_transport_spi | 67 | * 7. advansys_info is not safe against multiple simultaneous callers |
68 | * 8. advansys_info is not safe against multiple simultaneous callers | 68 | * 8. Kill boardp->id |
69 | * 9. Kill boardp->id | 69 | * 9. Add module_param to override ISA/VLB ioport array |
70 | * 10. Add module_param to override ISA/VLB ioport array | ||
71 | */ | 70 | */ |
72 | #warning this driver is still not properly converted to the DMA API | 71 | #warning this driver is still not properly converted to the DMA API |
73 | 72 | ||
@@ -2514,64 +2513,6 @@ do { \ | |||
2514 | #define HOST_BYTE(byte) ((byte) << 16) | 2513 | #define HOST_BYTE(byte) ((byte) << 16) |
2515 | #define DRIVER_BYTE(byte) ((byte) << 24) | 2514 | #define DRIVER_BYTE(byte) ((byte) << 24) |
2516 | 2515 | ||
2517 | /* | ||
2518 | * The following definitions and macros are OS independent interfaces to | ||
2519 | * the queue functions: | ||
2520 | * REQ - SCSI request structure | ||
2521 | * REQP - pointer to SCSI request structure | ||
2522 | * REQPTID(reqp) - reqp's target id | ||
2523 | * REQPNEXT(reqp) - reqp's next pointer | ||
2524 | * REQPNEXTP(reqp) - pointer to reqp's next pointer | ||
2525 | * REQPTIME(reqp) - reqp's time stamp value | ||
2526 | * REQTIMESTAMP() - system time stamp value | ||
2527 | */ | ||
2528 | typedef struct scsi_cmnd REQ, *REQP; | ||
2529 | #define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) | ||
2530 | #define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) | ||
2531 | #define REQPTID(reqp) ((reqp)->device->id) | ||
2532 | #define REQPTIME(reqp) ((reqp)->SCp.this_residual) | ||
2533 | #define REQTIMESTAMP() (jiffies) | ||
2534 | |||
2535 | #define REQTIMESTAT(function, ascq, reqp, tid) \ | ||
2536 | { \ | ||
2537 | /* | ||
2538 | * If the request time stamp is less than the system time stamp, then \ | ||
2539 | * maybe the system time stamp wrapped. Set the request time to zero.\ | ||
2540 | */ \ | ||
2541 | if (REQPTIME(reqp) <= REQTIMESTAMP()) { \ | ||
2542 | REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \ | ||
2543 | } else { \ | ||
2544 | /* Indicate an error occurred with the assertion. */ \ | ||
2545 | ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \ | ||
2546 | REQPTIME(reqp) = 0; \ | ||
2547 | } \ | ||
2548 | /* Handle first minimum time case without external initialization. */ \ | ||
2549 | if (((ascq)->q_tot_cnt[tid] == 1) || \ | ||
2550 | (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \ | ||
2551 | (ascq)->q_min_tim[tid] = REQPTIME(reqp); \ | ||
2552 | ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \ | ||
2553 | (function), (tid), (ascq)->q_min_tim[tid]); \ | ||
2554 | } \ | ||
2555 | if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \ | ||
2556 | (ascq)->q_max_tim[tid] = REQPTIME(reqp); \ | ||
2557 | ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \ | ||
2558 | (function), tid, (ascq)->q_max_tim[tid]); \ | ||
2559 | } \ | ||
2560 | (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \ | ||
2561 | /* Reset the time stamp field. */ \ | ||
2562 | REQPTIME(reqp) = 0; \ | ||
2563 | } | ||
2564 | |||
2565 | /* asc_enqueue() flags */ | ||
2566 | #define ASC_FRONT 1 | ||
2567 | #define ASC_BACK 2 | ||
2568 | |||
2569 | /* asc_dequeue_list() argument */ | ||
2570 | #define ASC_TID_ALL (-1) | ||
2571 | |||
2572 | /* Return non-zero, if the queue is empty. */ | ||
2573 | #define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0) | ||
2574 | |||
2575 | #ifndef ADVANSYS_STATS | 2516 | #ifndef ADVANSYS_STATS |
2576 | #define ASC_STATS(shost, counter) | 2517 | #define ASC_STATS(shost, counter) |
2577 | #define ASC_STATS_ADD(shost, counter, count) | 2518 | #define ASC_STATS_ADD(shost, counter, count) |
@@ -2784,23 +2725,6 @@ struct asc_stats { | |||
2784 | #endif /* ADVANSYS_STATS */ | 2725 | #endif /* ADVANSYS_STATS */ |
2785 | 2726 | ||
2786 | /* | 2727 | /* |
2787 | * Request queuing structure | ||
2788 | */ | ||
2789 | typedef struct asc_queue { | ||
2790 | ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */ | ||
2791 | REQP q_first[ADV_MAX_TID + 1]; /* first queued request */ | ||
2792 | REQP q_last[ADV_MAX_TID + 1]; /* last queued request */ | ||
2793 | #ifdef ADVANSYS_STATS | ||
2794 | short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */ | ||
2795 | short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */ | ||
2796 | ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */ | ||
2797 | ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */ | ||
2798 | ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */ | ||
2799 | ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */ | ||
2800 | #endif /* ADVANSYS_STATS */ | ||
2801 | } asc_queue_t; | ||
2802 | |||
2803 | /* | ||
2804 | * Adv Library Request Structures | 2728 | * Adv Library Request Structures |
2805 | * | 2729 | * |
2806 | * The following two structures are used to process Wide Board requests. | 2730 | * The following two structures are used to process Wide Board requests. |
@@ -2851,7 +2775,6 @@ typedef struct asc_board { | |||
2851 | ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ | 2775 | ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ |
2852 | } dvc_cfg; | 2776 | } dvc_cfg; |
2853 | ushort asc_n_io_port; /* Number I/O ports. */ | 2777 | ushort asc_n_io_port; /* Number I/O ports. */ |
2854 | asc_queue_t active; /* Active command queue */ | ||
2855 | ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ | 2778 | ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ |
2856 | struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */ | 2779 | struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */ |
2857 | ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */ | 2780 | ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */ |
@@ -2914,14 +2837,10 @@ static int asc_dbglvl = 3; | |||
2914 | */ | 2837 | */ |
2915 | 2838 | ||
2916 | static int advansys_slave_configure(struct scsi_device *); | 2839 | static int advansys_slave_configure(struct scsi_device *); |
2917 | static void asc_scsi_done_list(struct scsi_cmnd *); | ||
2918 | static int asc_execute_scsi_cmnd(struct scsi_cmnd *); | 2840 | static int asc_execute_scsi_cmnd(struct scsi_cmnd *); |
2919 | static int asc_build_req(asc_board_t *, struct scsi_cmnd *); | 2841 | static int asc_build_req(asc_board_t *, struct scsi_cmnd *); |
2920 | static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **); | 2842 | static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **); |
2921 | static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int); | 2843 | static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int); |
2922 | static void asc_enqueue(asc_queue_t *, REQP, int); | ||
2923 | static REQP asc_dequeue_list(asc_queue_t *, REQP *, int); | ||
2924 | static int asc_rmqueue(asc_queue_t *, REQP); | ||
2925 | #ifdef CONFIG_PROC_FS | 2844 | #ifdef CONFIG_PROC_FS |
2926 | static int asc_proc_copy(off_t, off_t, char *, int, char *, int); | 2845 | static int asc_proc_copy(off_t, off_t, char *, int, char *, int); |
2927 | static int asc_prt_board_devices(struct Scsi_Host *, char *, int); | 2846 | static int asc_prt_board_devices(struct Scsi_Host *, char *, int); |
@@ -2939,7 +2858,6 @@ static int asc_prt_line(char *, int, char *fmt, ...); | |||
2939 | #ifdef ADVANSYS_STATS | 2858 | #ifdef ADVANSYS_STATS |
2940 | #ifdef CONFIG_PROC_FS | 2859 | #ifdef CONFIG_PROC_FS |
2941 | static int asc_prt_board_stats(struct Scsi_Host *, char *, int); | 2860 | static int asc_prt_board_stats(struct Scsi_Host *, char *, int); |
2942 | static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int); | ||
2943 | #endif /* CONFIG_PROC_FS */ | 2861 | #endif /* CONFIG_PROC_FS */ |
2944 | #endif /* ADVANSYS_STATS */ | 2862 | #endif /* ADVANSYS_STATS */ |
2945 | 2863 | ||
@@ -2991,9 +2909,6 @@ advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, | |||
2991 | int leftlen; | 2909 | int leftlen; |
2992 | char *curbuf; | 2910 | char *curbuf; |
2993 | off_t advoffset; | 2911 | off_t advoffset; |
2994 | #ifdef ADVANSYS_STATS | ||
2995 | int tgt_id; | ||
2996 | #endif /* ADVANSYS_STATS */ | ||
2997 | 2912 | ||
2998 | ASC_DBG(1, "advansys_proc_info: begin\n"); | 2913 | ASC_DBG(1, "advansys_proc_info: begin\n"); |
2999 | 2914 | ||
@@ -3123,26 +3038,6 @@ advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, | |||
3123 | } | 3038 | } |
3124 | advoffset += cplen; | 3039 | advoffset += cplen; |
3125 | curbuf += cnt; | 3040 | curbuf += cnt; |
3126 | |||
3127 | /* | ||
3128 | * Display driver statistics for each target. | ||
3129 | */ | ||
3130 | for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) { | ||
3131 | cp = boardp->prtbuf; | ||
3132 | cplen = asc_prt_target_stats(shost, tgt_id, cp, | ||
3133 | ASC_PRTBUF_SIZE); | ||
3134 | ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); | ||
3135 | cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, | ||
3136 | cplen); | ||
3137 | totcnt += cnt; | ||
3138 | leftlen -= cnt; | ||
3139 | if (leftlen == 0) { | ||
3140 | ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); | ||
3141 | return totcnt; | ||
3142 | } | ||
3143 | advoffset += cplen; | ||
3144 | curbuf += cnt; | ||
3145 | } | ||
3146 | #endif /* ADVANSYS_STATS */ | 3041 | #endif /* ADVANSYS_STATS */ |
3147 | 3042 | ||
3148 | /* | 3043 | /* |
@@ -3331,8 +3226,6 @@ static int advansys_reset(struct scsi_cmnd *scp) | |||
3331 | ASC_DVC_VAR *asc_dvc_varp; | 3226 | ASC_DVC_VAR *asc_dvc_varp; |
3332 | ADV_DVC_VAR *adv_dvc_varp; | 3227 | ADV_DVC_VAR *adv_dvc_varp; |
3333 | ulong flags; | 3228 | ulong flags; |
3334 | struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; | ||
3335 | struct scsi_cmnd *tscp, *new_last_scp; | ||
3336 | int status; | 3229 | int status; |
3337 | int ret = SUCCESS; | 3230 | int ret = SUCCESS; |
3338 | 3231 | ||
@@ -3423,34 +3316,6 @@ static int advansys_reset(struct scsi_cmnd *scp) | |||
3423 | } | 3316 | } |
3424 | /* Board lock is held. */ | 3317 | /* Board lock is held. */ |
3425 | 3318 | ||
3426 | /* | ||
3427 | * Dequeue all board 'active' requests for all devices and set | ||
3428 | * the request status to DID_RESET. A pointer to the last request | ||
3429 | * is returned in 'last_scp'. | ||
3430 | */ | ||
3431 | if (done_scp == NULL) { | ||
3432 | done_scp = asc_dequeue_list(&boardp->active, &last_scp, | ||
3433 | ASC_TID_ALL); | ||
3434 | for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { | ||
3435 | tscp->result = HOST_BYTE(DID_RESET); | ||
3436 | } | ||
3437 | } else { | ||
3438 | /* Append to 'done_scp' at the end with 'last_scp'. */ | ||
3439 | ASC_ASSERT(last_scp != NULL); | ||
3440 | last_scp->host_scribble = | ||
3441 | (unsigned char *)asc_dequeue_list(&boardp->active, | ||
3442 | &new_last_scp, | ||
3443 | ASC_TID_ALL); | ||
3444 | if (new_last_scp != NULL) { | ||
3445 | ASC_ASSERT(REQPNEXT(last_scp) != NULL); | ||
3446 | for (tscp = REQPNEXT(last_scp); tscp; | ||
3447 | tscp = REQPNEXT(tscp)) { | ||
3448 | tscp->result = HOST_BYTE(DID_RESET); | ||
3449 | } | ||
3450 | last_scp = new_last_scp; | ||
3451 | } | ||
3452 | } | ||
3453 | |||
3454 | /* Save the time of the most recently completed reset. */ | 3319 | /* Save the time of the most recently completed reset. */ |
3455 | boardp->last_reset = jiffies; | 3320 | boardp->last_reset = jiffies; |
3456 | 3321 | ||
@@ -3458,12 +3323,6 @@ static int advansys_reset(struct scsi_cmnd *scp) | |||
3458 | boardp->flags &= ~ASC_HOST_IN_RESET; | 3323 | boardp->flags &= ~ASC_HOST_IN_RESET; |
3459 | spin_unlock_irqrestore(&boardp->lock, flags); | 3324 | spin_unlock_irqrestore(&boardp->lock, flags); |
3460 | 3325 | ||
3461 | /* | ||
3462 | * Complete all the 'done_scp' requests. | ||
3463 | */ | ||
3464 | if (done_scp) | ||
3465 | asc_scsi_done_list(done_scp); | ||
3466 | |||
3467 | ASC_DBG1(1, "advansys_reset: ret %d\n", ret); | 3326 | ASC_DBG1(1, "advansys_reset: ret %d\n", ret); |
3468 | 3327 | ||
3469 | return ret; | 3328 | return ret; |
@@ -3795,30 +3654,6 @@ static int advansys_slave_configure(struct scsi_device *sdev) | |||
3795 | } | 3654 | } |
3796 | 3655 | ||
3797 | /* | 3656 | /* |
3798 | * Complete all requests on the singly linked list pointed | ||
3799 | * to by 'scp'. | ||
3800 | * | ||
3801 | * Interrupts can be enabled on entry. | ||
3802 | */ | ||
3803 | static void asc_scsi_done_list(struct scsi_cmnd *scp) | ||
3804 | { | ||
3805 | struct scsi_cmnd *tscp; | ||
3806 | |||
3807 | ASC_DBG(2, "asc_scsi_done_list: begin\n"); | ||
3808 | while (scp != NULL) { | ||
3809 | ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp); | ||
3810 | tscp = REQPNEXT(scp); | ||
3811 | scp->host_scribble = NULL; | ||
3812 | |||
3813 | asc_scsi_done(scp); | ||
3814 | |||
3815 | scp = tscp; | ||
3816 | } | ||
3817 | ASC_DBG(2, "asc_scsi_done_list: done\n"); | ||
3818 | return; | ||
3819 | } | ||
3820 | |||
3821 | /* | ||
3822 | * Execute a single 'Scsi_Cmnd'. | 3657 | * Execute a single 'Scsi_Cmnd'. |
3823 | * | 3658 | * |
3824 | * The function 'done' is called when the request has been completed. | 3659 | * The function 'done' is called when the request has been completed. |
@@ -3854,9 +3689,8 @@ static void asc_scsi_done_list(struct scsi_cmnd *scp) | |||
3854 | * scsi_done - used to save caller's done function | 3689 | * scsi_done - used to save caller's done function |
3855 | * host_scribble - used for pointer to another struct scsi_cmnd | 3690 | * host_scribble - used for pointer to another struct scsi_cmnd |
3856 | * | 3691 | * |
3857 | * If this function returns ASC_NOERROR the request has been enqueued | 3692 | * If this function returns ASC_NOERROR the request will be completed |
3858 | * on the board's 'active' queue and will be completed from the | 3693 | * from the interrupt handler. |
3859 | * interrupt handler. | ||
3860 | * | 3694 | * |
3861 | * If this function returns ASC_ERROR the host error code has been set, | 3695 | * If this function returns ASC_ERROR the host error code has been set, |
3862 | * and the called must call asc_scsi_done. | 3696 | * and the called must call asc_scsi_done. |
@@ -3901,10 +3735,6 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) | |||
3901 | return ASC_ERROR; | 3735 | return ASC_ERROR; |
3902 | } | 3736 | } |
3903 | 3737 | ||
3904 | /* | ||
3905 | * Execute the command. If there is no error, add the command | ||
3906 | * to the active queue. | ||
3907 | */ | ||
3908 | switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { | 3738 | switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { |
3909 | case ASC_NOERROR: | 3739 | case ASC_NOERROR: |
3910 | ASC_STATS(scp->device->host, exe_noerror); | 3740 | ASC_STATS(scp->device->host, exe_noerror); |
@@ -3913,7 +3743,6 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) | |||
3913 | * successful request counter. Wrapping doesn't matter. | 3743 | * successful request counter. Wrapping doesn't matter. |
3914 | */ | 3744 | */ |
3915 | boardp->reqcnt[scp->device->id]++; | 3745 | boardp->reqcnt[scp->device->id]++; |
3916 | asc_enqueue(&boardp->active, scp, ASC_BACK); | ||
3917 | ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), " | 3746 | ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), " |
3918 | "ASC_NOERROR\n"); | 3747 | "ASC_NOERROR\n"); |
3919 | break; | 3748 | break; |
@@ -3970,10 +3799,6 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) | |||
3970 | return ASC_ERROR; | 3799 | return ASC_ERROR; |
3971 | } | 3800 | } |
3972 | 3801 | ||
3973 | /* | ||
3974 | * Execute the command. If there is no error, add the command | ||
3975 | * to the active queue. | ||
3976 | */ | ||
3977 | switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) { | 3802 | switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) { |
3978 | case ASC_NOERROR: | 3803 | case ASC_NOERROR: |
3979 | ASC_STATS(scp->device->host, exe_noerror); | 3804 | ASC_STATS(scp->device->host, exe_noerror); |
@@ -3982,7 +3807,6 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) | |||
3982 | * successful request counter. Wrapping doesn't matter. | 3807 | * successful request counter. Wrapping doesn't matter. |
3983 | */ | 3808 | */ |
3984 | boardp->reqcnt[scp->device->id]++; | 3809 | boardp->reqcnt[scp->device->id]++; |
3985 | asc_enqueue(&boardp->active, scp, ASC_BACK); | ||
3986 | ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), " | 3810 | ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), " |
3987 | "ASC_NOERROR\n"); | 3811 | "ASC_NOERROR\n"); |
3988 | break; | 3812 | break; |
@@ -4467,19 +4291,8 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) | |||
4467 | ASC_STATS(shost, callback); | 4291 | ASC_STATS(shost, callback); |
4468 | ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost); | 4292 | ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost); |
4469 | 4293 | ||
4470 | /* | ||
4471 | * If the request isn't found on the active queue, it may | ||
4472 | * have been removed to handle a reset request. | ||
4473 | * Display a message and return. | ||
4474 | */ | ||
4475 | boardp = ASC_BOARDP(shost); | 4294 | boardp = ASC_BOARDP(shost); |
4476 | ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var); | 4295 | ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var); |
4477 | if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { | ||
4478 | ASC_PRINT2 | ||
4479 | ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n", | ||
4480 | boardp->id, (ulong)scp); | ||
4481 | return; | ||
4482 | } | ||
4483 | 4296 | ||
4484 | /* | 4297 | /* |
4485 | * 'qdonep' contains the command's ending status. | 4298 | * 'qdonep' contains the command's ending status. |
@@ -4624,21 +4437,8 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) | |||
4624 | ASC_STATS(shost, callback); | 4437 | ASC_STATS(shost, callback); |
4625 | ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost); | 4438 | ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost); |
4626 | 4439 | ||
4627 | /* | ||
4628 | * If the request isn't found on the active queue, it may have been | ||
4629 | * removed to handle a reset request. Display a message and return. | ||
4630 | * | ||
4631 | * Note: Because the structure may still be in use don't attempt | ||
4632 | * to free the adv_req_t and adv_sgblk_t, if any, structures. | ||
4633 | */ | ||
4634 | boardp = ASC_BOARDP(shost); | 4440 | boardp = ASC_BOARDP(shost); |
4635 | ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var); | 4441 | ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var); |
4636 | if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { | ||
4637 | ASC_PRINT2 | ||
4638 | ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n", | ||
4639 | boardp->id, (ulong)scp); | ||
4640 | return; | ||
4641 | } | ||
4642 | 4442 | ||
4643 | /* | 4443 | /* |
4644 | * 'done_status' contains the command's ending status. | 4444 | * 'done_status' contains the command's ending status. |
@@ -4787,225 +4587,6 @@ static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) | |||
4787 | } | 4587 | } |
4788 | } | 4588 | } |
4789 | 4589 | ||
4790 | /* | ||
4791 | * Add a 'REQP' to the end of specified queue. Set 'tidmask' | ||
4792 | * to indicate a command is queued for the device. | ||
4793 | * | ||
4794 | * 'flag' may be either ASC_FRONT or ASC_BACK. | ||
4795 | * | ||
4796 | * 'REQPNEXT(reqp)' returns reqp's next pointer. | ||
4797 | */ | ||
4798 | static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag) | ||
4799 | { | ||
4800 | int tid; | ||
4801 | |||
4802 | ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n", | ||
4803 | (ulong)ascq, (ulong)reqp, flag); | ||
4804 | ASC_ASSERT(reqp != NULL); | ||
4805 | ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); | ||
4806 | tid = REQPTID(reqp); | ||
4807 | ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); | ||
4808 | if (flag == ASC_FRONT) { | ||
4809 | reqp->host_scribble = (unsigned char *)ascq->q_first[tid]; | ||
4810 | ascq->q_first[tid] = reqp; | ||
4811 | /* If the queue was empty, set the last pointer. */ | ||
4812 | if (ascq->q_last[tid] == NULL) { | ||
4813 | ascq->q_last[tid] = reqp; | ||
4814 | } | ||
4815 | } else { /* ASC_BACK */ | ||
4816 | if (ascq->q_last[tid] != NULL) { | ||
4817 | ascq->q_last[tid]->host_scribble = | ||
4818 | (unsigned char *)reqp; | ||
4819 | } | ||
4820 | ascq->q_last[tid] = reqp; | ||
4821 | reqp->host_scribble = NULL; | ||
4822 | /* If the queue was empty, set the first pointer. */ | ||
4823 | if (ascq->q_first[tid] == NULL) { | ||
4824 | ascq->q_first[tid] = reqp; | ||
4825 | } | ||
4826 | } | ||
4827 | /* The queue has at least one entry, set its bit. */ | ||
4828 | ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid); | ||
4829 | #ifdef ADVANSYS_STATS | ||
4830 | /* Maintain request queue statistics. */ | ||
4831 | ascq->q_tot_cnt[tid]++; | ||
4832 | ascq->q_cur_cnt[tid]++; | ||
4833 | if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) { | ||
4834 | ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid]; | ||
4835 | ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n", | ||
4836 | tid, ascq->q_max_cnt[tid]); | ||
4837 | } | ||
4838 | REQPTIME(reqp) = REQTIMESTAMP(); | ||
4839 | #endif /* ADVANSYS_STATS */ | ||
4840 | ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp); | ||
4841 | return; | ||
4842 | } | ||
4843 | |||
4844 | /* | ||
4845 | * Return a pointer to a singly linked list of all the requests queued | ||
4846 | * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. | ||
4847 | * | ||
4848 | * If 'lastpp' is not NULL, '*lastpp' will be set to point to the | ||
4849 | * the last request returned in the singly linked list. | ||
4850 | * | ||
4851 | * 'tid' should either be a valid target id or if it is ASC_TID_ALL, | ||
4852 | * then all queued requests are concatenated into one list and | ||
4853 | * returned. | ||
4854 | * | ||
4855 | * Note: If 'lastpp' is used to append a new list to the end of | ||
4856 | * an old list, only change the old list last pointer if '*lastpp' | ||
4857 | * (or the function return value) is not NULL, i.e. use a temporary | ||
4858 | * variable for 'lastpp' and check its value after the function return | ||
4859 | * before assigning it to the list last pointer. | ||
4860 | * | ||
4861 | * Unfortunately collecting queuing time statistics adds overhead to | ||
4862 | * the function that isn't inherent to the function's algorithm. | ||
4863 | */ | ||
4864 | static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid) | ||
4865 | { | ||
4866 | REQP firstp, lastp; | ||
4867 | int i; | ||
4868 | |||
4869 | ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid); | ||
4870 | ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); | ||
4871 | |||
4872 | /* | ||
4873 | * If 'tid' is not ASC_TID_ALL, return requests only for | ||
4874 | * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all | ||
4875 | * requests for all tids. | ||
4876 | */ | ||
4877 | if (tid != ASC_TID_ALL) { | ||
4878 | /* Return all requests for the specified 'tid'. */ | ||
4879 | if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) { | ||
4880 | /* List is empty; Set first and last return pointers to NULL. */ | ||
4881 | firstp = lastp = NULL; | ||
4882 | } else { | ||
4883 | firstp = ascq->q_first[tid]; | ||
4884 | lastp = ascq->q_last[tid]; | ||
4885 | ascq->q_first[tid] = ascq->q_last[tid] = NULL; | ||
4886 | ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); | ||
4887 | #ifdef ADVANSYS_STATS | ||
4888 | { | ||
4889 | REQP reqp; | ||
4890 | ascq->q_cur_cnt[tid] = 0; | ||
4891 | for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { | ||
4892 | REQTIMESTAT("asc_dequeue_list", ascq, | ||
4893 | reqp, tid); | ||
4894 | } | ||
4895 | } | ||
4896 | #endif /* ADVANSYS_STATS */ | ||
4897 | } | ||
4898 | } else { | ||
4899 | /* Return all requests for all tids. */ | ||
4900 | firstp = lastp = NULL; | ||
4901 | for (i = 0; i <= ADV_MAX_TID; i++) { | ||
4902 | if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) { | ||
4903 | if (firstp == NULL) { | ||
4904 | firstp = ascq->q_first[i]; | ||
4905 | lastp = ascq->q_last[i]; | ||
4906 | } else { | ||
4907 | ASC_ASSERT(lastp != NULL); | ||
4908 | lastp->host_scribble = | ||
4909 | (unsigned char *)ascq->q_first[i]; | ||
4910 | lastp = ascq->q_last[i]; | ||
4911 | } | ||
4912 | ascq->q_first[i] = ascq->q_last[i] = NULL; | ||
4913 | ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i); | ||
4914 | #ifdef ADVANSYS_STATS | ||
4915 | ascq->q_cur_cnt[i] = 0; | ||
4916 | #endif /* ADVANSYS_STATS */ | ||
4917 | } | ||
4918 | } | ||
4919 | #ifdef ADVANSYS_STATS | ||
4920 | { | ||
4921 | REQP reqp; | ||
4922 | for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { | ||
4923 | REQTIMESTAT("asc_dequeue_list", ascq, reqp, | ||
4924 | reqp->device->id); | ||
4925 | } | ||
4926 | } | ||
4927 | #endif /* ADVANSYS_STATS */ | ||
4928 | } | ||
4929 | if (lastpp) { | ||
4930 | *lastpp = lastp; | ||
4931 | } | ||
4932 | ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp); | ||
4933 | return firstp; | ||
4934 | } | ||
4935 | |||
4936 | /* | ||
4937 | * Remove the specified 'REQP' from the specified queue for | ||
4938 | * the specified target device. Clear the 'tidmask' bit for the | ||
4939 | * device if no more commands are left queued for it. | ||
4940 | * | ||
4941 | * 'REQPNEXT(reqp)' returns reqp's the next pointer. | ||
4942 | * | ||
4943 | * Return ASC_TRUE if the command was found and removed, | ||
4944 | * otherwise return ASC_FALSE. | ||
4945 | */ | ||
4946 | static int asc_rmqueue(asc_queue_t *ascq, REQP reqp) | ||
4947 | { | ||
4948 | REQP currp, prevp; | ||
4949 | int tid; | ||
4950 | int ret = ASC_FALSE; | ||
4951 | |||
4952 | ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n", | ||
4953 | (ulong)ascq, (ulong)reqp); | ||
4954 | ASC_ASSERT(reqp != NULL); | ||
4955 | |||
4956 | tid = REQPTID(reqp); | ||
4957 | ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); | ||
4958 | |||
4959 | /* | ||
4960 | * Handle the common case of 'reqp' being the first | ||
4961 | * entry on the queue. | ||
4962 | */ | ||
4963 | if (reqp == ascq->q_first[tid]) { | ||
4964 | ret = ASC_TRUE; | ||
4965 | ascq->q_first[tid] = REQPNEXT(reqp); | ||
4966 | /* If the queue is now empty, clear its bit and the last pointer. */ | ||
4967 | if (ascq->q_first[tid] == NULL) { | ||
4968 | ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); | ||
4969 | ASC_ASSERT(ascq->q_last[tid] == reqp); | ||
4970 | ascq->q_last[tid] = NULL; | ||
4971 | } | ||
4972 | } else if (ascq->q_first[tid] != NULL) { | ||
4973 | ASC_ASSERT(ascq->q_last[tid] != NULL); | ||
4974 | /* | ||
4975 | * Because the case of 'reqp' being the first entry has been | ||
4976 | * handled above and it is known the queue is not empty, if | ||
4977 | * 'reqp' is found on the queue it is guaranteed the queue will | ||
4978 | * not become empty and that 'q_first[tid]' will not be changed. | ||
4979 | * | ||
4980 | * Set 'prevp' to the first entry, 'currp' to the second entry, | ||
4981 | * and search for 'reqp'. | ||
4982 | */ | ||
4983 | for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp); | ||
4984 | currp; prevp = currp, currp = REQPNEXT(currp)) { | ||
4985 | if (currp == reqp) { | ||
4986 | ret = ASC_TRUE; | ||
4987 | prevp->host_scribble = | ||
4988 | (unsigned char *)REQPNEXT(currp); | ||
4989 | reqp->host_scribble = NULL; | ||
4990 | if (ascq->q_last[tid] == reqp) { | ||
4991 | ascq->q_last[tid] = prevp; | ||
4992 | } | ||
4993 | break; | ||
4994 | } | ||
4995 | } | ||
4996 | } | ||
4997 | #ifdef ADVANSYS_STATS | ||
4998 | /* Maintain request queue statistics. */ | ||
4999 | if (ret == ASC_TRUE) { | ||
5000 | ascq->q_cur_cnt[tid]--; | ||
5001 | REQTIMESTAT("asc_rmqueue", ascq, reqp, tid); | ||
5002 | } | ||
5003 | ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); | ||
5004 | #endif /* ADVANSYS_STATS */ | ||
5005 | ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret); | ||
5006 | return ret; | ||
5007 | } | ||
5008 | |||
5009 | #ifdef CONFIG_PROC_FS | 4590 | #ifdef CONFIG_PROC_FS |
5010 | /* | 4591 | /* |
5011 | * asc_prt_board_devices() | 4592 | * asc_prt_board_devices() |
@@ -6465,79 +6046,6 @@ static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen) | |||
6465 | 6046 | ||
6466 | return totlen; | 6047 | return totlen; |
6467 | } | 6048 | } |
6468 | |||
6469 | /* | ||
6470 | * asc_prt_target_stats() | ||
6471 | * | ||
6472 | * Note: no single line should be greater than ASC_PRTLINE_SIZE, | ||
6473 | * cf. asc_prt_line(). | ||
6474 | * | ||
6475 | * This is separated from asc_prt_board_stats because a full set | ||
6476 | * of targets will overflow ASC_PRTBUF_SIZE. | ||
6477 | * | ||
6478 | * Return the number of characters copied into 'cp'. No more than | ||
6479 | * 'cplen' characters will be copied to 'cp'. | ||
6480 | */ | ||
6481 | static int | ||
6482 | asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen) | ||
6483 | { | ||
6484 | int leftlen; | ||
6485 | int totlen; | ||
6486 | int len; | ||
6487 | struct asc_stats *s; | ||
6488 | ushort chip_scsi_id; | ||
6489 | asc_board_t *boardp; | ||
6490 | asc_queue_t *active; | ||
6491 | |||
6492 | leftlen = cplen; | ||
6493 | totlen = len = 0; | ||
6494 | |||
6495 | boardp = ASC_BOARDP(shost); | ||
6496 | s = &boardp->asc_stats; | ||
6497 | |||
6498 | active = &ASC_BOARDP(shost)->active; | ||
6499 | |||
6500 | if (ASC_NARROW_BOARD(boardp)) { | ||
6501 | chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; | ||
6502 | } else { | ||
6503 | chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; | ||
6504 | } | ||
6505 | |||
6506 | if ((chip_scsi_id == tgt_id) || | ||
6507 | ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) { | ||
6508 | return 0; | ||
6509 | } | ||
6510 | |||
6511 | do { | ||
6512 | if (active->q_tot_cnt[tgt_id] > 0) { | ||
6513 | len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id); | ||
6514 | ASC_PRT_NEXT(); | ||
6515 | |||
6516 | len = asc_prt_line(cp, leftlen, | ||
6517 | " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", | ||
6518 | active->q_cur_cnt[tgt_id], | ||
6519 | active->q_max_cnt[tgt_id], | ||
6520 | active->q_tot_cnt[tgt_id], | ||
6521 | active->q_min_tim[tgt_id], | ||
6522 | active->q_max_tim[tgt_id], | ||
6523 | (active->q_tot_cnt[tgt_id] == | ||
6524 | 0) ? 0 : (active-> | ||
6525 | q_tot_tim[tgt_id] / | ||
6526 | active-> | ||
6527 | q_tot_cnt[tgt_id]), | ||
6528 | (active->q_tot_cnt[tgt_id] == | ||
6529 | 0) ? 0 : ASC_TENTHS(active-> | ||
6530 | q_tot_tim | ||
6531 | [tgt_id], | ||
6532 | active-> | ||
6533 | q_tot_cnt | ||
6534 | [tgt_id])); | ||
6535 | ASC_PRT_NEXT(); | ||
6536 | } | ||
6537 | } while (0); | ||
6538 | |||
6539 | return totlen; | ||
6540 | } | ||
6541 | #endif /* CONFIG_PROC_FS */ | 6049 | #endif /* CONFIG_PROC_FS */ |
6542 | #endif /* ADVANSYS_STATS */ | 6050 | #endif /* ADVANSYS_STATS */ |
6543 | 6051 | ||