advansys.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:724k
- *
- * This function is called from init/main.c at boot time.
- * It it passed LILO parameters that can be set from the
- * LILO command line or in /etc/lilo.conf.
- *
- * It is used by the AdvanSys driver to either disable I/O
- * port scanning or to limit scanning to 1 - 4 I/O ports.
- * Regardless of the option setting EISA and PCI boards
- * will still be searched for and detected. This option
- * only affects searching for ISA and VL boards.
- *
- * If ADVANSYS_DEBUG is defined the driver debug level may
- * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
- *
- * Examples:
- * 1. Eliminate I/O port scanning:
- * boot: linux advansys=
- * or
- * boot: linux advansys=0x0
- * 2. Limit I/O port scanning to one I/O port:
- * boot: linux advansys=0x110
- * 3. Limit I/O port scanning to four I/O ports:
- * boot: linux advansys=0x110,0x210,0x230,0x330
- * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
- * set the driver debug level to 2.
- * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
- *
- * ints[0] - number of arguments
- * ints[1] - first argument
- * ints[2] - second argument
- * ...
- */
- ASC_INITFUNC(
- void,
- advansys_setup(char *str, int *ints)
- )
- {
- int i;
- if (asc_iopflag == ASC_TRUE) {
- printk("AdvanSys SCSI: 'advansys' LILO option may appear only oncen");
- return;
- }
- asc_iopflag = ASC_TRUE;
- if (ints[0] > ASC_NUM_IOPORT_PROBE) {
- #ifdef ADVANSYS_DEBUG
- if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
- (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
- asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
- } else {
- #endif /* ADVANSYS_DEBUG */
- printk("AdvanSys SCSI: only %d I/O ports acceptedn",
- ASC_NUM_IOPORT_PROBE);
- #ifdef ADVANSYS_DEBUG
- }
- #endif /* ADVANSYS_DEBUG */
- }
- #ifdef ADVANSYS_DEBUG
- ASC_DBG1(1, "advansys_setup: ints[0] %dn", ints[0]);
- for (i = 1; i < ints[0]; i++) {
- ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]);
- }
- ASC_DBG(1, "n");
- #endif /* ADVANSYS_DEBUG */
- for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
- asc_ioport[i-1] = ints[i];
- ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%xn",
- i - 1, asc_ioport[i-1]);
- }
- }
- /*
- * --- Loadable Driver Support
- */
- #if ASC_LINUX_KERNEL24
- static
- #endif
- #if ASC_LINUX_KERNEL24 || (ASC_LINUX_KERNEL22 && defined(MODULE))
- Scsi_Host_Template driver_template = ADVANSYS;
- # include "scsi_module.c"
- #endif
- /*
- * --- Miscellaneous Driver Functions
- */
- /*
- * First-level interrupt handler.
- *
- * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
- * all boards are currently checked for interrupts on each interrupt, 'dev_id'
- * is not referenced. 'dev_id' could be used to identify an interrupt passed
- * to the AdvanSys driver which is for a device sharing an interrupt with
- * an AdvanSys adapter.
- */
- STATIC void
- advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
- ulong flags;
- int i;
- asc_board_t *boardp;
- Scsi_Cmnd *done_scp = NULL, *last_scp = NULL;
- Scsi_Cmnd *new_last_scp;
- ASC_DBG(1, "advansys_interrupt: beginn");
- /*
- * Check for interrupts on all boards.
- * AscISR() will call asc_isr_callback().
- */
- for (i = 0; i < asc_board_count; i++) {
- boardp = ASC_BOARDP(asc_host[i]);
- ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lxn",
- i, (ulong) boardp);
- spin_lock_irqsave(&boardp->lock, flags);
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- if (AscIsIntPending(asc_host[i]->io_port)) {
- ASC_STATS(asc_host[i], interrupt);
- ASC_DBG(1, "advansys_interrupt: before AscISR()n");
- AscISR(&boardp->dvc_var.asc_dvc_var);
- }
- } else {
- /*
- * Wide Board
- */
- ASC_DBG(1, "advansys_interrupt: before AdvISR()n");
- if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(asc_host[i], interrupt);
- }
- }
- /*
- * Start waiting requests and create a list of completed requests.
- *
- * If a reset request is being performed for the board, the reset
- * handler will complete pending requests after it has completed.
- */
- if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
- ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lxn",
- (ulong) done_scp, (ulong) last_scp);
- /* Start any waiting commands for the board. */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()n");
- asc_execute_queue(&boardp->waiting);
- }
- /*
- * Add to the list of requests that must be completed.
- *
- * 'done_scp' will always be NULL on the first iteration
- * of this loop. 'last_scp' is set at the same time as
- * 'done_scp'.
- */
- if (done_scp == NULL) {
- done_scp = asc_dequeue_list(&boardp->done, &last_scp,
- ASC_TID_ALL);
- } else {
- ASC_ASSERT(last_scp != NULL);
- REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done,
- &new_last_scp, ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- last_scp = new_last_scp;
- }
- }
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
- }
- /*
- * If interrupts were enabled on entry, then they
- * are now enabled here.
- *
- * Complete all requests on the done list.
- */
- asc_scsi_done_list(done_scp);
- ASC_DBG(1, "advansys_interrupt: endn");
- return;
- }
- /*
- * Set the number of commands to queue per device for the
- * specified host adapter.
- */
- STATIC void
- advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
- {
- Scsi_Device *device;
- asc_board_t *boardp;
- boardp = ASC_BOARDP(shp);
- boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
- for (device = devicelist; device != NULL; device = device->next) {
- if (device->host != shp) {
- continue;
- }
- /*
- * Save a pointer to the device and set its initial/maximum
- * queue depth.
- */
- boardp->device[device->id] = device;
- if (ASC_NARROW_BOARD(boardp)) {
- device->queue_depth =
- boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id];
- } else {
- device->queue_depth =
- boardp->dvc_var.adv_dvc_var.max_dvc_qng;
- }
- ASC_DBG3(1,
- "advansys_select_queue_depths: shp 0x%lx, id %d, depth %dn",
- (ulong) shp, device->id, device->queue_depth);
- }
- }
- /*
- * Complete all requests on the singly linked list pointed
- * to by 'scp'.
- *
- * Interrupts can be enabled on entry.
- */
- STATIC void
- asc_scsi_done_list(Scsi_Cmnd *scp)
- {
- Scsi_Cmnd *tscp;
- ASC_DBG(2, "asc_scsi_done_list: beginn");
- while (scp != NULL) {
- ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lxn", (ulong) scp);
- tscp = REQPNEXT(scp);
- REQPNEXT(scp) = NULL;
- ASC_STATS(scp->host, done);
- ASC_ASSERT(scp->scsi_done != NULL);
- scp->scsi_done(scp);
- scp = tscp;
- }
- ASC_DBG(2, "asc_scsi_done_list: donen");
- return;
- }
- /*
- * Execute a single 'Scsi_Cmnd'.
- *
- * The function 'done' is called when the request has been completed.
- *
- * Scsi_Cmnd:
- *
- * host - board controlling device
- * device - device to send command
- * target - target of device
- * lun - lun of device
- * cmd_len - length of SCSI CDB
- * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
- * use_sg - if non-zero indicates scatter-gather request with use_sg elements
- *
- * if (use_sg == 0) {
- * request_buffer - buffer address for request
- * request_bufflen - length of request buffer
- * } else {
- * request_buffer - pointer to scatterlist structure
- * }
- *
- * sense_buffer - sense command buffer
- *
- * result (4 bytes of an int):
- * Byte Meaning
- * 0 SCSI Status Byte Code
- * 1 SCSI One Byte Message Code
- * 2 Host Error Code
- * 3 Mid-Level Error Code
- *
- * host driver fields:
- * SCp - Scsi_Pointer used for command processing status
- * scsi_done - used to save caller's done function
- * host_scribble - used for pointer to another 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 has been enqueued
- * on the board's 'done' queue and must be completed by the caller.
- *
- * If ASC_BUSY is returned the request will be enqueued by the
- * caller on the target's waiting queue and re-tried later.
- */
- STATIC int
- asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
- {
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ADV_SCSI_REQ_Q *adv_scsiqp;
- Scsi_Device *device;
- int ret;
- ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lxn",
- (ulong) scp, (ulong) scp->scsi_done);
- boardp = ASC_BOARDP(scp->host);
- device = boardp->device[scp->target];
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Build and execute Narrow Board request.
- */
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- /*
- * Build Asc Library request structure using the
- * global structures 'asc_scsi_req' and 'asc_sg_head'.
- *
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- *
- * asc_build_req() can not return ASC_BUSY.
- */
- if (asc_build_req(boardp, scp) == ASC_ERROR) {
- ASC_STATS(scp->host, build_error);
- 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->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->target]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERRORn");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2(
- "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%xn",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2(
- "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%xn",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- }
- } else {
- /*
- * Build and execute Wide Board request.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- /*
- * Build and get a pointer to an Adv Library request structure.
- *
- * If the request is successfully built then send it below,
- * otherwise return with an error.
- */
- switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERRORn");
- break;
- case ASC_BUSY:
- ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSYn");
- /*
- * If busy is returned the request has not been enqueued.
- * It will be enqueued by the caller on the target's waiting
- * queue and retried later.
- *
- * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
- * count wide board busy conditions. They are updated in
- * adv_build_req and adv_get_sglist, respectively.
- */
- return ASC_BUSY;
- case ASC_ERROR:
- /*
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- */
- default:
- ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERRORn");
- ASC_STATS(scp->host, build_error);
- 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->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->target]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERRORn");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2(
- "asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%xn",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2(
- "asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%xn",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- }
- }
- ASC_DBG(1, "asc_execute_scsi_cmnd: endn");
- return ret;
- }
- /*
- * Build a request structure for the Asc Library (Narrow Board).
- *
- * The global structures 'asc_scsi_q' and 'asc_sg_head' are
- * used to build the request.
- *
- * If an error occurs, then queue the request on the board done
- * queue and return ASC_ERROR.
- */
- STATIC int
- asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
- {
- /*
- * Mutually exclusive access is required to 'asc_scsi_q' and
- * 'asc_sg_head' until after the request is started.
- */
- memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
- /*
- * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
- */
- asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
- /*
- * Build the ASC_SCSI_Q request.
- *
- * For narrow boards a CDB length maximum of 12 bytes
- * is supported.
- */
- if (scp->cmd_len > ASC_MAX_CDB_LEN) {
- ASC_PRINT3(
- "asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %dn",
- boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- asc_scsi_q.cdbptr = &scp->cmnd[0];
- asc_scsi_q.q2.cdb_len = scp->cmd_len;
- asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
- asc_scsi_q.q1.target_lun = scp->lun;
- asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
- asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
- /*
- * If there are any outstanding requests for the current target,
- * then every 255th request send an ORDERED request. This heuristic
- * tries to retain the benefit of request sorting while preventing
- * request starvation. 255 is the max number of tags or pending commands
- * a device may have outstanding.
- *
- * The request count is incremented below for every successfully
- * started request.
- *
- */
- if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) &&
- (boardp->reqcnt[scp->target] % 255) == 0) {
- asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
- } else {
- asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
- }
- /*
- * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- ASC_STATS(scp->host, cont_cnt);
- asc_scsi_q.q1.data_addr =
- cpu_to_le32(virt_to_bus(scp->request_buffer));
- asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
- ASC_STATS_ADD(scp->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- asc_scsi_q.q1.sg_queue_cnt = 0;
- asc_scsi_q.sg_head = NULL;
- } else {
- /*
- * CDB scatter-gather request list.
- */
- int sgcnt;
- struct scatterlist *slp;
- if (scp->use_sg > scp->host->sg_tablesize) {
- ASC_PRINT3(
- "asc_build_req: board %d: use_sg %d > sg_tablesize %dn",
- boardp->id, scp->use_sg, scp->host->sg_tablesize);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- ASC_STATS(scp->host, sg_cnt);
- /*
- * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
- * structure to point to it.
- */
- memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
- asc_scsi_q.q1.cntl |= QC_SG_HEAD;
- asc_scsi_q.sg_head = &asc_sg_head;
- asc_scsi_q.q1.data_cnt = 0;
- asc_scsi_q.q1.data_addr = 0;
- /* This is a byte value, otherwise it would need to be swapped. */
- asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
- ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
- /*
- * Convert scatter-gather list into ASC_SG_HEAD list.
- */
- slp = (struct scatterlist *) scp->request_buffer;
- for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
- asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(virt_to_bus(slp->address));
- asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
- ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
- }
- }
- ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
- return ASC_NOERROR;
- }
- /*
- * Build a request structure for the Adv Library (Wide Board).
- *
- * If an adv_req_t can not be allocated to issue the request,
- * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
- *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
- * microcode for DMA addresses or math operations are byte swapped
- * to little-endian order.
- */
- STATIC int
- adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp,
- ADV_SCSI_REQ_Q **adv_scsiqpp)
- {
- adv_req_t *reqp;
- ADV_SCSI_REQ_Q *scsiqp;
- int i;
- int ret;
- /*
- * Allocate an adv_req_t structure from the board to execute
- * the command.
- */
- if (boardp->adv_reqp == NULL) {
- ASC_DBG(1, "adv_build_req: no free adv_req_tn");
- ASC_STATS(scp->host, adv_build_noreq);
- return ASC_BUSY;
- } else {
- reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp->next_reqp;
- reqp->next_reqp = NULL;
- }
- /*
- * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
- */
- scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
- /*
- * Initialize the structure.
- */
- scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
- /*
- * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
- */
- scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
- /*
- * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure.
- */
- reqp->cmndp = scp;
- /*
- * Build the ADV_SCSI_REQ_Q request.
- */
- /*
- * Set CDB length and copy it to the request structure.
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
- if (scp->cmd_len > ADV_MAX_CDB_LEN) {
- ASC_PRINT3(
- "adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %dn",
- boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- scsiqp->cdb_len = scp->cmd_len;
- /* Copy first 12 CDB bytes to cdb[]. */
- for (i = 0; i < scp->cmd_len && i < 12; i++) {
- scsiqp->cdb[i] = scp->cmnd[i];
- }
- /* Copy last 4 CDB bytes, if present, to cdb16[]. */
- for (; i < scp->cmd_len; i++) {
- scsiqp->cdb16[i - 12] = scp->cmnd[i];
- }
- scsiqp->target_id = scp->target;
- scsiqp->target_lun = scp->lun;
- scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- scsiqp->sense_len = sizeof(scp->sense_buffer);
- /*
- * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- scsiqp->vdata_addr = scp->request_buffer;
- scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- reqp->sgblkp = NULL;
- scsiqp->sg_list_ptr = NULL;
- scsiqp->sg_real_addr = 0;
- ASC_STATS(scp->host, cont_cnt);
- ASC_STATS_ADD(scp->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- } else {
- /*
- * CDB scatter-gather request list.
- */
- if (scp->use_sg > ADV_MAX_SG_LIST) {
- ASC_PRINT3(
- "adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %dn",
- boardp->id, scp->use_sg, scp->host->sg_tablesize);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- /*
- * Free the 'adv_req_t' structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
- return ASC_ERROR;
- }
- if ((ret = adv_get_sglist(boardp, reqp, scp)) != ADV_SUCCESS) {
- /*
- * Free the adv_req_t structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
- return ret;
- }
- ASC_STATS(scp->host, sg_cnt);
- ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg);
- }
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
- *adv_scsiqpp = scsiqp;
- return ASC_NOERROR;
- }
- /*
- * Build scatter-gather list for Adv Library (Wide Board).
- *
- * Additional ADV_SG_BLOCK structures will need to be allocated
- * if the total number of scatter-gather elements exceeds
- * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
- * assumed to be physically contiguous.
- *
- * Return:
- * ADV_SUCCESS(1) - SG List successfully created
- * ADV_ERROR(-1) - SG List creation failed
- */
- STATIC int
- adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
- {
- adv_sgblk_t *sgblkp;
- ADV_SCSI_REQ_Q *scsiqp;
- struct scatterlist *slp;
- int sg_elem_cnt;
- ADV_SG_BLOCK *sg_block, *prev_sg_block;
- ADV_PADDR sg_block_paddr;
- int i;
- scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
- slp = (struct scatterlist *) scp->request_buffer;
- sg_elem_cnt = scp->use_sg;
- prev_sg_block = NULL;
- reqp->sgblkp = NULL;
- do
- {
- /*
- * Allocate a 'adv_sgblk_t' structure from the board free
- * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
- * (15) scatter-gather elements.
- */
- if ((sgblkp = boardp->adv_sgblkp) == NULL) {
- ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_tn");
- ASC_STATS(scp->host, adv_build_nosg);
- /*
- * Allocation failed. Free 'adv_sgblk_t' structures already
- * allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL)
- {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
- return ASC_BUSY;
- } else {
- /* Complete 'adv_sgblk_t' board allocation. */
- boardp->adv_sgblkp = sgblkp->next_sgblkp;
- sgblkp->next_sgblkp = NULL;
- /*
- * Get 8 byte aligned virtual and physical addresses for
- * the allocated ADV_SG_BLOCK structure.
- */
- sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block);
- sg_block_paddr = virt_to_bus(sg_block);
- /*
- * Check if this is the first 'adv_sgblk_t' for the request.
- */
- if (reqp->sgblkp == NULL)
- {
- /* Request's first scatter-gather block. */
- reqp->sgblkp = sgblkp;
- /*
- * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
- * address pointers.
- */
- scsiqp->sg_list_ptr = sg_block;
- scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
- } else
- {
- /* Request's second or later scatter-gather block. */
- sgblkp->next_sgblkp = reqp->sgblkp;
- reqp->sgblkp = sgblkp;
- /*
- * Point the previous ADV_SG_BLOCK structure to
- * the newly allocated ADV_SG_BLOCK structure.
- */
- ASC_ASSERT(prev_sg_block != NULL);
- prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
- }
- }
- for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
- {
- sg_block->sg_list[i].sg_addr =
- cpu_to_le32(virt_to_bus(slp->address));
- sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
- ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
- if (--sg_elem_cnt == 0)
- { /* Last ADV_SG_BLOCK and scatter-gather entry. */
- sg_block->sg_cnt = i + 1;
- sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
- return ADV_SUCCESS;
- }
- slp++;
- }
- sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
- prev_sg_block = sg_block;
- }
- while (1);
- /* NOTREACHED */
- }
- /*
- * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
- *
- * Interrupt callback function for the Narrow SCSI Asc Library.
- */
- STATIC void
- asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
- {
- asc_board_t *boardp;
- Scsi_Cmnd *scp;
- struct Scsi_Host *shp;
- int i;
- ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lxn",
- (ulong) asc_dvc_varp, (ulong) qdonep);
- ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
- /*
- * Get the Scsi_Cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- */
- scp = (Scsi_Cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
- ASC_DBG1(1, "asc_isr_callback: scp 0x%lxn", (ulong) scp);
- if (scp == NULL) {
- ASC_PRINT("asc_isr_callback: scp is NULLn");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
- /*
- * If the request's host pointer is not valid, display a
- * message and return.
- */
- shp = scp->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shp) {
- break;
- }
- }
- if (i == asc_board_count) {
- ASC_PRINT2(
- "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lxn",
- (ulong) scp, (ulong) shp);
- return;
- }
- ASC_STATS(shp, callback);
- ASC_DBG1(1, "asc_isr_callback: shp 0x%lxn", (ulong) shp);
- /*
- * 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(shp);
- 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 queuen",
- boardp->id, (ulong) scp);
- return;
- }
- /*
- * 'qdonep' contains the command's ending status.
- */
- switch (qdonep->d3.done_stat) {
- case QD_NO_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_NO_ERRORn");
- scp->result = 0;
- /*
- * If an INQUIRY command completed successfully, then call
- * the AscInquiryHandling() function to set-up the device.
- */
- if (scp->cmnd[0] == SCSICMD_Inquiry && scp->lun == 0 &&
- (scp->request_bufflen - qdonep->remain_bytes) >= 8)
- {
- AscInquiryHandling(asc_dvc_varp, scp->target & 0x7,
- (ASC_SCSI_INQUIRY *) scp->request_buffer);
- }
- #if ASC_LINUX_KERNEL24
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
- qdonep->remain_bytes <= scp->request_bufflen != 0) {
- ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytesn",
- (unsigned) qdonep->remain_bytes);
- scp->resid = qdonep->remain_bytes;
- }
- #endif
- break;
- case QD_WITH_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_WITH_ERRORn");
- switch (qdonep->d3.host_stat) {
- case QHSTA_NO_ERROR:
- if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
- ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITIONn");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- } else {
- scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
- }
- break;
- default:
- /* QHSTA error occurred */
- ASC_DBG1(1, "asc_isr_callback: host_stat 0x%xn",
- qdonep->d3.host_stat);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOSTn");
- scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
- default:
- ASC_DBG1(1, "asc_isr_callback: done_stat 0x%xn", qdonep->d3.done_stat);
- scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
- }
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 &&
- qdonep->d3.done_stat == QD_NO_ERROR &&
- qdonep->d3.host_stat == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
- }
- /*
- * Because interrupts may be enabled by the 'Scsi_Cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return;
- }
- /*
- * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
- *
- * Callback function for the Wide SCSI Adv Library.
- */
- STATIC void
- adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
- {
- asc_board_t *boardp;
- adv_req_t *reqp;
- adv_sgblk_t *sgblkp;
- Scsi_Cmnd *scp;
- struct Scsi_Host *shp;
- int i;
- #if ASC_LINUX_KERNEL24
- ADV_DCNT resid_cnt;
- #endif
- ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lxn",
- (ulong) adv_dvc_varp, (ulong) scsiqp);
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
- /*
- * Get the adv_req_t structure for the command that has been
- * completed. The adv_req_t structure actually contains the
- * completed ADV_SCSI_REQ_Q structure.
- */
- reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
- ASC_DBG1(1, "adv_isr_callback: reqp 0x%lxn", (ulong) reqp);
- if (reqp == NULL) {
- ASC_PRINT("adv_isr_callback: reqp is NULLn");
- return;
- }
- /*
- * Get the Scsi_Cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- *
- * Note: The adv_req_t request structure and adv_sgblk_t structure,
- * if any, are dropped, because a board structure pointer can not be
- * determined.
- */
- scp = reqp->cmndp;
- ASC_DBG1(1, "adv_isr_callback: scp 0x%lxn", (ulong) scp);
- if (scp == NULL) {
- ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
- /*
- * If the request's host pointer is not valid, display a message
- * and return.
- */
- shp = scp->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shp) {
- break;
- }
- }
- /*
- * Note: If the host structure is not found, the adv_req_t request
- * structure and adv_sgblk_t structure, if any, is dropped.
- */
- if (i == asc_board_count) {
- ASC_PRINT2(
- "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lxn",
- (ulong) scp, (ulong) shp);
- return;
- }
- ASC_STATS(shp, callback);
- ASC_DBG1(1, "adv_isr_callback: shp 0x%lxn", (ulong) shp);
- /*
- * 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(shp);
- 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 queuen",
- boardp->id, (ulong) scp);
- return;
- }
- /*
- * 'done_status' contains the command's ending status.
- */
- switch (scsiqp->done_status) {
- case QD_NO_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_NO_ERRORn");
- scp->result = 0;
- #if ASC_LINUX_KERNEL24
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- resid_cnt = le32_to_cpu(scsiqp->data_cnt);
- if (scp->request_bufflen != 0 && resid_cnt != 0 &&
- resid_cnt <= scp->request_bufflen) {
- ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytesn",
- (ulong) resid_cnt);
- scp->resid = resid_cnt;
- }
- #endif
- break;
- case QD_WITH_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_WITH_ERRORn");
- switch (scsiqp->host_status) {
- case QHSTA_NO_ERROR:
- if (scsiqp->scsi_status == SS_CHK_CONDITION) {
- ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITIONn");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(scsiqp->scsi_status);
- } else {
- scp->result = STATUS_BYTE(scsiqp->scsi_status);
- }
- break;
- default:
- /* Some other QHSTA error occurred. */
- ASC_DBG1(1, "adv_isr_callback: host_status 0x%xn",
- scsiqp->host_status);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOSTn");
- scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
- break;
- default:
- ASC_DBG1(1, "adv_isr_callback: done_status 0x%xn", scsiqp->done_status);
- scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
- break;
- }
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 &&
- scsiqp->done_status == QD_NO_ERROR &&
- scsiqp->host_status == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
- }
- /*
- * Because interrupts may be enabled by the 'Scsi_Cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- /*
- * Free all 'adv_sgblk_t' structures allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL)
- {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
- /*
- * Free the adv_req_t structure used with the command by adding
- * it back to the board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
- ASC_DBG(1, "adv_isr_callback: donen");
- return;
- }
- /*
- * adv_async_callback() - Adv Library asynchronous event callback function.
- */
- STATIC void
- adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
- {
- switch (code)
- {
- case ADV_ASYNC_SCSI_BUS_RESET_DET:
- /*
- * The firmware detected a SCSI Bus reset.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DETn");
- break;
- case ADV_ASYNC_RDMA_FAILURE:
- /*
- * Handle RDMA failure by resetting the SCSI Bus and
- * possibly the chip if it is unresponsive. Log the error
- * with a unique code.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILUREn");
- AdvResetChipAndSB(adv_dvc_varp);
- break;
- case ADV_HOST_SCSI_BUS_RESET:
- /*
- * Host generated SCSI bus reset occurred.
- */
- ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESETn");
- break;
- default:
- ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%xn", code);
- break;
- }
- }
- /*
- * 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 %dn",
- (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) {
- REQPNEXT(reqp) = 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) {
- REQPNEXT(ascq->q_last[tid]) = reqp;
- }
- ascq->q_last[tid] = reqp;
- REQPNEXT(reqp) = 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] %dn",
- tid, ascq->q_max_cnt[tid]);
- }
- REQPTIME(reqp) = REQTIMESTAMP();
- #endif /* ADVANSYS_STATS */
- ASC_DBG1(3, "asc_enqueue: reqp 0x%lxn", (ulong) reqp);
- return;
- }
- /*
- * Return first queued 'REQP' on 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 next pointer.
- */
- STATIC REQP
- asc_dequeue(asc_queue_t *ascq, int tid)
- {
- REQP reqp;
- ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %dn", (ulong) ascq, tid);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if ((reqp = ascq->q_first[tid]) != NULL) {
- ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is 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;
- }
- #ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_cur_cnt[tid]--;
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
- REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
- #endif /* ADVANSYS_STATS */
- }
- ASC_DBG1(3, "asc_dequeue: reqp 0x%lxn", (ulong) reqp);
- return reqp;
- }
- /*
- * 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 %dn", (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);
- REQPNEXT(lastp) = 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->target);
- }
- }
- #endif /* ADVANSYS_STATS */
- }
- if (lastpp) {
- *lastpp = lastp;
- }
- ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lxn", (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%lxn",
- (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;
- REQPNEXT(prevp) = REQPNEXT(currp);
- REQPNEXT(reqp) = 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 %dn", (ulong) reqp, ret);
- return ret;
- }
- /*
- * Execute as many queued requests as possible for the specified queue.
- *
- * Calls asc_execute_scsi_cmnd() to execute a REQP/Scsi_Cmnd.
- */
- STATIC void
- asc_execute_queue(asc_queue_t *ascq)
- {
- ADV_SCSI_BIT_ID_TYPE scan_tidmask;
- REQP reqp;
- int i;
- ASC_DBG1(1, "asc_execute_queue: ascq 0x%lxn", (ulong) ascq);
- /*
- * Execute queued commands for devices attached to
- * the current board in round-robin fashion.
- */
- scan_tidmask = ascq->q_tidmask;
- do {
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if ((reqp = asc_dequeue(ascq, i)) == NULL) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp)
- == ASC_BUSY) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- /*
- * The request returned ASC_BUSY. Enqueue at the front of
- * target's waiting list to maintain correct ordering.
- */
- asc_enqueue(ascq, reqp, ASC_FRONT);
- }
- }
- }
- } while (scan_tidmask);
- return;
- }
- #ifdef CONFIG_PROC_FS
- /*
- * asc_prt_board_devices()
- *
- * Print driver information for devices attached to the board.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int chip_scsi_id;
- int i;
- boardp = ASC_BOARDP(shp);
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nDevice Information for AdvanSys SCSI Host %d:n", shp->host_no);
- ASC_PRT_NEXT();
- 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;
- }
- len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X,", i);
- ASC_PRT_NEXT();
- }
- }
- len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)n", chip_scsi_id);
- ASC_PRT_NEXT();
- return totlen;
- }
- /*
- * Display Wide Board BIOS Information.
- */
- STATIC int
- asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- ushort major, minor, letter;
- boardp = ASC_BOARDP(shp);
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen, "nROM BIOS Version: ");
- ASC_PRT_NEXT();
- /*
- * If the BIOS saved a valid signature, then fill in
- * the BIOS code segment base address.
- */
- if (boardp->bios_signature != 0x55AA) {
- len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer versionn");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pubn");
- ASC_PRT_NEXT();
- } else {
- major = (boardp->bios_version >> 12) & 0xF;
- minor = (boardp->bios_version >> 8) & 0xF;
- letter = (boardp->bios_version & 0xFF);
- len = asc_prt_line(cp, leftlen, "%d.%d%cn",
- major, minor, letter >= 26 ? '?' : letter + 'A');
- ASC_PRT_NEXT();
- /*
- * Current available ROM BIOS release is 3.1I for UW
- * and 3.2I for U2W. This code doesn't differentiate
- * UW and U2W boards.
- */
- if (major < 3 || (major <= 3 && minor < 1) ||
- (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
- len = asc_prt_line(cp, leftlen,
- "Newer version of ROM BIOS is available at the ConnectCom FTP site:n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "ftp://ftp.connectcom.net/pubn");
- ASC_PRT_NEXT();
- }
- }
- return totlen;
- }
- /*
- * Add serial number to information bar if signature AAh
- * is found in at bit 15-9 (7 bits) of word 1.
- *
- * Serial Number consists fo 12 alpha-numeric digits.
- *
- * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
- * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
- * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
- * 5 - Product revision (A-J) Word0: " "
- *
- * Signature Word1: 15-9 (7 bits)
- * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
- * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
- *
- * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
- *
- * Note 1: Only production cards will have a serial number.
- *
- * Note 2: Signature is most significant 7 bits (0xFE).
- *
- * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
- */
- STATIC int
- asc_get_eeprom_string(ushort *serialnum, uchar *cp)
- {
- ushort w, num;
- if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
- return ASC_FALSE;
- } else {
- /*
- * First word - 6 digits.
- */
- w = serialnum[0];
- /* Product type - 1st digit. */
- if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
- /* Product type is P=Prototype */
- *cp += 0x8;
- }
- cp++;
- /* Manufacturing location - 2nd digit. */
- *cp++ = 'A' + ((w & 0x1C00) >> 10);
- /* Product ID - 3rd, 4th digits. */
- num = w & 0x3FF;
- *cp++ = '0' + (num / 100);
- num %= 100;
- *cp++ = '0' + (num / 10);
- /* Product revision - 5th digit. */
- *cp++ = 'A' + (num % 10);
- /*
- * Second word
- */
- w = serialnum[1];
- /*
- * Year - 6th digit.
- *
- * If bit 15 of third word is set, then the
- * last digit of the year is greater than 7.
- */
- if (serialnum[2] & 0x8000) {
- *cp++ = '8' + ((w & 0x1C0) >> 6);
- } else {
- *cp++ = '0' + ((w & 0x1C0) >> 6);
- }
- /* Week of year - 7th, 8th digits. */
- num = w & 0x003F;
- *cp++ = '0' + num / 10;
- num %= 10;
- *cp++ = '0' + num;
- /*
- * Third word
- */
- w = serialnum[2] & 0x7FFF;
- /* Serial number - 9th digit. */
- *cp++ = 'A' + (w / 1000);
- /* 10th, 11th, 12th digits. */
- num = w % 1000;
- *cp++ = '0' + num / 100;
- num %= 100;
- *cp++ = '0' + num / 10;
- num %= 10;
- *cp++ = '0' + num;
- *cp = ' '; /* Null Terminate the string. */
- return ASC_TRUE;
- }
- }
- /*
- * asc_prt_asc_board_eeprom()
- *
- * Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- int leftlen;
- int totlen;
- int len;
- ASCEEP_CONFIG *ep;
- int i;
- #ifdef CONFIG_ISA
- int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
- #endif /* CONFIG_ISA */
- uchar serialstr[13];
- boardp = ASC_BOARDP(shp);
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- ep = &boardp->eep_config.asc_eep;
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nEEPROM Settings for AdvanSys SCSI Host %d:n", shp->host_no);
- ASC_PRT_NEXT();
- if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
- ASC_TRUE) {
- len = asc_prt_line(cp, leftlen, " Serial Number: %sn", serialstr);
- ASC_PRT_NEXT();
- } else {
- if (ep->adapter_info[5] == 0xBB) {
- len = asc_prt_line(cp, leftlen,
- " Default Settings Used for EEPROM-less Adapter.n");
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.n");
- ASC_PRT_NEXT();
- }
- }
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %un",
- ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " cntl 0x%x, no_scam 0x%xn",
- ep->cntl, ep->no_scam);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- #ifdef CONFIG_ISA
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- len = asc_prt_line(cp, leftlen,
- " Host ISA DMA speed: %d MB/Sn",
- isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
- ASC_PRT_NEXT();
- }
- #endif /* CONFIG_ISA */
- return totlen;
- }
- /*
- * asc_prt_adv_board_eeprom()
- *
- * Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- ADV_DVC_VAR *adv_dvc_varp;
- int leftlen;
- int totlen;
- int len;
- int i;
- char *termstr;
- uchar serialstr[13];
- ADVEEP_3550_CONFIG *ep_3550 = NULL;
- ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
- ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
- ushort word;
- ushort *wordp;
- ushort sdtr_speed = 0;
- boardp = ASC_BOARDP(shp);
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- ep_3550 = &boardp->eep_config.adv_3550_eep;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
- } else
- {
- ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
- }
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nEEPROM Settings for AdvanSys SCSI Host %d:n", shp->host_no);
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- wordp = &ep_3550->serial_number_word1;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- wordp = &ep_38C0800->serial_number_word1;
- } else
- {
- wordp = &ep_38C1600->serial_number_word1;
- }
- if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
- len = asc_prt_line(cp, leftlen, " Serial Number: %sn", serialstr);
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.n");
- ASC_PRT_NEXT();
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %un",
- ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
- ep_3550->max_dvc_qng);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %un",
- ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
- ep_38C0800->max_dvc_qng);
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %un",
- ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng,
- ep_38C1600->max_dvc_qng);
- ASC_PRT_NEXT();
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->termination;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->termination_lvd;
- } else
- {
- word = ep_38C1600->termination_lvd;
- }
- switch (word) {
- case 1:
- termstr = "Low Off/High Off";
- break;
- case 2:
- termstr = "Low Off/High On";
- break;
- case 3:
- termstr = "Low On/High On";
- break;
- default:
- case 0:
- termstr = "Automatic";
- break;
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%xn",
- ep_3550->termination, termstr, ep_3550->bios_ctrl);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%xn",
- ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%xn",
- ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen,
- " Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %X", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->disc_enable;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->disc_enable;
- } else
- {
- word = ep_38C1600->disc_enable;
- }
- len = asc_prt_line(cp, leftlen,
- " Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->tagqng_able;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->tagqng_able;
- } else
- {
- word = ep_38C1600->tagqng_able;
- }
- len = asc_prt_line(cp, leftlen,
- " Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->start_motor;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->start_motor;
- } else
- {
- word = ep_38C1600->start_motor;
- }
- len = asc_prt_line(cp, leftlen,
- " Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
- " Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
- " Ultra Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->wdtr_able;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->wdtr_able;
- } else
- {
- word = ep_38C1600->wdtr_able;
- }
- len = asc_prt_line(cp, leftlen,
- " Wide Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
- adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600)
- {
- len = asc_prt_line(cp, leftlen,
- " Synchronous Transfer Speed (Mhz):n ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- char *speed_str;
- if (i == 0)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed1;
- } else if (i == 4)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed2;
- } else if (i == 8)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed3;
- } else if (i == 12)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed4;
- }
- switch (sdtr_speed & ADV_MAX_TID)
- {
- case 0: speed_str = "Off"; break;
- case 1: speed_str = " 5"; break;
- case 2: speed_str = " 10"; break;
- case 3: speed_str = " 20"; break;
- case 4: speed_str = " 40"; break;
- case 5: speed_str = " 80"; break;
- default: speed_str = "Unk"; break;
- }
- len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
- ASC_PRT_NEXT();
- if (i == 7)
- {
- len = asc_prt_line(cp, leftlen, "n ");
- ASC_PRT_NEXT();
- }
- sdtr_speed >>= 4;
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- }
- return totlen;
- }
- /*
- * asc_prt_driver_conf()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int chip_scsi_id;
- int i;
- boardp = ASC_BOARDP(shp);
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:n",
- shp->host_no);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %un",
- shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
- shp->max_channel);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %un",
- shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
- shp->cmd_per_lun);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " unchecked_isa_dma %d, use_clustering %d, loaded_as_module %dn",
- shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%xn",
- boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port);
- ASC_PRT_NEXT();
- /* 'shp->n_io_port' may be truncated because it is only one byte. */
- len = asc_prt_line(cp, leftlen,
- " io_port 0x%x, n_io_port 0x%xn",
- shp->io_port, shp->n_io_port);
- ASC_PRT_NEXT();
- 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 (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) {
- len = asc_prt_line(cp, leftlen, " queue_depth:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- if (boardp->device[i] == NULL) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%d",
- i, boardp->device[i]->queue_depth);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- }
- return totlen;
- }
- /*
- * asc_prt_asc_board_info()
- *
- * Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- int chip_scsi_id;
- int leftlen;
- int totlen;
- int len;
- ASC_DVC_VAR *v;
- ASC_DVC_CFG *c;
- int i;
- int renegotiate = 0;
- boardp = ASC_BOARDP(shp);
- v = &boardp->dvc_var.asc_dvc_var;
- c = &boardp->dvc_cfg.asc_dvc_cfg;
- chip_scsi_id = c->chip_scsi_id;
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:n",
- shp->host_no);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%xn",
- c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " mcode_version 0x%x, err_code %un",
- c->mcode_version, v->err_code);
- ASC_PRT_NEXT();
- /* Current number of commands waiting for the host. */
- len = asc_prt_line(cp, leftlen,
- " Total Command Pending: %dn", v->cur_total_qng);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Command Queuing:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- /* Current number of commands waiting for a device. */
- len = asc_prt_line(cp, leftlen,
- " Command Queue Pending:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- /* Current limit on number of commands that can be sent to a device. */
- len = asc_prt_line(cp, leftlen,
- " Command Queue Limit:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- /* Indicate whether the device has returned queue full status. */
- len = asc_prt_line(cp, leftlen,
- " Command Queue Full:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X:Y-%d",
- i, boardp->queue_full_cnt[i]);
- } else {
- len = asc_prt_line(cp, leftlen, " %X:N", i);
- }
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- uchar syn_period_ix;
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
- ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
- if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
- {
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
- } else
- {
- syn_period_ix =
- (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
- len = asc_prt_line(cp, leftlen,
- " Transfer Period Factor: %d (%d.%d Mhz),",
- v->sdtr_period_tbl[syn_period_ix],
- 250 / v->sdtr_period_tbl[syn_period_ix],
- ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
- ASC_PRT_NEXT();
- }
- if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*n");
- renegotiate = 1;
- } else
- {
- len = asc_prt_line(cp, leftlen, "n");
- }
- ASC_PRT_NEXT();
- }
- if (renegotiate)
- {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.n");
- ASC_PRT_NEXT();
- }
- return totlen;
- }
- /*
- * asc_prt_adv_board_info()
- *
- * Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
- {
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int i;
- ADV_DVC_VAR *v;
- ADV_DVC_CFG *c;
- AdvPortAddr iop_base;
- ushort chip_scsi_id;
- ushort lramword;
- uchar lrambyte;
- ushort tagqng_able;
- ushort sdtr_able, wdtr_able;
- ushort wdtr_done, sdtr_done;
- ushort period = 0;
- int renegotiate = 0;
- boardp = ASC_BOARDP(shp);
- v = &boardp->dvc_var.adv_dvc_var;
- c = &boardp->dvc_cfg.adv_dvc_cfg;
- iop_base = v->iop_base;
- chip_scsi_id = v->chip_scsi_id;
- leftlen = cplen;
- totlen = len = 0;
- len = asc_prt_line(cp, leftlen,
- "nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:n",
- shp->host_no);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " iop_base 0x%lx, cable_detect: %X, err_code %un",
- v->iop_base,
- AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
- v->err_code);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%xn",
- c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
- ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- len = asc_prt_line(cp, leftlen,
- " Queuing Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Queue Limit:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " Command Pending:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- len = asc_prt_line(cp, leftlen,
- " Wide Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
- len = asc_prt_line(cp, leftlen,
- " Transfer Bit Width:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
- lramword);
- len = asc_prt_line(cp, leftlen, " %X:%d",
- i, (lramword & 0x8000) ? 16 : 8);
- ASC_PRT_NEXT();
- if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
- (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*");
- ASC_PRT_NEXT();
- renegotiate = 1;
- }
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- len = asc_prt_line(cp, leftlen,
- " Synchronous Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "n");
- ASC_PRT_NEXT();
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
- for (i = 0; i <= ADV_MAX_TID; i++) {
- AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
- lramword);
- lramword &= ~0x8000;
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
- ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
- if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
- {
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
- ASC_PRT_NEXT();
- if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
- {
- len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
- ASC_PRT_NEXT();
- } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
- {
- len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
- ASC_PRT_NEXT();
- } else /* 20 Mhz or below. */
- {
- period = (((lramword >> 8) * 25) + 50)/4;
- if (period == 0) /* Should never happen. */
- {
- len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
- "%d (%d.%d Mhz),",
- period, 250/period, ASC_TENTHS(250, period));
- ASC_PRT_NEXT();
- }
- }
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- lramword & 0x1F);
- ASC_PRT_NEXT();
- }
- if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*n");
- renegotiate = 1;
- } else
- {
- len = asc_prt_line(cp, leftlen, "n");
- }
- ASC_PRT_NEXT();
- }
- if (renegotiate)
- {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.n");
- ASC_PRT_NEXT();
- }
- return totlen;
- }
- /*
- * asc_proc_copy()
- *
- * Copy proc information to a read buffer taking into account the current
- * read offset in the file and the remaining space in the read buffer.
- */
- STATIC int
- asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
- char *cp, int cplen)
- {
- int cnt = 0;
- ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %dn",
- (unsigned) offset, (unsigned) advoffset, cplen);
- if (offset <= advoffset) {
- /* Read offset below current offset, copy everything. */
- cnt = ASC_MIN(cplen, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %dn",
- (ulong) curbuf, (ulong) cp, cnt);
- memcpy(curbuf, cp, cnt);
- } else if (offset < advoffset + cplen) {
- /* Read offset within current range, partial copy. */
- cnt = (advoffset + cplen) - offset;
- cp = (cp + cplen) - cnt;
- cnt = ASC_MIN(cnt, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %dn",
- (ulong) curbuf, (ulong) cp, cnt);
- memcpy(curbuf, cp, cnt);
- }
- return cnt;
- }
- /*
- * asc_prt_line()
- *
- * If 'cp' is NULL print to the console, otherwise print to a buffer.
- *
- * Return 0 if printing to the console, otherwise return the number of
- * bytes written to the buffer.
- *
- * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
- * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
- */
- STATIC int
- asc_prt_line(char *buf, int buflen, char *fmt, ...)
- {
- va_list args;
- int ret;
- char s[ASC_PRTLINE_SIZE];
- va_start(args, fmt);
- ret = vsprintf(s, fmt, args);
- ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
- if (buf == NULL) {
- (void) printk(s);
- ret = 0;
- } else {
- ret = ASC_MIN(buflen, ret);
- memcpy(buf, s, ret);
- }
- va_end(args);
- return ret;
- }
- #endif /* CONFIG_PROC_FS */
- /*
- * --- Functions Required by the Asc Library
- */
- /*
- * Delay for 'n' milliseconds. Don't use the 'jiffies'
- * global variable which is incremented once every 5 ms
- * from a timer interrupt, because this function may be
- * called when interrupts are disabled.
- */
- STATIC void
- DvcSleepMilliSecond(ADV_DCNT n)
- {
- ASC_DBG1(4, "DvcSleepMilliSecond: %lun", (ulong) n);
- mdelay(n);
- }
- /*
- * Currently and inline noop but leave as a placeholder.
- * Leave DvcEnterCritical() as a noop placeholder.
- */
- STATIC inline ulong
- DvcEnterCritical(void)
- {
- return 0;
- }
- /*
- * Critical sections are all protected by the board spinlock.
- * Leave DvcLeaveCritical() as a noop placeholder.
- */
- STATIC inline void
- DvcLeaveCritical(ulong flags)
- {
- return;
- }
- /*
- * void
- * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
- *
- * Calling/Exit State:
- * none
- *
- * Description:
- * Output an ASC_SCSI_Q structure to the chip
- */
- STATIC void
- DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
- {
- int i;
- ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- if (i == 4 || i == 20) {
- continue;
- }
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort) outbuf[i + 1] << 8) | outbuf[i]);
- }
- }
- /*
- * void
- * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
- *
- * Calling/Exit State:
- * none
- *
- * Description:
- * Input an ASC_QDONE_INFO structure from the chip
- */
- STATIC void
- DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
- {
- int i;
- ushort word;
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- if (i == 10) {
- continue;
- }
- word = inpw(iop_base + IOP_RAM_DATA);
- inbuf[i] = word & 0xff;
- inbuf[i + 1] = (word >> 8) & 0xff;
- }
- ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
- }
- /*
- * Read a PCI configuration byte.
- */
- ASC_INITFUNC(
- STATIC uchar,
- DvcReadPCIConfigByte(
- ASC_DVC_VAR *asc_dvc,
- ushort offset)
- )
- {
- #ifdef CONFIG_PCI
- uchar byte_data;
- pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
- PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
- ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
- offset, &byte_data);
- return byte_data;
- #else /* !defined(CONFIG_PCI) */
- return 0;
- #endif /* !defined(CONFIG_PCI) */
- }
- /*
- * Write a PCI configuration byte.
- */
- ASC_INITFUNC(
- STATIC void,
- DvcWritePCIConfigByte(
- ASC_DVC_VAR *asc_dvc,
- ushort offset,
- uchar byte_data)
- )
- {
- #ifdef CONFIG_PCI
- pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
- PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
- ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
- offset, byte_data);
- #endif /* CONFIG_PCI */
- }
- /*
- * Return the BIOS address of the adapter at the specified
- * I/O port and with the specified bus type.
- */
- ASC_INITFUNC(
- STATIC ushort,
- AscGetChipBiosAddress(
- PortAddr iop_base,
- ushort bus_type
- )
- )
- {
- ushort cfg_lsw;
- ushort bios_addr;
- /*
- * The PCI BIOS is re-located by the motherboard BIOS. Because
- * of this the driver can not determine where a PCI BIOS is
- * loaded and executes.
- */
- if (bus_type & ASC_IS_PCI)
- {
- return(0);
- }
- #ifdef CONFIG_ISA
- if((bus_type & ASC_IS_EISA) != 0)
- {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- cfg_lsw &= 0x000F;
- bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
- (cfg_lsw * ASC_BIOS_BANK_SIZE));
- return(bios_addr);
- }/* if */
- #endif /* CONFIG_ISA */
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- /*
- * ISA PnP uses the top bit as the 32K BIOS flag
- */
- if (bus_type == ASC_IS_ISAPNP)
- {
- cfg_lsw &= 0x7FFF;
- }/* if */
- bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
- ASC_BIOS_MIN_ADDR);
- return(bios_addr);
- }
- /*
- * --- Functions Required by the Adv Library
- */
- /*
- * DvcGetPhyAddr()
- *
- * Return the physical address of 'vaddr' and set '*lenp' to the
- * number of physically contiguous bytes that follow 'vaddr'.
- * 'flag' indicates the type of structure whose physical address
- * is being translated.
- *
- * Note: Because Linux currently doesn't page the kernel and all
- * kernel buffers are physically contiguous, leave '*lenp' unchanged.
- */
- ADV_PADDR
- DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
- uchar *vaddr, ADV_SDCNT *lenp, int flag)
- {
- ADV_PADDR paddr;
- paddr = virt_to_bus(vaddr);
- ASC_DBG4(4,
- "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lxn",
- (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
- return paddr;
- }
- /*
- * Read a PCI configuration byte.
- */
- ASC_INITFUNC(
- STATIC uchar,
- DvcAdvReadPCIConfigByte(
- ADV_DVC_VAR *asc_dvc,
- ushort offset)
- )
- {
- #ifdef CONFIG_PCI
- uchar byte_data;
- pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
- PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
- ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
- offset, &byte_data);
- return byte_data;
- #else /* CONFIG_PCI */
- return 0;
- #endif /* CONFIG_PCI */
- }
- /*
- * Write a PCI configuration byte.
- */
- ASC_INITFUNC(
- STATIC void,
- DvcAdvWritePCIConfigByte(
- ADV_DVC_VAR *asc_dvc,
- ushort offset,
- uchar byte_data)
- )
- {
- #ifdef CONFIG_PCI
- pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info),
- PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info),
- ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)),
- offset, byte_data);
- #else /* CONFIG_PCI */
- return 0;
- #endif /* CONFIG_PCI */
- }
- /*
- * --- Tracing and Debugging Functions
- */
- #ifdef ADVANSYS_STATS
- #ifdef CONFIG_PROC_FS
- /*
- * asc_prt_board_stats()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
- */
- STATIC int
- asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
- {
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- asc_board_t *boardp;
- leftlen = cplen;
- totlen = len = 0;
- boardp = ASC_BOARDP(shp);
- s = &boardp->asc_stats;
- len = asc_prt_line(cp, leftlen,
- "nLinux Driver Statistics for AdvanSys SCSI Host %d:n", shp->host_no);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lun",
- s->queuecommand, s->reset, s->biosparam, s->interrupt);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lun",
- s->callback, s->done, s->build_error, s->adv_build_noreq,
- s->adv_build_nosg);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lun",
- s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
- ASC_PRT_NEXT();
- /*
- * Display data transfer statistics.
- */
- if (s->cont_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
- s->cont_xfer/2,
- ASC_TENTHS(s->cont_xfer, 2));
- ASC_PRT_NEXT();
- /* Contiguous transfer average size */
- len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kbn",
- (s->cont_xfer/2)/s->cont_cnt,
- ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
- ASC_PRT_NEXT();
- }
- if (s->sg_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
- s->sg_cnt, s->sg_elem);
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kbn",
- s->sg_xfer/2,