Commit f7148255 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB hpusbscsi driver

Port changes from 2.4:
  We do request_sense ourselves to comply with
  the scanner command set
parent c32692c6
......@@ -129,6 +129,9 @@ hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
if (scsi_register_host(&new->ctempl))
goto err_out;
new->sense_command[0] = REQUEST_SENSE;
new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
/* adding to list for module unload */
list_add (&hpusbscsi_devices, &new->lh);
......@@ -379,6 +382,7 @@ static void handle_usb_error (struct hpusbscsi *hpusbscsi)
static void control_interrupt_callback (struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
u8 scsi_state;
DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
if(unlikely(u->status < 0)) {
......@@ -386,10 +390,23 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
handle_usb_error(hpusbscsi);
return;
}
scsi_state = hpusbscsi->scsi_state_byte;
if (hpusbscsi->state != HP_STATE_ERROR) {
hpusbscsi->srb->result &= SCSI_ERR_MASK;
hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte;
hpusbscsi->srb->result |= scsi_state;
}
if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
if (scsi_state == CHECK_CONDITION << 1) {
if (hpusbscsi->state == HP_STATE_WAIT) {
issue_request_sense(hpusbscsi);
} else {
/* we request sense after an eventual data transfer */
hpusbscsi->state = HP_STATE_ERROR;
}
}
if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
/* we do a callback to the scsi layer if and only if all data has been transfered */
hpusbscsi->scallback(hpusbscsi->srb);
......@@ -404,6 +421,8 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
hpusbscsi->state = HP_STATE_PREMATURE;
TRACE_STATE;
break;
case HP_STATE_ERROR:
break;
default:
printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
TRACE_STATE;
......@@ -432,32 +451,6 @@ static void simple_command_callback(struct urb *u)
}
}
static void request_sense_callback (struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
if (unlikely(u->status<0)) {
handle_usb_error(hpusbscsi);
return;
}
FILL_BULK_URB(
u,
hpusbscsi->dev,
hpusbscsi->current_data_pipe,
hpusbscsi->srb->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
simple_done,
hpusbscsi
);
if (unlikely(0 > usb_submit_urb(u, GFP_ATOMIC))) {
handle_usb_error(hpusbscsi);
return;
}
hpusbscsi->state = HP_STATE_WORKING;
}
static void scatter_gather_callback(struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
......@@ -494,7 +487,7 @@ static void scatter_gather_callback(struct urb *u)
res = usb_submit_urb(u, GFP_ATOMIC);
if (unlikely(res))
hpusbscsi->state = HP_STATE_ERROR;
handle_usb_error(hpusbscsi);
TRACE_STATE;
}
......@@ -509,11 +502,15 @@ static void simple_done (struct urb *u)
DEBUG("Data transfer done\n");
TRACE_STATE;
if (hpusbscsi->state != HP_STATE_PREMATURE) {
if (unlikely(u->status < 0))
hpusbscsi->state = HP_STATE_ERROR;
else
if (unlikely(u->status < 0)) {
handle_usb_error(hpusbscsi);
} else {
if (hpusbscsi->state != HP_STATE_ERROR) {
hpusbscsi->state = HP_STATE_WAIT;
TRACE_STATE;
} else {
issue_request_sense(hpusbscsi);
}
}
} else {
if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
......@@ -550,12 +547,52 @@ static void simple_payload_callback (struct urb *u)
if (hpusbscsi->state != HP_STATE_PREMATURE) {
hpusbscsi->state = HP_STATE_WORKING;
TRACE_STATE;
} else {
if (likely(hpusbscsi->scallback != NULL))
hpusbscsi->scallback(hpusbscsi->srb);
hpusbscsi->state = HP_STATE_FREE;
TRACE_STATE;
}
}
static void request_sense_callback (struct urb *u)
{
struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
if (u->status<0) {
handle_usb_error(hpusbscsi);
return;
}
FILL_BULK_URB(
u,
hpusbscsi->dev,
hpusbscsi->current_data_pipe,
hpusbscsi->srb->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
simple_done,
hpusbscsi
);
if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
handle_usb_error(hpusbscsi);
return;
}
if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
hpusbscsi->state = HP_STATE_WORKING;
}
static void issue_request_sense (struct hpusbscsi *hpusbscsi)
{
FILL_BULK_URB(
hpusbscsi->dataurb,
hpusbscsi->dev,
usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
&hpusbscsi->sense_command,
SENSE_COMMAND_SIZE,
request_sense_callback,
hpusbscsi
);
hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
handle_usb_error(hpusbscsi);
}
}
......@@ -4,9 +4,14 @@
/* large parts based on or taken from code by John Fremlin and Matt Dharm */
/* this file is licensed under the GPL */
/* A big thanks to Jose for untiring testing */
typedef void (*usb_urb_callback) (struct urb *);
typedef void (*scsi_callback)(Scsi_Cmnd *);
#define SENSE_COMMAND_SIZE 6
#define HPUSBSCSI_SENSE_LENGTH 0x16
struct hpusbscsi
{
struct list_head lh;
......@@ -21,6 +26,7 @@ struct hpusbscsi
int number;
scsi_callback scallback;
Scsi_Cmnd *srb;
u8 sense_command[SENSE_COMMAND_SIZE];
int use_count;
wait_queue_head_t pending;
......@@ -57,6 +63,7 @@ static void simple_done (struct urb *u);
static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
static void issue_request_sense (struct hpusbscsi *hpusbscsi);
static Scsi_Host_Template hpusbscsi_scsi_host_template = {
name: "hpusbscsi",
......@@ -86,3 +93,4 @@ static Scsi_Host_Template hpusbscsi_scsi_host_template = {
#define HP_STATE_PREMATURE 5 /* status prematurely reported */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment