3ware 5/6/7/8000 driver v1.26.02.000
PATCH 2/3 3ware 5/6/7/8000 driver v1.26.02.000
drivers/scsi/3w-xxxx.c +566 -1092
@@ -1369,1263 +1288,737 @@ tw_dev->pending_head =TW_Q_START ; tw_dev->pending_tail =TW_Q_START ; -spin_lock_init (&tw_dev->tw_lock); tw_dev->chrdev_request_id =TW_IOCTL_CHRDEV_FREE ; +init_MUTEX (&tw_dev->ioctl_sem); +init_waitqueue_head (&tw_dev->ioctl_wqueue); +return 0 ; }/* End tw_initialize_device_extension() */ -/* This function will get unit info from the controller */ -int tw_initialize_units (TW_Device_Extension *tw_dev) +static int tw_map_scsi_sg_data (struct pci_dev *pdev,struct scsi_cmnd *cmd) { -int found =0 ; -unsigned char request_id =0 ; -TW_Command *command_packet; -TW_Param *param; -int i, imax, num_units =0 ; -unsigned long command_que_value; -u32 command_que_addr; -u32 response_que_addr; -TW_Response_Queue response_queue; -unsigned long param_value; -unsigned char *is_unit_present; - -dprintk (KERN_NOTICE "3w-xxxx: tw_initialize_units()\n" ); +int use_sg; - command_que_addr = tw_dev->registers.command_que_addr; - response_que_addr = tw_dev->registers.response_que_addr; - -/* Setup the command packet */ +dprintk (KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n" ); + +if (cmd->use_sg ==0 ) +return 0 ; + + use_sg =pci_map_sg (pdev, cmd->buffer, cmd->use_sg,DMA_BIDIRECTIONAL ); + +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 u32 tw_map_scsi_single_data (struct pci_dev *pdev,struct scsi_cmnd *cmd) +{ +dma_addr_t mapping; + +dprintk (KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n" ); + +if (cmd->request_bufflen ==0 ) +return 0 ; + + mapping =pci_map_page (pdev,virt_to_page (cmd->request_buffer),offset_in_page (cmd->request_buffer), cmd->request_bufflen,DMA_BIDIRECTIONAL ); + +if (mapping ==0 ) { +printk (KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n" ); +return 0 ; + } + + cmd->SCp.phase =TW_PHASE_SINGLE ; + cmd->SCp.have_data_in = mapping; + +return mapping; +}/* End tw_map_scsi_single_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" ); + +switch (cmd->SCp.phase) { +case TW_PHASE_SINGLE : +pci_unmap_page (pdev, cmd->SCp.have_data_in, cmd->request_bufflen,DMA_BIDIRECTIONAL ); +break ; +case TW_PHASE_SGLIST : +pci_unmap_sg (pdev, cmd->request_buffer, cmd->use_sg,DMA_BIDIRECTIONAL ); +break ; + } +}/* End tw_unmap_scsi_data() */ + +/* This function will reset a device extension */ +static int tw_reset_device_extension (TW_Device_Extension *tw_dev,int ioctl_reset) +{ +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); + +/* Wake up any ioctl that was pending before the reset */ +if ((tw_dev->chrdev_request_id ==TW_IOCTL_CHRDEV_FREE ) || (ioctl_reset)) { +clear_bit (TW_IN_RESET , &tw_dev->flags); + }else { + tw_dev->chrdev_request_id =TW_IOCTL_CHRDEV_FREE ; +wake_up (&tw_dev->ioctl_wqueue); + } + +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; + +spin_unlock_irq (tw_dev->host->host_lock); + + tw_dev->num_resets++; + +printk (KERN_WARNING "3w-xxxx: scsi%d: WARNING: Unit #%d: Command (0x%x) timed out, resetting card.\n" , tw_dev->host->host_no, SCpnt->device->id, SCpnt->cmnd[0 ]); + +/* Now reset the card and some of the device extension data */ +if (tw_reset_device_extension (tw_dev,0 )) { +printk (KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n" , tw_dev->host->host_no); + goto out; + } + + retval =SUCCESS ; +out: +spin_lock_irq (tw_dev->host->host_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_initialize_units(): Bad command packet virtual address.\n" ); +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->byte0.opcode =TW_OP_GET_PARAM ; - command_packet->byte0.sgl_offset =2 ; - command_packet->size =4 ; - command_packet->request_id = request_id; - command_packet->byte3.unit =0 ; - command_packet->byte3.host_id =0 ; - command_packet->status =0 ; - command_packet->flags =0 ; - command_packet->byte6.block_count =1 ; + 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_initialize_units(): Bad alignment virtual address.\n" ); +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 ;/* unitstatus parameter */ + 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_initialize_units(): Bad alignment physical address.\n" ); +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); - -/* Post the command packet to the board */ command_que_value = tw_dev->command_packet_physical_address[request_id];if (command_que_value ==0 ) { -printk (KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n" ); +printk (KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n" );return 1 ; } -outl (command_que_value, command_que_addr); -/* 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" ); +/* Now try to post the command packet */ +tw_post_command_packet (tw_dev, request_id); + +return 0 ; +}/* End tw_scsiop_inquiry() */ + +/* This function is called by the isr to complete an inquiry command */ +static int tw_scsiop_inquiry_complete (TW_Device_Extension *tw_dev,int request_id) +{ +unsigned char *is_unit_present; +unsigned char *request_buffer; +TW_Param *param; + +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n" ); + +/* Fill request buffer */ +if (tw_dev->srb[request_id]->request_buffer ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n" );return 1 ; } + request_buffer = tw_dev->srb[request_id]->request_buffer; +memset (request_buffer,0 , tw_dev->srb[request_id]->request_bufflen); + request_buffer[0 ] =TYPE_DISK ;/* Peripheral device type */ + request_buffer[1 ] =0 ;/* Device type modifier */ + request_buffer[2 ] =0 ;/* No ansi/iso compliance */ + request_buffer[4 ] =31 ;/* Additional length */ +memcpy (&request_buffer[8 ],"3ware " ,8 );/* Vendor ID */ +sprintf (&request_buffer[16 ],"Logical Disk %-2d " , tw_dev->srb[request_id]->device->id); +memcpy (&request_buffer[32 ], tw_driver_version,3 ); 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++; - } - } +if (param ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n" ); +return 1 ; } - tw_dev->num_units = num_units; + is_unit_present = &(param->data[0 ]); -if (num_units ==0 ) { -dprintk (KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n" ); -return 1 ; +if (is_unit_present[tw_dev->srb[request_id]->device->id] &TW_UNIT_ONLINE ) { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] =1 ; + }else { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] =0 ; + tw_dev->srb[request_id]->result = (DID_BAD_TARGET <<16 ); +return TW_ISR_DONT_RESULT ; }return 0 ; -}/* End tw_initialize_units() */ +}/* End tw_scsiop_inquiry_complete() */ -/* This function is the interrupt service routine */ -static irqreturn_t tw_interrupt (int irq,void *dev_instance, -struct pt_regs *regs) +/* This function handles scsi mode_sense commands */ +static int tw_scsiop_mode_sense (TW_Device_Extension *tw_dev,int request_id) { -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_Param *param;TW_Command *command_packet; -int handled =0 ; +unsigned long command_que_value; +unsigned long param_value; -dprintk (KERN_WARNING "3w-xxxx: tw_interrupt()\n" ); +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n" ); -/* See if we are already running on another processor */ -if (test_and_set_bit (TW_IN_INTR , &tw_dev->flags)) -return IRQ_NONE ; +/* Only page control = 0, page code = 0x8 (cache page) supported */ +if (tw_dev->srb[request_id]->cmnd[2 ] !=0x8 ) { + 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 ; + } -/* Get the host lock for io completions */ -spin_lock_irqsave (tw_dev->host->host_lock, flags); +/* Now read firmware cache setting for this unit */ + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; +if (command_packet ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n" ); +return 1 ; + } -/* See if the interrupt matches this instance */ -if (tw_dev->tw_pci_dev->irq == irq) { +/* Setup the command packet */ +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 ; - handled =1 ; -/* Make sure io isn't queueing */ -spin_lock (&tw_dev->tw_lock); +/* Setup the param */ +if (tw_dev->alignment_virtual_address[request_id] ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n" ); +return 1 ; + } -/* 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 ; - } - } - } + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; +memset (param,0 ,sizeof (TW_Sector)); + param->table_id =TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id; + param->parameter_id =7 ;/* unit flags */ + param->parameter_size_bytes =1 ; + param_value = tw_dev->alignment_physical_address[request_id]; +if (param_value ==0 ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n" ); +return 1 ; + } -dprintk (KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n" , request_id); + 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_mode_sense(): Bad command packet physical address.\n" ); +return 1 ; + } -/* 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 ; - } +/* Now try to post the command packet */ +tw_post_command_packet (tw_dev, request_id); + +return 0 ; +}/* End tw_scsiop_mode_sense() */ -/* If no error command was a success */ -if (error ==0 ) { - tw_dev->srb[request_id]->result = (DID_OK <<16 ); - } +/* This function is called by the isr to complete a mode sense command */ +static int tw_scsiop_mode_sense_complete (TW_Device_Extension *tw_dev,int request_id) +{ +TW_Param *param; +unsigned char *flags; +unsigned char *request_buffer; -/* If error, command failed */ -if (error ==1 ) { -/* Ask for a host reset */ - tw_dev->srb[request_id]->result = (DID_OK <<16 ) | (CHECK_CONDITION <<1 ); - } +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n" ); -/* 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]); + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; +if (param ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n" ); +return 1 ; + } + flags = (char *)&(param->data[0 ]); + request_buffer = tw_dev->srb[request_id]->buffer; +memset (request_buffer,0 , tw_dev->srb[request_id]->request_bufflen); -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" ); + request_buffer[0 ] =0xf ;/* mode data length */ + request_buffer[1 ] =0 ;/* default medium type */ + request_buffer[2 ] =0x10 ;/* dpo/fua support on */ + request_buffer[3 ] =0 ;/* no block descriptors */ + request_buffer[4 ] =0x8 ;/* caching page */ + request_buffer[5 ] =0xa ;/* page length */ +if (*flags &0x1 ) + request_buffer[6 ] =0x4 ;/* WCE on */ +else + request_buffer[6 ] =0x0 ;/* WCE off */ -spin_unlock_irqrestore (tw_dev->host->host_lock, flags); -clear_bit (TW_IN_INTR , &tw_dev->flags); -return IRQ_RETVAL (handled); -}/* End tw_interrupt() */ +return 0 ; +}/* End tw_scsiop_mode_sense_complete() */ -/* This function handles ioctls from userspace to the driver */ -int tw_ioctl (TW_Device_Extension *tw_dev,int request_id) +/* This function handles scsi read_capacity commands */ +static int tw_scsiop_read_capacity (TW_Device_Extension *tw_dev,int request_id) { -unsigned char opcode; -int bufflen, error =0 ;TW_Param *param; -TW_Command *command_packet, *command_save; +TW_Command *command_packet; +unsigned long command_que_value;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; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\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_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 ; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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->unit__hostid =TW_UNITHOST_IN (0 , tw_dev->srb[request_id]->device->id); + command_packet->status =0 ; + command_packet->flags =0 ; + command_packet->byte6.block_count =1 ; -/* Initialize param */ +/* Now setup the 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 ; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n" ); +return 1 ; } 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_aen_code =TW_AEN_QUEUE_EMPTY ; -memcpy (tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes); - }else { -/* Copy aen queue entry to request buffer */ -dprintk (KERN_NOTICE "3w-xxxx: tw_ioctl(): Returning aen 0x%x\n" , tw_dev->aen_queue[tw_dev->aen_head]); - tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head]; -memcpy (tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes); -if (tw_dev->aen_head ==TW_Q_LENGTH -1 ) { - tw_dev->aen_head =TW_Q_START ; - }else { - tw_dev->aen_head = tw_dev->aen_head +1 ; - } - } - 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 ; -case TW_ATA_PASSTHRU : -if (ioctl->data !=NULL ) { -memcpy (command_packet, ioctl->data,sizeof (TW_Command)); - command_packet->request_id = request_id; - }else { -printk (KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n" ); -return 1 ; - } - - passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id]; -/* Don't load sg_list for non-data ATA cmds */ -if ((passthru->param !=0 ) && (passthru->param !=0x8 )) { - passthru->sg_list[0 ].length = passthru->sector_count*512 ; -if (passthru->sg_list[0 ].length >TW_MAX_PASSTHRU_BYTES ) { -printk (KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n" , passthru->sg_list[0 ].length); -return 1 ; - } - passthru->sg_list[0 ].address = tw_dev->alignment_physical_address[request_id]; - } -tw_post_command_packet (tw_dev, request_id); -return 0 ; -case TW_CMD_PACKET : -dprintk (KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET.\n" ); -if (ioctl->data !=NULL ) { -memcpy (command_packet, ioctl->data,sizeof (TW_Command)); - command_packet->request_id = request_id; -tw_post_command_packet (tw_dev, request_id); -return 0 ; - }else { -printk (KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n" ); -return 1 ; - } -case TW_CMD_PACKET_WITH_DATA : -dprintk (KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n" ); - command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id]; -if (command_save ==NULL ) { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n" , tw_dev->host->host_no); -return 1 ; - } -if (ioctl->data !=NULL ) { -/* Copy down the command packet */ -memcpy (command_packet, ioctl->data,sizeof (TW_Command)); -memcpy (command_save, ioctl->data,sizeof (TW_Command)); - command_packet->request_id = request_id; - -/* Now deal with the two possible sglists */ -if (command_packet->byte0.sgl_offset ==2 ) { - use_sg = command_packet->size -3 ; -for (i=0 ;i<use_sg;i++) - total_bytes+=command_packet->byte8.param.sgl[i].length; - tw_dev->ioctl_data[request_id] =pci_alloc_consistent (tw_dev->tw_pci_dev, total_bytes, &dma_handle); - -if (!tw_dev->ioctl_data[request_id]) { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n" , tw_dev->host->host_no, request_id); -return 1 ; - } - -/* Copy param sglist into the kernel */ - data_ptr = tw_dev->ioctl_data[request_id]; -for (i=0 ;i<use_sg;i++) { -if (command_packet->byte8.param.sgl[i].address !=0 ) { - error =copy_from_user (data_ptr, (void *)(unsigned long )command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length); -if (error) { -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n" , tw_dev->host->host_no); - goto tw_ioctl_bail; - } - }else { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n" , tw_dev->host->host_no); - tw_dev->srb[request_id]->result = (DID_RESET <<16 ); - goto tw_ioctl_bail; - } - data_ptr+=command_packet->byte8.param.sgl[i].length; - } - command_packet->size =4 ; - command_packet->byte8.param.sgl[0 ].address = dma_handle; - command_packet->byte8.param.sgl[0 ].length = total_bytes; - } -if (command_packet->byte0.sgl_offset ==3 ) { - use_sg = command_packet->size -4 ; -for (i=0 ;i<use_sg;i++) - total_bytes+=command_packet->byte8.io.sgl[i].length; - tw_dev->ioctl_data[request_id] =pci_alloc_consistent (tw_dev->tw_pci_dev, total_bytes, &dma_handle); - -if (!tw_dev->ioctl_data[request_id]) { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n" , tw_dev->host->host_no, request_id); -return 1 ; - } -if (command_packet->byte0.opcode ==TW_OP_WRITE ) { -/* Copy io sglist into the kernel */ - data_ptr = tw_dev->ioctl_data[request_id]; -for (i=0 ;i<use_sg;i++) { -if (command_packet->byte8.io.sgl[i].address !=0 ) { - error =copy_from_user (data_ptr, (void *)(unsigned long )command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length); -if (error) { -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n" , tw_dev->host->host_no); - goto tw_ioctl_bail; - } - }else { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n" , tw_dev->host->host_no); - tw_dev->srb[request_id]->result = (DID_RESET <<16 ); - goto tw_ioctl_bail; - } - data_ptr+=command_packet->byte8.io.sgl[i].length; - } - } - command_packet->size =5 ; - command_packet->byte8.io.sgl[0 ].address = dma_handle; - command_packet->byte8.io.sgl[0 ].length = total_bytes; - } - -spin_unlock (&tw_dev->tw_lock); -spin_unlock_irq (tw_dev->host->host_lock); - -set_bit (TW_IN_IOCTL , &tw_dev->flags); - -/* Finally post the command packet */ -tw_post_command_packet (tw_dev, request_id); - posted =1 ; -do_gettimeofday (&before); - - tw_ioctl_retry: -mdelay (TW_IOCTL_WAIT_TIME ); -if (test_bit (TW_IN_IOCTL , &tw_dev->flags)) { -do_gettimeofday (&timeout); -if (before.tv_sec +TW_IOCTL_TIMEOUT < timeout.tv_sec) { -spin_lock_irq (tw_dev->host->host_lock); -spin_lock (&tw_dev->tw_lock); - goto tw_ioctl_bail; - }else { - goto tw_ioctl_retry; - } - } - -spin_lock_irq (tw_dev->host->host_lock); -spin_lock (&tw_dev->tw_lock); - -if (signal_pending (current)) { -dprintk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n" , tw_dev->host->host_no); - tw_dev->srb[request_id]->result = (DID_OK <<16 ); - goto tw_ioctl_bail; - } - - tw_dev->srb[request_id]->result = (DID_OK <<16 ); -/* Now copy up the param or io sglist to userspace */ -if (command_packet->byte0.sgl_offset ==2 ) { - use_sg = command_save->size -3 ; - data_ptr = tw_dev->ioctl_data[request_id]; -for (i=0 ;i<use_sg;i++) { -if (command_save->byte8.param.sgl[i].address !=0 ) { - error =copy_to_user ((void *)(unsigned long )command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length); -if (error) { -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n" , tw_dev->host->host_no); - goto tw_ioctl_bail; - } -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n" , tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid); - data_ptr+=command_save->byte8.param.sgl[i].length; - }else { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n" , tw_dev->host->host_no); - tw_dev->srb[request_id]->result = (DID_RESET <<16 ); - goto tw_ioctl_bail; - } - } - } -if (command_packet->byte0.sgl_offset ==3 ) { - use_sg = command_save->size -4 ; -if (command_packet->byte0.opcode ==TW_OP_READ ) { - data_ptr = tw_dev->ioctl_data[request_id]; -for (i=0 ;i<use_sg;i++) { -if (command_save->byte8.io.sgl[i].address !=0 ) { - error =copy_to_user ((void *)(unsigned long )command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length); -if (error) { -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n" , tw_dev->host->host_no); - goto tw_ioctl_bail; - } -dprintk (KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n" , tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid); - data_ptr+=command_save->byte8.io.sgl[i].length; - }else { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n" , tw_dev->host->host_no); - tw_dev->srb[request_id]->result = (DID_RESET <<16 ); - goto tw_ioctl_bail; - } - } - } - } - - tw_ioctl_bail: - -/* Free up sglist memory */ -if (tw_dev->ioctl_data[request_id]) -pci_free_consistent (tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle); -else -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n" , tw_dev->host->host_no); - -/* Now complete the io */ - tw_dev->state[request_id] =TW_S_COMPLETED ; -tw_state_request_finish (tw_dev, request_id); -if (posted) - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done (tw_dev->srb[request_id]); -return 0 ; - }else { -printk (KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n" ); -return 1 ; - } -default : -dprintk (KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n" , opcode); - 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->table_id =TW_UNIT_INFORMATION_TABLE_BASE + + tw_dev->srb[request_id]->device->id; + param->parameter_id =4 ;/* unitcapacity parameter */ + param->parameter_size_bytes =4 ; param_value = tw_dev->alignment_physical_address[request_id];if (param_value ==0 ) { -printk (KERN_WARNING "3w-xxxx: tw_ioctl(): 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]); +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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_packet->byte0.sgl_offset =2 ; - command_packet->size =4 ; - command_packet->request_id = request_id; - command_packet->byte3.host_id =0 ; - command_packet->status =0 ; - command_packet->flags =0 ; - command_packet->byte6.parameter_count =1 ; + command_que_value = tw_dev->command_packet_physical_address[request_id]; +if (command_que_value ==0 ) { +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n" ); +return 1 ; + }/* Now try to post the command to the board */ tw_post_command_packet (tw_dev, request_id); - +return 0 ; -}/* End tw_ioctl() */ +}/* End tw_scsiop_read_capacity() */ -/* This function is called by the isr to complete ioctl requests */ -int tw_ioctl_complete (TW_Device_Extension *tw_dev,int request_id) +/* This function is called by the isr to complete a readcapacity command */ +static int tw_scsiop_read_capacity_complete (TW_Device_Extension *tw_dev,int request_id) {unsigned char *param_data; -unsigned char *buff; +u32 capacity; +char *buff;TW_Param *param; -TW_Ioctl *ioctl =NULL ; -TW_Passthru *passthru =NULL ; -TW_Command *command_packet; - ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; -dprintk (KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n" ); +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n" ); + buff = tw_dev->srb[request_id]->request_buffer;if (buff ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n" ); +printk (KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n" );return 1 ; } - - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; -if (command_packet ==NULL ) { -printk (KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n" , tw_dev->host->host_no); +memset (buff,0 , tw_dev->srb[request_id]->request_bufflen); + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; +if (param ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n" );return 1 ; } + param_data = &(param->data[0 ]); -dprintk (KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n" , tw_dev->srb[request_id]->request_bufflen); + capacity = (param_data[3 ] <<24 ) | (param_data[2 ] <<16 ) | + (param_data[1 ] <<8 ) | param_data[0 ]; - ioctl = (TW_Ioctl *)buff; -switch (ioctl->opcode) { -case TW_ATA_PASSTHRU : - passthru = (TW_Passthru *)ioctl->data; -/* Don't return data for non-data ATA cmds */ -if ((passthru->param !=0 ) && (passthru->param !=0x8 )) -memcpy (buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count *512 ); -else { -/* For non-data cmds, return cmd pkt */ -if (tw_dev->srb[request_id]->request_bufflen >=sizeof (TW_Command)) -memcpy (buff, tw_dev->command_packet_virtual_address[request_id],sizeof (TW_Command)); - } -break ; -case TW_CMD_PACKET_WITH_DATA : -dprintk (KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n" ); -clear_bit (TW_IN_IOCTL , &tw_dev->flags); -return TW_ISR_DONT_COMPLETE ;/* Special case for isr to not complete io */ -default : -memset (buff,0 , tw_dev->srb[request_id]->request_bufflen); - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; -if (param ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Bad alignment virtual address.\n" ); -return 1 ; - } - param_data = &(param->data[0 ]); -memcpy (buff, param_data, tw_dev->ioctl_size[request_id]); - } -return 0 ; -}/* End tw_ioctl_complete() */ +/* Subtract one sector to fix get last sector ioctl */ + capacity -=1 ; -static int tw_map_scsi_sg_data (struct pci_dev *pdev,Scsi_Cmnd *cmd) -{ -int use_sg; -int dma_dir =scsi_to_pci_dma_dir (cmd->sc_data_direction); +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n" , capacity); -dprintk (KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n" ); - -if (cmd->use_sg ==0 ) -return 0 ; +/* Number of LBA's */ + buff[0 ] = (capacity >>24 ); + buff[1 ] = (capacity >>16 ) &0xff ; + buff[2 ] = (capacity >>8 ) &0xff ; + buff[3 ] = capacity &0xff ; - use_sg =pci_map_sg (pdev, cmd->buffer, cmd->use_sg, dma_dir); - -if (use_sg ==0 ) { -printk (KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n" ); -return 0 ; - } +/* Block size in bytes (512) */ + buff[4 ] = (TW_BLOCK_SIZE >>24 ); + buff[5 ] = (TW_BLOCK_SIZE >>16 ) &0xff ; + buff[6 ] = (TW_BLOCK_SIZE >>8 ) &0xff ; + buff[7 ] =TW_BLOCK_SIZE &0xff ; - cmd->SCp.phase =2 ; - cmd->SCp.have_data_in = use_sg; - -return use_sg; -}/* End tw_map_scsi_sg_data() */ +return 0 ; +}/* End tw_scsiop_read_capacity_complete() */ -static u32 tw_map_scsi_single_data (struct pci_dev *pdev,Scsi_Cmnd *cmd) +/* This function handles scsi read or write commands */ +static int tw_scsiop_read_write (TW_Device_Extension *tw_dev,int request_id) { -dma_addr_t mapping; -int dma_dir =scsi_to_pci_dma_dir (cmd->sc_data_direction); - -dprintk (KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n" ); +TW_Command *command_packet; +unsigned long command_que_value; +u32 lba =0x0 , num_sectors =0x0 , buffaddr =0x0 ; +int i, use_sg; +struct scsi_cmnd *srb; +struct scatterlist *sglist; -if (cmd->request_bufflen ==0 ) -return 0 ; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n" ); - mapping =pci_map_page (pdev,virt_to_page (cmd->request_buffer),offset_in_page (cmd->request_buffer), cmd->request_bufflen, dma_dir); +if (tw_dev->srb[request_id]->request_buffer ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n" ); +return 1 ; + } + sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; + srb = tw_dev->srb[request_id]; -if (mapping ==0 ) { -printk (KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n" ); -return 0 ; +/* Initialize command packet */ + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; +if (command_packet ==NULL ) { +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n" ); +return 1 ; } - cmd->SCp.phase =1 ; - cmd->SCp.have_data_in = mapping; +if (srb->cmnd[0 ] ==READ_6 || srb->cmnd[0 ] ==READ_10 ) { + command_packet->opcode__sgloffset =TW_OPSGL_IN (3 ,TW_OP_READ ); + }else { + command_packet->opcode__sgloffset =TW_OPSGL_IN (3 ,TW_OP_WRITE ); + } -return mapping; -}/* End tw_map_scsi_single_data() */ + command_packet->size =3 ; + command_packet->request_id = request_id; + command_packet->unit__hostid =TW_UNITHOST_IN (0 , srb->device->id); + command_packet->status =0 ; + command_packet->flags =0 ; -/* This function will mask the command interrupt */ -void tw_mask_command_interrupt (TW_Device_Extension *tw_dev) -{ -u32 control_reg_addr, control_reg_value; - - control_reg_addr = tw_dev->registers.control_reg_addr; - control_reg_value =TW_CONTROL_MASK_COMMAND_INTERRUPT ; -outl (control_reg_value, control_reg_addr); -}/* End tw_mask_command_interrupt() */ +if (srb->cmnd[0 ] ==WRITE_10 ) { +if ((srb->cmnd[1 ] &0x8 ) || (srb->cmnd[1 ] &0x10 )) + command_packet->flags =1 ; + } -/* This function will poll the status register for a flag */ -int tw_poll_status (TW_Device_Extension *tw_dev,u32 flag,int seconds) -{ -u32 status_reg_addr, status_reg_value; -struct timeval before, timeout; +if (srb->cmnd[0 ] ==READ_6 || srb->cmnd[0 ] ==WRITE_6 ) { + lba = ((u32 )srb->cmnd[1 ] <<16 ) | ((u32 )srb->cmnd[2 ] <<8 ) | (u32 )srb->cmnd[3 ]; + num_sectors = (u32 )srb->cmnd[4 ]; + }else { + lba = ((u32 )srb->cmnd[2 ] <<24 ) | ((u32 )srb->cmnd[3 ] <<16 ) | ((u32 )srb->cmnd[4 ] <<8 ) | (u32 )srb->cmnd[5 ]; + num_sectors = (u32 )srb->cmnd[8 ] | ((u32 )srb->cmnd[7 ] <<8 ); + } + +/* Update sector statistic */ + tw_dev->sector_count = num_sectors; +if (tw_dev->sector_count > tw_dev->max_sector_count) + tw_dev->max_sector_count = tw_dev->sector_count; + +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n" , lba, num_sectors); + command_packet->byte8.io.lba = lba; + command_packet->byte6.block_count = num_sectors; - status_reg_addr = tw_dev->registers.status_reg_addr; -do_gettimeofday (&before); - status_reg_value =inl (status_reg_addr); +/* Do this if there are no sg list entries */ +if (tw_dev->srb[request_id]->use_sg ==0 ) { +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n" ); + buffaddr =tw_map_scsi_single_data (tw_dev->tw_pci_dev, tw_dev->srb[request_id]); +if (buffaddr ==0 ) +return 1 ; -if (tw_check_bits (status_reg_value)) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n" ); -tw_decode_bits (tw_dev, status_reg_value,0 ); + command_packet->byte8.io.sgl[0 ].address = buffaddr; + command_packet->byte8.io.sgl[0 ].length = tw_dev->srb[request_id]->request_bufflen; + command_packet->size+=2 ; } - -while ((status_reg_value & flag) != flag) { - status_reg_value =inl (status_reg_addr); - -if (tw_check_bits (status_reg_value)) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n" ); -tw_decode_bits (tw_dev, status_reg_value,0 ); - } -do_gettimeofday (&timeout); -if (before.tv_sec + seconds < timeout.tv_sec) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n" , flag); +/* Do this if we have multiple sg list entries */ +if (tw_dev->srb[request_id]->use_sg >0 ) { + use_sg =tw_map_scsi_sg_data (tw_dev->tw_pci_dev, tw_dev->srb[request_id]); +if (use_sg ==0 )return 1 ; + +for (i=0 ;i<use_sg; i++) { + command_packet->byte8.io.sgl[i].address =sg_dma_address (&sglist[i]); + command_packet->byte8.io.sgl[i].length =sg_dma_len (&sglist[i]); + command_packet->size+=2 ; } -mdelay (5 ); } -return 0 ; -}/* End tw_poll_status() */ -/* This function will poll the status register for disappearance of a flag */ -int tw_poll_status_gone (TW_Device_Extension *tw_dev,u32 flag,int seconds) -{ -u32 status_reg_addr, status_reg_value; -struct timeval before, timeout; - - status_reg_addr = tw_dev->registers.status_reg_addr; -do_gettimeofday (&before); - status_reg_value =inl (status_reg_addr); +/* Update SG statistics */ + tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg; +if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) + tw_dev->max_sgl_entries = tw_dev->sgl_entries; -if (tw_check_bits (status_reg_value)) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n" ); -tw_decode_bits (tw_dev, status_reg_value,0 ); + command_que_value = tw_dev->command_packet_physical_address[request_id]; +if (command_que_value ==0 ) { +dprintk (KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n" ); +return 1 ; } + +/* Now try to post the command to the board */ +tw_post_command_packet (tw_dev, request_id); -while ((status_reg_value & flag) !=0 ) { - status_reg_value =inl (status_reg_addr); +return 0 ; +}/* End tw_scsiop_read_write() */ -if (tw_check_bits (status_reg_value)) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n" ); -tw_decode_bits (tw_dev, status_reg_value,0 ); - } - -do_gettimeofday (&timeout); -if (before.tv_sec + seconds < timeout.tv_sec) { -dprintk (KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n" , flag); -return 1 ; - } -mdelay (5 ); - } -return 0 ; -}/* End tw_poll_status_gone() */ - -/* This function will attempt to post a command packet to the board */ -int tw_post_command_packet (TW_Device_Extension *tw_dev,int request_id) +/* This function will handle the request sense scsi command */ +static int tw_scsiop_request_sense (TW_Device_Extension *tw_dev,int request_id) { -u32 status_reg_addr, status_reg_value; -unsigned long command_que_value; -u32 command_que_addr; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n" ); -dprintk (KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n" ); - command_que_addr = tw_dev->registers.command_que_addr; - command_que_value = tw_dev->command_packet_physical_address[request_id]; - status_reg_addr = tw_dev->registers.status_reg_addr; - status_reg_value =inl (status_reg_addr); +/* For now we just zero the request buffer */ +memset (tw_dev->srb[request_id]->request_buffer,0 , tw_dev->srb[request_id]->request_bufflen); + tw_dev->state[request_id] =TW_S_COMPLETED ; +tw_state_request_finish (tw_dev, request_id); -if (tw_check_bits (status_reg_value)) { -dprintk (KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n" ); -tw_decode_bits (tw_dev, status_reg_value,1 ); - } +/* If we got a request_sense, we probably want a reset, return error */ + tw_dev->srb[request_id]->result = (DID_ERROR <<16 ); + tw_dev->srb[request_id]->scsi_done (tw_dev->srb[request_id]); -if ((status_reg_value &TW_STATUS_COMMAND_QUEUE_FULL ) ==0 ) { -/* We successfully posted the command packet */ -outl (command_que_value, command_que_addr); - tw_dev->state[request_id] =TW_S_POSTED ; - tw_dev->posted_request_count++; -if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { - tw_dev->max_posted_request_count = tw_dev->posted_request_count; - } - }else { -/* Couldn't post the command packet, so we do it in the isr */ -if (tw_dev->state[request_id] !=TW_S_PENDING ) { - tw_dev->state[request_id] =TW_S_PENDING ; - tw_dev->pending_request_count++; -if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { - tw_dev->max_pending_request_count = tw_dev->pending_request_count; - } - tw_dev->pending_queue[tw_dev->pending_tail] = request_id; -if (tw_dev->pending_tail ==TW_Q_LENGTH -1 ) { - tw_dev->pending_tail =TW_Q_START ; - }else { - tw_dev->pending_tail = tw_dev->pending_tail +1 ; - } - } -tw_unmask_command_interrupt (tw_dev); -return 1 ; - }return 0 ; -}/* End tw_post_command_packet() */ +}/* End tw_scsiop_request_sense() */ -/* This function will reset a device extension */ -int tw_reset_device_extension (TW_Device_Extension *tw_dev) +/* This function will handle synchronize cache scsi command */ +static int tw_scsiop_synchronize_cache (TW_Device_Extension *tw_dev,int request_id) { -int imax =0 ; -int i =0 ; -Scsi_Cmnd *srb; +TW_Command *command_packet; +unsigned long command_que_value; -dprintk (KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n" ); - imax =TW_Q_LENGTH ; +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n" ); -if (tw_reset_sequence (tw_dev)) { -printk (KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n" , tw_dev->host->host_no); +/* Send firmware flush command for this unit */ + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; +if (command_packet ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n" );return 1 ; } -/* Abort all requests that are in progress */ -for (i=0 ;i<imax;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]); - } - } +/* Setup the command packet */ +memset (command_packet,0 ,sizeof (TW_Sector)); + command_packet->opcode__sgloffset =TW_OPSGL_IN (0 ,TW_OP_FLUSH_CACHE ); + command_packet->size =2 ; + command_packet->request_id = request_id; + command_packet->unit__hostid =TW_UNITHOST_IN (0 , tw_dev->srb[request_id]->device->id); + command_packet->status =0 ; + command_packet->flags =0 ; + 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_scsiop_synchronize_cache(): Bad command packet physical address.\n" ); +return 1 ; } -/* Reset queues and counts */ -for (i=0 ;i<imax;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 ; - tw_dev->chrdev_request_id =TW_IOCTL_CHRDEV_FREE ; +/* Now try to post the command packet */ +tw_post_command_packet (tw_dev, request_id);return 0 ; -}/* End tw_reset_device_extension() */ +}/* End tw_scsiop_synchronize_cache() */ -/* This function will reset a controller */ -int tw_reset_sequence (TW_Device_Extension *tw_dev) +/* This function will handle test unit ready scsi command */ +static int tw_scsiop_test_unit_ready (TW_Device_Extension *tw_dev,int request_id) { -int error =0 ; -int tries =0 ; - -/* Disable interrupts */ -tw_disable_interrupts (tw_dev); - -/* 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 ; - } +TW_Param *param; +TW_Command *command_packet; +unsigned long command_que_value; +unsigned long param_value; -/* 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 ; - } +dprintk (KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n" ); -/* Now the controller is in a good state */ -break ; +/* 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_test_unit_ready(): 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 ; -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); +/* Now setup the param */ +if (tw_dev->alignment_virtual_address[request_id] ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n" );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); + 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_test_unit_ready(): Bad alignment physical address.\n" );return 1 ; } -/* Re-enable interrupts */ -tw_enable_and_clear_interrupts (tw_dev); - -return 0 ; -}/* End tw_reset_sequence() */ - -/* This funciton returns unit geometry in cylinders/heads/sectors */ -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 = (unsigned long )capacity / (heads * sectors); - -if (capacity >=0x200000 ) { - heads =255 ; - sectors =63 ; - cylinders = (unsigned long )capacity / (heads * sectors); + 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_test_unit_ready(): Bad command packet physical address.\n" ); +return 1 ; } -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; +/* Now try to post the command packet */ +tw_post_command_packet (tw_dev, request_id);return 0 ; -}/* End tw_scsi_biosparam() */ - -/* This function will find and initialize any cards */ -int tw_scsi_detect (Scsi_Host_Template *tw_host) -{ -int ret; - -dprintk (KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n" ); - -printk (KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n" , tw_driver_version); - - ret =tw_findcards (tw_host); - -return ret; -}/* End tw_scsi_detect() */ +}/* End tw_scsiop_test_unit_ready() */ -/* This is the new scsi eh abort function */ -int tw_scsi_eh_abort (Scsi_Cmnd *SCpnt) +/* This function is called by the isr to complete a testunitready command */ +static int tw_scsiop_test_unit_ready_complete (TW_Device_Extension *tw_dev,int request_id) { -TW_Device_Extension *tw_dev=NULL ; -int i =0 ; - -dprintk (KERN_NOTICE "3w-xxxx: tw_scsi_eh_abort()\n" ); +unsigned char *is_unit_present; +TW_Param *param; -if (!SCpnt) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid Scsi_Cmnd.\n" ); -return (FAILED ); - } +dprintk (KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n" ); - tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; -if (tw_dev ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid device extension.\n" ); -return (FAILED ); + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; +if (param ==NULL ) { +printk (KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n" ); +return 1 ; } + is_unit_present = &(param->data[0 ]); -spin_lock (&tw_dev->tw_lock); - tw_dev->num_aborts++; - -/* If the command hasn't been posted yet, we can do the abort */ -for (i=0 ;i<TW_Q_LENGTH ;i++) { -if (tw_dev->srb[i] == SCpnt) { -if (tw_dev->state[i] ==TW_S_STARTED ) { -printk (KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n" , tw_dev->host->host_no, tw_dev->srb[i]==0 ?0 : tw_dev->srb[i]->device->id, SCpnt); - tw_dev->state[i] =TW_S_COMPLETED ; -tw_state_request_finish (tw_dev, i); -spin_unlock (&tw_dev->tw_lock); -return (SUCCESS ); - } -if (tw_dev->state[i] ==TW_S_PENDING ) { -printk (KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n" , tw_dev->host->host_no, tw_dev->srb[i]==0 ?0 : tw_dev->srb[i]->device->id, SCpnt); -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--; - tw_dev->state[i] =TW_S_COMPLETED ; -tw_state_request_finish (tw_dev, i); -spin_unlock (&tw_dev->tw_lock); -return (SUCCESS ); - } -if (tw_dev->state[i] ==TW_S_POSTED ) { -/* If the command has already been posted, we have to reset the card */ -printk (KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n" , tw_dev->host->host_no, tw_dev->srb[i]==0 ?0 : tw_dev->srb[i]->device->id, SCpnt); -/* We have to let AEN requests through before the reset */ -spin_unlock (&tw_dev->tw_lock); -spin_unlock_irq (tw_dev->host->host_lock); -mdelay (TW_AEN_WAIT_TIME ); -spin_lock_irq (tw_dev->host->host_lock); -spin_lock (&tw_dev->tw_lock); - -if (tw_reset_device_extension (tw_dev)) { -dprintk (KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n" , tw_dev->host->host_no); -spin_unlock (&tw_dev->tw_lock); -return (FAILED ); - } - } - } +if (is_unit_present[tw_dev->srb[request_id]->device->id] &TW_UNIT_ONLINE ) { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] =1 ; + }else { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] =0 ; + tw_dev->srb[request_id]->result = (DID_BAD_TARGET <<16 ); +return TW_ISR_DONT_RESULT ; } -spin_unlock (&tw_dev->tw_lock); -return (SUCCESS ); -}/* End tw_scsi_eh_abort() */ +return 0 ; +}/* End tw_scsiop_test_unit_ready_complete() */ -/* This is the new scsi eh reset function */ -int tw_scsi_eh_reset (Scsi_Cmnd *SCpnt) +/* This is the main scsi queue function to handle scsi opcodes */ +static int tw_scsi_queue (struct scsi_cmnd *SCpnt,void (*done)(struct scsi_cmnd *)) { -TW_Device_Extension *tw_dev=NULL ; - -dprintk (KERN_NOTICE "3w-xxxx: tw_scsi_eh_reset()\n" ); - -if (!SCpnt) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid Scsi_Cmnd.\n" ); -return (FAILED ); - } - - tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; -if (tw_dev ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid device extension.\n" ); -return (FAILED ); - } +unsigned char *command = SCpnt->cmnd; +int request_id =0 ; +int retval =1 ; +TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; -/* We have to let AEN requests through before the reset */ -spin_unlock_irq (tw_dev->host->host_lock); -mdelay (TW_AEN_WAIT_TIME ); -spin_lock_irq (tw_dev->host->host_lock); +/* Save done function into Scsi_Cmnd struct */ + SCpnt->scsi_done = done; + +/* Queue the command and get a request id */ +tw_state_request_start (tw_dev, &request_id); -spin_lock (&tw_dev->tw_lock); - tw_dev->num_resets++; +/* Save the scsi command for use by the ISR */ + tw_dev->srb[request_id] = SCpnt; -/* 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); -spin_unlock (&tw_dev->tw_lock); -return (FAILED ); - } -printk (KERN_WARNING "3w-xxxx: scsi%d: Reset succeeded.\n" , tw_dev->host->host_no); -spin_unlock (&tw_dev->tw_lock); - -return (SUCCESS ); -}/* End tw_scsi_eh_reset() */ - -/* This function handles input and output from /proc/scsi/3w-xxxx/x */ -int tw_scsi_proc_info (struct Scsi_Host *shost,char *buffer,char **start, -off_t offset,int length,int inout) -{ -TW_Device_Extension *tw_dev =NULL ; -TW_Info info; -int i; -int j; - -dprintk (KERN_NOTICE "3w-xxxx: tw_scsi_proc_info()\n" ); - -/* Find the correct device extension */ -for (i=0 ;i<tw_device_extension_count;i++) -if (tw_device_extension_list[i]->host->host_no == shost->host_no) - tw_dev = tw_device_extension_list[i]; -if (tw_dev ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n" ); -return (-EINVAL ); - } - - info.buffer = buffer; - info.length = length; - info.offset = offset; - info.position =0 ; - -if (inout) { -/* Write */ -if (strncmp (buffer,"debug" ,5 ) ==0 ) { -printk (KERN_INFO "3w-xxxx: Posted commands:\n" ); -for (j=0 ;j<TW_Q_LENGTH ;j++) { -if (tw_dev->state[j] ==TW_S_POSTED ) { -TW_Command *command = (TW_Command *)tw_dev->command_packet_virtual_address[j]; -printk (KERN_INFO "3w-xxxx: Request_id: %d\n" , j); -printk (KERN_INFO "Opcode: 0x%x\n" , command->byte0.opcode); -printk (KERN_INFO "Block_count: 0x%x\n" , command->byte6.block_count); -printk (KERN_INFO "LBA: 0x%x\n" , command->byte8.io.lba); -printk (KERN_INFO "Physical command packet addr: 0x%lx\n" , tw_dev->command_packet_physical_address[j]); -printk (KERN_INFO "Scsi_Cmnd: %p\n" , tw_dev->srb[j]); - } - } -printk (KERN_INFO "3w-xxxx: Free_head: %3d\n" , tw_dev->free_head); -printk (KERN_INFO "3w-xxxx: Free_tail: %3d\n" , tw_dev->free_tail); - } -return length; - }else { -/* Read */ -if (start) { - *start = buffer; - } -tw_copy_info (&info,"scsi%d: 3ware Storage Controller\n" , shost->host_no); -tw_copy_info (&info,"Driver version: %s\n" , tw_driver_version); -tw_copy_info (&info,"Current commands posted: %3d\n" , tw_dev->posted_request_count); -tw_copy_info (&info,"Max commands posted: %3d\n" , tw_dev->max_posted_request_count); -tw_copy_info (&info,"Current pending commands: %3d\n" , tw_dev->pending_request_count); -tw_copy_info (&info,"Max pending commands: %3d\n" , tw_dev->max_pending_request_count); -tw_copy_info (&info,"Last sgl length: %3d\n" , tw_dev->sgl_entries); -tw_copy_info (&info,"Max sgl length: %3d\n" , tw_dev->max_sgl_entries); -tw_copy_info (&info,"Last sector count: %3d\n" , tw_dev->sector_count); -tw_copy_info (&info,"Max sector count: %3d\n" , tw_dev->max_sector_count); -tw_copy_info (&info,"Resets: %3d\n" , tw_dev->num_resets); -tw_copy_info (&info,"Aborts: %3d\n" , tw_dev->num_aborts); -tw_copy_info (&info,"AEN's: %3d\n" , tw_dev->aen_count); - } -if (info.position > info.offset) { -return (info.position - info.offset); - }else { -return 0 ; - } -}/* End tw_scsi_proc_info() */ - -/* This is the main scsi queue function to handle scsi opcodes */ -int tw_scsi_queue (Scsi_Cmnd *SCpnt,void (*done)(Scsi_Cmnd *)) -{ -unsigned char *command = SCpnt->cmnd; -int request_id =0 ; -int error =0 ; -TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - -if (tw_dev ==NULL ) { -printk (KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n" ); - SCpnt->result = (DID_ERROR <<16 ); -done (SCpnt); -return 0 ; - } - -spin_lock (&tw_dev->tw_lock); -dprintk (KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n" ); - -/* Skip scsi command if it isn't for us */ -if ((SCpnt->device->channel !=0 ) || (SCpnt->device->lun !=0 )) { - SCpnt->result = (DID_BAD_TARGET <<16 ); -done (SCpnt); -spin_unlock (&tw_dev->tw_lock); -return 0 ; - } - -/* Save done function into Scsi_Cmnd struct */ - SCpnt->scsi_done = done; - -/* Queue the command and get a request id */ -tw_state_request_start (tw_dev, &request_id); - -/* Save the scsi command for use by the ISR */ - tw_dev->srb[request_id] = SCpnt; - -/* Initialize phase to zero */ - SCpnt->SCp.phase =0 ; +/* Initialize phase to zero */ + SCpnt->SCp.phase =TW_PHASE_INITIAL ;switch (*command) {case READ_10 :