* has not occurred then print a message and run in polled mode.
* 4. Need to add support for target mode commands, cf. CAM XPT.
* 5. check DMA mapping functions for failure
- * 6. Remove internal queueing
- * 7. Use scsi_transport_spi
- * 8. advansys_info is not safe against multiple simultaneous callers
- * 9. Kill boardp->id
- * 10. Add module_param to override ISA/VLB ioport array
+ * 6. Use scsi_transport_spi
+ * 7. advansys_info is not safe against multiple simultaneous callers
+ * 8. Kill boardp->id
+ * 9. Add module_param to override ISA/VLB ioport array
*/
#warning this driver is still not properly converted to the DMA API
#define HOST_BYTE(byte) ((byte) << 16)
#define DRIVER_BYTE(byte) ((byte) << 24)
-/*
- * The following definitions and macros are OS independent interfaces to
- * the queue functions:
- * REQ - SCSI request structure
- * REQP - pointer to SCSI request structure
- * REQPTID(reqp) - reqp's target id
- * REQPNEXT(reqp) - reqp's next pointer
- * REQPNEXTP(reqp) - pointer to reqp's next pointer
- * REQPTIME(reqp) - reqp's time stamp value
- * REQTIMESTAMP() - system time stamp value
- */
-typedef struct scsi_cmnd REQ, *REQP;
-#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
-#define REQPTID(reqp) ((reqp)->device->id)
-#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
-#define REQTIMESTAMP() (jiffies)
-
-#define REQTIMESTAT(function, ascq, reqp, tid) \
-{ \
- /*
- * If the request time stamp is less than the system time stamp, then \
- * maybe the system time stamp wrapped. Set the request time to zero.\
- */ \
- if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
- REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
- } else { \
- /* Indicate an error occurred with the assertion. */ \
- ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
- REQPTIME(reqp) = 0; \
- } \
- /* Handle first minimum time case without external initialization. */ \
- if (((ascq)->q_tot_cnt[tid] == 1) || \
- (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
- (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
- (function), (tid), (ascq)->q_min_tim[tid]); \
- } \
- if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
- (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
- (function), tid, (ascq)->q_max_tim[tid]); \
- } \
- (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
- /* Reset the time stamp field. */ \
- REQPTIME(reqp) = 0; \
-}
-
-/* asc_enqueue() flags */
-#define ASC_FRONT 1
-#define ASC_BACK 2
-
-/* asc_dequeue_list() argument */
-#define ASC_TID_ALL (-1)
-
-/* Return non-zero, if the queue is empty. */
-#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
-
#ifndef ADVANSYS_STATS
#define ASC_STATS(shost, counter)
#define ASC_STATS_ADD(shost, counter, count)
};
#endif /* ADVANSYS_STATS */
-/*
- * Request queuing structure
- */
-typedef struct asc_queue {
- ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
- REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
- REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
-#ifdef ADVANSYS_STATS
- short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
- short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
- ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
- ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
- ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
- ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
-#endif /* ADVANSYS_STATS */
-} asc_queue_t;
-
/*
* Adv Library Request Structures
*
ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
} dvc_cfg;
ushort asc_n_io_port; /* Number I/O ports. */
- asc_queue_t active; /* Active command queue */
ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
*/
static int advansys_slave_configure(struct scsi_device *);
-static void asc_scsi_done_list(struct scsi_cmnd *);
static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-static void asc_enqueue(asc_queue_t *, REQP, int);
-static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-static int asc_rmqueue(asc_queue_t *, REQP);
#ifdef CONFIG_PROC_FS
static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
#ifdef ADVANSYS_STATS
#ifdef CONFIG_PROC_FS
static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
-static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
#endif /* CONFIG_PROC_FS */
#endif /* ADVANSYS_STATS */
int leftlen;
char *curbuf;
off_t advoffset;
-#ifdef ADVANSYS_STATS
- int tgt_id;
-#endif /* ADVANSYS_STATS */
ASC_DBG(1, "advansys_proc_info: begin\n");
}
advoffset += cplen;
curbuf += cnt;
-
- /*
- * Display driver statistics for each target.
- */
- for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
- cp = boardp->prtbuf;
- cplen = asc_prt_target_stats(shost, tgt_id, cp,
- ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
#endif /* ADVANSYS_STATS */
/*
ASC_DVC_VAR *asc_dvc_varp;
ADV_DVC_VAR *adv_dvc_varp;
ulong flags;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *tscp, *new_last_scp;
int status;
int ret = SUCCESS;
}
/* Board lock is held. */
- /*
- * Dequeue all board 'active' requests for all devices and set
- * the request status to DID_RESET. A pointer to the last request
- * is returned in 'last_scp'.
- */
- if (done_scp == NULL) {
- done_scp = asc_dequeue_list(&boardp->active, &last_scp,
- ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->active,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp;
- tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
-
/* Save the time of the most recently completed reset. */
boardp->last_reset = jiffies;
boardp->flags &= ~ASC_HOST_IN_RESET;
spin_unlock_irqrestore(&boardp->lock, flags);
- /*
- * Complete all the 'done_scp' requests.
- */
- if (done_scp)
- asc_scsi_done_list(done_scp);
-
ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
return ret;
return 0;
}
-/*
- * Complete all requests on the singly linked list pointed
- * to by 'scp'.
- *
- * Interrupts can be enabled on entry.
- */
-static void asc_scsi_done_list(struct scsi_cmnd *scp)
-{
- struct scsi_cmnd *tscp;
-
- ASC_DBG(2, "asc_scsi_done_list: begin\n");
- while (scp != NULL) {
- ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
- tscp = REQPNEXT(scp);
- scp->host_scribble = NULL;
-
- asc_scsi_done(scp);
-
- scp = tscp;
- }
- ASC_DBG(2, "asc_scsi_done_list: done\n");
- return;
-}
-
/*
* Execute a single 'Scsi_Cmnd'.
*
* scsi_done - used to save caller's done function
* host_scribble - used for pointer to another struct scsi_cmnd
*
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'active' queue and will be completed from the
- * interrupt handler.
+ * If this function returns ASC_NOERROR the request will be completed
+ * from the interrupt handler.
*
* If this function returns ASC_ERROR the host error code has been set,
* and the called must call asc_scsi_done.
return ASC_ERROR;
}
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
case ASC_NOERROR:
ASC_STATS(scp->device->host, exe_noerror);
* successful request counter. Wrapping doesn't matter.
*/
boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
"ASC_NOERROR\n");
break;
return ASC_ERROR;
}
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
case ASC_NOERROR:
ASC_STATS(scp->device->host, exe_noerror);
* successful request counter. Wrapping doesn't matter.
*/
boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
"ASC_NOERROR\n");
break;
ASC_STATS(shost, callback);
ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
- /*
- * If the request isn't found on the active queue, it may
- * have been removed to handle a reset request.
- * Display a message and return.
- */
boardp = ASC_BOARDP(shost);
ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
/*
* 'qdonep' contains the command's ending status.
ASC_STATS(shost, callback);
ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
- /*
- * If the request isn't found on the active queue, it may have been
- * removed to handle a reset request. Display a message and return.
- *
- * Note: Because the structure may still be in use don't attempt
- * to free the adv_req_t and adv_sgblk_t, if any, structures.
- */
boardp = ASC_BOARDP(shost);
ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
/*
* 'done_status' contains the command's ending status.
}
}
-/*
- * Add a 'REQP' to the end of specified queue. Set 'tidmask'
- * to indicate a command is queued for the device.
- *
- * 'flag' may be either ASC_FRONT or ASC_BACK.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
-{
- int tid;
-
- ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
- (ulong)ascq, (ulong)reqp, flag);
- ASC_ASSERT(reqp != NULL);
- ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if (flag == ASC_FRONT) {
- reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
- ascq->q_first[tid] = reqp;
- /* If the queue was empty, set the last pointer. */
- if (ascq->q_last[tid] == NULL) {
- ascq->q_last[tid] = reqp;
- }
- } else { /* ASC_BACK */
- if (ascq->q_last[tid] != NULL) {
- ascq->q_last[tid]->host_scribble =
- (unsigned char *)reqp;
- }
- ascq->q_last[tid] = reqp;
- reqp->host_scribble = NULL;
- /* If the queue was empty, set the first pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_first[tid] = reqp;
- }
- }
- /* The queue has at least one entry, set its bit. */
- ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_tot_cnt[tid]++;
- ascq->q_cur_cnt[tid]++;
- if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
- ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
- ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
- tid, ascq->q_max_cnt[tid]);
- }
- REQPTIME(reqp) = REQTIMESTAMP();
-#endif /* ADVANSYS_STATS */
- ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
- return;
-}
-
-/*
- * Return a pointer to a singly linked list of all the requests queued
- * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
- *
- * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
- * the last request returned in the singly linked list.
- *
- * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
- * then all queued requests are concatenated into one list and
- * returned.
- *
- * Note: If 'lastpp' is used to append a new list to the end of
- * an old list, only change the old list last pointer if '*lastpp'
- * (or the function return value) is not NULL, i.e. use a temporary
- * variable for 'lastpp' and check its value after the function return
- * before assigning it to the list last pointer.
- *
- * Unfortunately collecting queuing time statistics adds overhead to
- * the function that isn't inherent to the function's algorithm.
- */
-static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
-{
- REQP firstp, lastp;
- int i;
-
- ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
- ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
-
- /*
- * If 'tid' is not ASC_TID_ALL, return requests only for
- * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
- * requests for all tids.
- */
- if (tid != ASC_TID_ALL) {
- /* Return all requests for the specified 'tid'. */
- if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
- /* List is empty; Set first and last return pointers to NULL. */
- firstp = lastp = NULL;
- } else {
- firstp = ascq->q_first[tid];
- lastp = ascq->q_last[tid];
- ascq->q_first[tid] = ascq->q_last[tid] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- ascq->q_cur_cnt[tid] = 0;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq,
- reqp, tid);
- }
- }
-#endif /* ADVANSYS_STATS */
- }
- } else {
- /* Return all requests for all tids. */
- firstp = lastp = NULL;
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if (firstp == NULL) {
- firstp = ascq->q_first[i];
- lastp = ascq->q_last[i];
- } else {
- ASC_ASSERT(lastp != NULL);
- lastp->host_scribble =
- (unsigned char *)ascq->q_first[i];
- lastp = ascq->q_last[i];
- }
- ascq->q_first[i] = ascq->q_last[i] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-#ifdef ADVANSYS_STATS
- ascq->q_cur_cnt[i] = 0;
-#endif /* ADVANSYS_STATS */
- }
- }
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq, reqp,
- reqp->device->id);
- }
- }
-#endif /* ADVANSYS_STATS */
- }
- if (lastpp) {
- *lastpp = lastp;
- }
- ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
- return firstp;
-}
-
-/*
- * Remove the specified 'REQP' from the specified queue for
- * the specified target device. Clear the 'tidmask' bit for the
- * device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's the next pointer.
- *
- * Return ASC_TRUE if the command was found and removed,
- * otherwise return ASC_FALSE.
- */
-static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
-{
- REQP currp, prevp;
- int tid;
- int ret = ASC_FALSE;
-
- ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
- (ulong)ascq, (ulong)reqp);
- ASC_ASSERT(reqp != NULL);
-
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
- /*
- * Handle the common case of 'reqp' being the first
- * entry on the queue.
- */
- if (reqp == ascq->q_first[tid]) {
- ret = ASC_TRUE;
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is now empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
- } else if (ascq->q_first[tid] != NULL) {
- ASC_ASSERT(ascq->q_last[tid] != NULL);
- /*
- * Because the case of 'reqp' being the first entry has been
- * handled above and it is known the queue is not empty, if
- * 'reqp' is found on the queue it is guaranteed the queue will
- * not become empty and that 'q_first[tid]' will not be changed.
- *
- * Set 'prevp' to the first entry, 'currp' to the second entry,
- * and search for 'reqp'.
- */
- for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
- currp; prevp = currp, currp = REQPNEXT(currp)) {
- if (currp == reqp) {
- ret = ASC_TRUE;
- prevp->host_scribble =
- (unsigned char *)REQPNEXT(currp);
- reqp->host_scribble = NULL;
- if (ascq->q_last[tid] == reqp) {
- ascq->q_last[tid] = prevp;
- }
- break;
- }
- }
- }
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- if (ret == ASC_TRUE) {
- ascq->q_cur_cnt[tid]--;
- REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
- }
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-#endif /* ADVANSYS_STATS */
- ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
- return ret;
-}
-
#ifdef CONFIG_PROC_FS
/*
* asc_prt_board_devices()
return totlen;
}
-
-/*
- * asc_prt_target_stats()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * This is separated from asc_prt_board_stats because a full set
- * of targets will overflow ASC_PRTBUF_SIZE.
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
-static int
-asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
-{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- ushort chip_scsi_id;
- asc_board_t *boardp;
- asc_queue_t *active;
-
- leftlen = cplen;
- totlen = len = 0;
-
- boardp = ASC_BOARDP(shost);
- s = &boardp->asc_stats;
-
- active = &ASC_BOARDP(shost)->active;
-
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
- }
-
- if ((chip_scsi_id == tgt_id) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
- return 0;
- }
-
- do {
- if (active->q_tot_cnt[tgt_id] > 0) {
- len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
- " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
- active->q_cur_cnt[tgt_id],
- active->q_max_cnt[tgt_id],
- active->q_tot_cnt[tgt_id],
- active->q_min_tim[tgt_id],
- active->q_max_tim[tgt_id],
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : (active->
- q_tot_tim[tgt_id] /
- active->
- q_tot_cnt[tgt_id]),
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : ASC_TENTHS(active->
- q_tot_tim
- [tgt_id],
- active->
- q_tot_cnt
- [tgt_id]));
- ASC_PRT_NEXT();
- }
- } while (0);
-
- return totlen;
-}
#endif /* CONFIG_PROC_FS */
#endif /* ADVANSYS_STATS */