📄 3w-xxxx.c
字号:
if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); request_id = TW_RESID_OUT(response_queue.response_id); if (request_id != 0) { /* unexpected request id */ printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ tw_decode_sense(tw_dev, request_id, 0); return 1; } } return 0;} /* End tw_initconnection() *//* Set a value in the features table */static int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val){ TW_Param *param; TW_Command *command_packet; TW_Response_Queue response_queue; int request_id = 0; unsigned long command_que_value; unsigned long param_value; /* Initialize SetParam command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n"); return 1; } command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; memset(command_packet, 0, sizeof(TW_Sector)); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); param->table_id = 0x404; /* Features table */ param->parameter_id = parm; param->parameter_size_bytes = param_size; memcpy(param->data, val, param_size); param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad alignment physical 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]); } command_packet->byte8.param.sgl[0].address = param_value; command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); command_packet->size = 4; command_packet->request_id = request_id; command_packet->byte6.parameter_count = 1; command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n"); return 1; } /* Send command packet to the board */ outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); /* Poll for completion */ if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); request_id = TW_RESID_OUT(response_queue.response_id); if (request_id != 0) { /* unexpected request id */ printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ tw_decode_sense(tw_dev, request_id, 0); return 1; } } return 0;} /* End tw_setfeature() *//* This function will reset a controller */static int tw_reset_sequence(TW_Device_Extension *tw_dev) { int error = 0; int tries = 0; unsigned char c = 1; /* Reset the board */ while (tries < TW_MAX_RESET_TRIES) { TW_SOFT_RESET(tw_dev); error = tw_aen_drain_queue(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no); tries++; continue; } /* Now the controller is in a good state */ break; } if (tries >= TW_MAX_RESET_TRIES) { printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no); return 1; } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no); return 1; } error = tw_setfeature(tw_dev, 2, 1, &c); if (error) { printk(KERN_WARNING "3w-xxxx: Unable to set features for card, probable old firmware or card.\n"); } return 0;} /* End tw_reset_sequence() *//* This function will initialize the fields of a device extension */static int tw_initialize_device_extension(TW_Device_Extension *tw_dev){ int i, error=0; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); /* Initialize command packet buffers */ error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0); if (error) { printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n"); return 1; } /* Initialize generic buffer */ error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1); if (error) { printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n"); return 1; } for (i=0;i<TW_Q_LENGTH;i++) { tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; } tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; mutex_init(&tw_dev->ioctl_lock); init_waitqueue_head(&tw_dev->ioctl_wqueue); return 0;} /* End tw_initialize_device_extension() */static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd){ int use_sg; dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n"); use_sg = scsi_dma_map(cmd); if (use_sg < 0) { printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n"); return 0; } cmd->SCp.phase = TW_PHASE_SGLIST; cmd->SCp.have_data_in = use_sg; return use_sg;} /* End tw_map_scsi_sg_data() */static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd){ dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); scsi_dma_unmap(cmd);} /* End tw_unmap_scsi_data() *//* This function will reset a device extension */static int tw_reset_device_extension(TW_Device_Extension *tw_dev){ int i = 0; struct scsi_cmnd *srb; unsigned long flags = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n"); set_bit(TW_IN_RESET, &tw_dev->flags); TW_DISABLE_INTERRUPTS(tw_dev); TW_MASK_COMMAND_INTERRUPT(tw_dev); spin_lock_irqsave(tw_dev->host->host_lock, flags); /* Abort all requests that are in progress */ for (i=0;i<TW_Q_LENGTH;i++) { if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { srb = tw_dev->srb[i]; if (srb != NULL) { srb->result = (DID_RESET << 16); tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]); } } } /* Reset queues and counts */ for (i=0;i<TW_Q_LENGTH;i++) { tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; } tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_START; tw_dev->posted_request_count = 0; tw_dev->pending_request_count = 0; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; tw_dev->reset_print = 0; spin_unlock_irqrestore(tw_dev->host->host_lock, flags); if (tw_reset_sequence(tw_dev)) { printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); return 1; } TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); clear_bit(TW_IN_RESET, &tw_dev->flags); tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; return 0;} /* End tw_reset_device_extension() *//* This funciton returns unit geometry in cylinders/heads/sectors */static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { int heads, sectors, cylinders; TW_Device_Extension *tw_dev; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n"); tw_dev = (TW_Device_Extension *)sdev->host->hostdata; heads = 64; sectors = 32; cylinders = sector_div(capacity, heads * sectors); if (capacity >= 0x200000) { heads = 255; sectors = 63; cylinders = sector_div(capacity, heads * sectors); } dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders); geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return 0;} /* End tw_scsi_biosparam() *//* This is the new scsi eh reset function */static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) { TW_Device_Extension *tw_dev=NULL; int retval = FAILED; tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; tw_dev->num_resets++; sdev_printk(KERN_WARNING, SCpnt->device, "WARNING: Command (0x%x) timed out, resetting card.\n", SCpnt->cmnd[0]); /* Make sure we are not issuing an ioctl or resetting from ioctl */ mutex_lock(&tw_dev->ioctl_lock); /* Now reset the card and some of the device extension data */ if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); goto out; } retval = SUCCESS;out: mutex_unlock(&tw_dev->ioctl_lock); return retval;} /* End tw_scsi_eh_reset() *//* This function handles scsi inquiry commands */static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id){ TW_Param *param; TW_Command *command_packet; unsigned long command_que_value; unsigned long param_value; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n"); /* 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_scsiop_inquiry(): Bad command packet virtual address.\n"); return 1; } memset(command_packet, 0, sizeof(TW_Sector)); command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); command_packet->size = 4; command_packet->request_id = request_id; command_packet->status = 0; command_packet->flags = 0; command_packet->byte6.parameter_count = 1; /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment virtual address.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; memset(param, 0, sizeof(TW_Sector)); param->table_id = 3; /* unit summary table */ param->parameter_id = 3; /* unitsstatus parameter */ param->parameter_size_bytes = TW_MAX_UNITS; param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n"); return 1; } command_packet->byte8.param.sgl[0].address = param_value; command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n"); return 1; } /* Now try to post the command packet */ tw_post_command_packet(tw_dev, request_id); return 0;} /* End tw_scsiop_inquiry() */static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, void *data, unsigned int len){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -