?? 3w-xxxx.c
字號:
/* Poll for completion */ if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { response_queue.value = inl(response_que_addr); request_id = (unsigned char)response_queue.u.response_id; if (request_id != 0) { /* unexpected request id */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ tw_decode_sense(tw_dev, request_id, 0); return 1; } found = 1; } if (found == 0) { /* response never received */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; is_unit_present = (unsigned char *)&(param->data[0]); /* Show all units present */ imax = TW_MAX_UNITS; for(i=0; i<imax; i++) { if (is_unit_present[i] == 0) { tw_dev->is_unit_present[i] = FALSE; } else { if (is_unit_present[i] & TW_UNIT_ONLINE) { dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): Unit %d found.\n", i); tw_dev->is_unit_present[i] = TRUE; num_units++; } } } tw_dev->num_units = num_units; if (num_units == 0) { dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); return 1; } return 0;} /* End tw_initialize_units() *//* This function is the interrupt service routine */static irqreturn_t tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { int request_id; u32 status_reg_addr, status_reg_value; u32 response_que_addr; TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; TW_Response_Queue response_que; int error = 0, retval = 0; unsigned long flags = 0; TW_Command *command_packet; int handled = 0; dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* See if we are already running on another processor */ if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags)) return IRQ_NONE; /* Get the host lock for io completions */ spin_lock_irqsave(tw_dev->host->host_lock, flags); /* See if the interrupt matches this instance */ if (tw_dev->tw_pci_dev->irq == irq) { handled = 1; /* Make sure io isn't queueing */ spin_lock(&tw_dev->tw_lock); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; status_reg_value = inl(status_reg_addr); /* Check if this is our interrupt, otherwise bail */ if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) goto tw_interrupt_bail; /* Check controller for errors */ if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); if (tw_decode_bits(tw_dev, status_reg_value, 1)) { tw_clear_all_interrupts(tw_dev); goto tw_interrupt_bail; } } /* Handle host interrupt */ if (status_reg_value & TW_STATUS_HOST_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n"); tw_clear_host_interrupt(tw_dev); } /* Handle attention interrupt */ if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } } /* Handle command interrupt */ if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { /* Drain as many pending commands as we can */ while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; if (tw_dev->state[request_id] != TW_S_PENDING) { printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no); break; } if (tw_post_command_packet(tw_dev, request_id)==0) { if (tw_dev->pending_head == TW_Q_LENGTH-1) { tw_dev->pending_head = TW_Q_START; } else { tw_dev->pending_head = tw_dev->pending_head + 1; } tw_dev->pending_request_count--; } else { /* If we get here, we will continue re-posting on the next command interrupt */ break; } } /* If there are no more pending requests, we mask command interrupt */ if (tw_dev->pending_request_count == 0) tw_mask_command_interrupt(tw_dev); } /* Handle response interrupt */ if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { /* Drain the response queue from the board */ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { /* Read response queue register */ response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; error = 0; /* Check for bad response */ if (command_packet->status != 0) { /* If internal command, don't error, don't fill sense */ if (tw_dev->srb[request_id] == 0) { tw_decode_sense(tw_dev, request_id, 0); } else { error = tw_decode_sense(tw_dev, request_id, 1); } } /* Check for correct state */ if (tw_dev->state[request_id] != TW_S_POSTED) { /* Handle timed out ioctl's */ if (tw_dev->srb[request_id] != 0) { if (tw_dev->srb[request_id]->cmnd[0] != TW_IOCTL) { printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode); error = 1; } } } dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); /* Check for internal command completion */ if (tw_dev->srb[request_id] == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); /* Check for chrdev ioctl completion */ if (request_id != tw_dev->chrdev_request_id) { retval = tw_aen_complete(tw_dev, request_id); if (retval) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); } } else { tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; wake_up(&tw_dev->ioctl_wqueue); } } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: case READ_6: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n"); break; case WRITE_10: case WRITE_6: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n"); break; case TEST_UNIT_READY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n"); error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id); break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); error = tw_scsiop_inquiry_complete(tw_dev, request_id); break; case READ_CAPACITY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n"); error = tw_scsiop_read_capacity_complete(tw_dev, request_id); break; case MODE_SENSE: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n"); error = tw_scsiop_mode_sense_complete(tw_dev, request_id); break; case SYNCHRONIZE_CACHE: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n"); break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n"); error = tw_ioctl_complete(tw_dev, request_id); break; default: printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n"); error = 1; } /* If no error command was a success */ if (error == 0) { tw_dev->srb[request_id]->result = (DID_OK << 16); } /* If error, command failed */ if (error == 1) { /* Ask for a host reset */ tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } /* Now complete the io */ if ((error != TW_ISR_DONT_COMPLETE)) { tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); } } /* Check for valid status after each drain */ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); if (tw_decode_bits(tw_dev, status_reg_value, 1)) { tw_clear_all_interrupts(tw_dev); goto tw_interrupt_bail; } } } }tw_interrupt_bail: spin_unlock(&tw_dev->tw_lock); } else dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n"); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); clear_bit(TW_IN_INTR, &tw_dev->flags); return IRQ_RETVAL(handled);} /* End tw_interrupt() *//* This function handles ioctls from userspace to the driver */int tw_ioctl(TW_Device_Extension *tw_dev, int request_id){ unsigned char opcode; int bufflen, error = 0; TW_Param *param; TW_Command *command_packet, *command_save; unsigned long param_value; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; int tw_aen_code, i, use_sg; unsigned long *data_ptr; int total_bytes = 0, posted = 0; dma_addr_t dma_handle; struct timeval before, timeout; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; if (ioctl == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Request buffer NULL.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } bufflen = tw_dev->srb[request_id]->request_bufflen; /* Initialize command packet */ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad command packet virtual address.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } memset(command_packet, 0, sizeof(TW_Sector)); /* Initialize param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment virtual address.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; memset(param, 0, sizeof(TW_Sector)); dprintk(KERN_NOTICE "opcode = %d table_id = %d parameter_id = %d parameter_size_bytes = %d\n", ioctl->opcode, ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes); opcode = ioctl->opcode; switch (opcode) { case TW_OP_NOP: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_NOP.\n"); command_packet->byte0.opcode = TW_OP_NOP; break; case TW_OP_GET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n"); command_packet->byte0.opcode = TW_OP_GET_PARAM; command_packet->byte3.unit = ioctl->unit_index; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; tw_dev->ioctl_size[request_id] = ioctl->parameter_size_bytes; dprintk(KERN_NOTICE "table_id = %d parameter_id = %d parameter_size_bytes %d\n", param->table_id, param->parameter_id, param->parameter_size_bytes); break; case TW_OP_SET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n", ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes); if (ioctl->data != NULL) { command_packet->byte0.opcode = TW_OP_SET_PARAM; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes); break; } else { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); return 1; } case TW_OP_AEN_LISTEN: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n"); if (tw_dev->aen_head == tw_dev->aen_tail) { /* aen queue empty */ dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Aen queue empty.\n"); tw_ae
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -