cciss: factor out core of sendcmd() for a more sane interface
Factor out the core of sendcmd() to provide a simpler interface which exposes all the error information to the caller and make the original sendcmd use this new function. Rationale: The SCSI error handling routines need to send commands with interrupts turned off, but they also need access to the full error information. Signed-off-by: Stephen M. Cameron <scameron@beardog.cca.cpqcorp.net> Cc: Mike Miller <mikem@beardog.cca.cpqcorp.net> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
53c663ce0f
commit
4a4b2d7684
|
@ -2373,41 +2373,21 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Send command c to controller h and poll for it to complete.
|
||||||
* Send a command to the controller, and wait for it to complete.
|
* Turns interrupts off on the board. Used at driver init time
|
||||||
* Only used at init time.
|
* and during SCSI error recovery.
|
||||||
*/
|
*/
|
||||||
static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
|
static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c)
|
||||||
1: address logical volume log_unit,
|
|
||||||
2: periph device address is scsi3addr */
|
|
||||||
unsigned int log_unit,
|
|
||||||
__u8 page_code, unsigned char *scsi3addr, int cmd_type)
|
|
||||||
{
|
{
|
||||||
CommandList_struct *c;
|
|
||||||
int i;
|
int i;
|
||||||
unsigned long complete;
|
unsigned long complete;
|
||||||
ctlr_info_t *info_p = hba[ctlr];
|
int status = IO_ERROR;
|
||||||
u64bit buff_dma_handle;
|
u64bit buff_dma_handle;
|
||||||
int status, done = 0;
|
|
||||||
|
|
||||||
if ((c = cmd_alloc(info_p, 1)) == NULL) {
|
resend_cmd1:
|
||||||
printk(KERN_WARNING "cciss: unable to get memory");
|
|
||||||
return IO_ERROR;
|
/* Disable interrupt on the board. */
|
||||||
}
|
h->access.set_intr_mask(h, CCISS_INTR_OFF);
|
||||||
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
|
|
||||||
log_unit, page_code, scsi3addr, cmd_type);
|
|
||||||
if (status != IO_OK) {
|
|
||||||
cmd_free(info_p, c, 1);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
resend_cmd1:
|
|
||||||
/*
|
|
||||||
* Disable interrupt
|
|
||||||
*/
|
|
||||||
#ifdef CCISS_DEBUG
|
|
||||||
printk(KERN_DEBUG "cciss: turning intr off\n");
|
|
||||||
#endif /* CCISS_DEBUG */
|
|
||||||
info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
|
|
||||||
|
|
||||||
/* Make sure there is room in the command FIFO */
|
/* Make sure there is room in the command FIFO */
|
||||||
/* Actually it should be completely empty at this time */
|
/* Actually it should be completely empty at this time */
|
||||||
|
@ -2415,21 +2395,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
|
||||||
/* tape side of the driver. */
|
/* tape side of the driver. */
|
||||||
for (i = 200000; i > 0; i--) {
|
for (i = 200000; i > 0; i--) {
|
||||||
/* if fifo isn't full go */
|
/* if fifo isn't full go */
|
||||||
if (!(info_p->access.fifo_full(info_p))) {
|
if (!(h->access.fifo_full(h)))
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
udelay(10);
|
udelay(10);
|
||||||
printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
|
printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
|
||||||
" waiting!\n", ctlr);
|
" waiting!\n", h->ctlr);
|
||||||
}
|
}
|
||||||
/*
|
h->access.submit_command(h, c); /* Send the cmd */
|
||||||
* Send the cmd
|
|
||||||
*/
|
|
||||||
info_p->access.submit_command(info_p, c);
|
|
||||||
done = 0;
|
|
||||||
do {
|
do {
|
||||||
complete = pollcomplete(ctlr);
|
complete = pollcomplete(h->ctlr);
|
||||||
|
|
||||||
#ifdef CCISS_DEBUG
|
#ifdef CCISS_DEBUG
|
||||||
printk(KERN_DEBUG "cciss: command completed\n");
|
printk(KERN_DEBUG "cciss: command completed\n");
|
||||||
|
@ -2438,97 +2412,116 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
|
||||||
if (complete == 1) {
|
if (complete == 1) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"cciss cciss%d: SendCmd Timeout out, "
|
"cciss cciss%d: SendCmd Timeout out, "
|
||||||
"No command list address returned!\n", ctlr);
|
"No command list address returned!\n", h->ctlr);
|
||||||
status = IO_ERROR;
|
status = IO_ERROR;
|
||||||
done = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This will need to change for direct lookup completions */
|
/* If it's not the cmd we're looking for, save it for later */
|
||||||
if ((complete & CISS_ERROR_BIT)
|
if ((complete & ~CISS_ERROR_BIT) != c->busaddr) {
|
||||||
&& (complete & ~CISS_ERROR_BIT) == c->busaddr) {
|
if (add_sendcmd_reject(c->Request.CDB[0],
|
||||||
/* if data overrun or underun on Report command
|
h->ctlr, complete) != 0)
|
||||||
ignore it
|
BUG(); /* we are hosed if we get here. */
|
||||||
*/
|
|
||||||
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
|
|
||||||
(c->Request.CDB[0] == CISS_REPORT_PHYS) ||
|
|
||||||
(c->Request.CDB[0] == CISS_INQUIRY)) &&
|
|
||||||
((c->err_info->CommandStatus ==
|
|
||||||
CMD_DATA_OVERRUN) ||
|
|
||||||
(c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
|
|
||||||
)) {
|
|
||||||
complete = c->busaddr;
|
|
||||||
} else {
|
|
||||||
if (c->err_info->CommandStatus ==
|
|
||||||
CMD_UNSOLICITED_ABORT) {
|
|
||||||
printk(KERN_WARNING "cciss%d: "
|
|
||||||
"unsolicited abort %p\n",
|
|
||||||
ctlr, c);
|
|
||||||
if (c->retry_count < MAX_CMD_RETRIES) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"cciss%d: retrying %p\n",
|
|
||||||
ctlr, c);
|
|
||||||
c->retry_count++;
|
|
||||||
/* erase the old error */
|
|
||||||
/* information */
|
|
||||||
memset(c->err_info, 0,
|
|
||||||
sizeof
|
|
||||||
(ErrorInfo_struct));
|
|
||||||
goto resend_cmd1;
|
|
||||||
} else {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"cciss%d: retried %p too "
|
|
||||||
"many times\n", ctlr, c);
|
|
||||||
status = IO_ERROR;
|
|
||||||
goto cleanup1;
|
|
||||||
}
|
|
||||||
} else if (c->err_info->CommandStatus ==
|
|
||||||
CMD_UNABORTABLE) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"cciss%d: command could not be aborted.\n",
|
|
||||||
ctlr);
|
|
||||||
status = IO_ERROR;
|
|
||||||
goto cleanup1;
|
|
||||||
}
|
|
||||||
printk(KERN_WARNING "ciss ciss%d: sendcmd"
|
|
||||||
" Error %x \n", ctlr,
|
|
||||||
c->err_info->CommandStatus);
|
|
||||||
printk(KERN_WARNING "ciss ciss%d: sendcmd"
|
|
||||||
" offensive info\n"
|
|
||||||
" size %x\n num %x value %x\n",
|
|
||||||
ctlr,
|
|
||||||
c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
||||||
offense_size,
|
|
||||||
c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
||||||
offense_num,
|
|
||||||
c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
||||||
offense_value);
|
|
||||||
status = IO_ERROR;
|
|
||||||
goto cleanup1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* This will need changing for direct lookup completions */
|
|
||||||
if (complete != c->busaddr) {
|
|
||||||
if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
|
|
||||||
BUG(); /* we are pretty much hosed if we get here. */
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
done = 1;
|
|
||||||
} while (!done);
|
|
||||||
|
|
||||||
cleanup1:
|
/* It is our command. If no error, we're done. */
|
||||||
|
if (!(complete & CISS_ERROR_BIT)) {
|
||||||
|
status = IO_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is an error... */
|
||||||
|
|
||||||
|
/* if data overrun or underun on Report command ignore it */
|
||||||
|
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
|
||||||
|
(c->Request.CDB[0] == CISS_REPORT_PHYS) ||
|
||||||
|
(c->Request.CDB[0] == CISS_INQUIRY)) &&
|
||||||
|
((c->err_info->CommandStatus == CMD_DATA_OVERRUN) ||
|
||||||
|
(c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) {
|
||||||
|
complete = c->busaddr;
|
||||||
|
status = IO_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) {
|
||||||
|
printk(KERN_WARNING "cciss%d: unsolicited abort %p\n",
|
||||||
|
h->ctlr, c);
|
||||||
|
if (c->retry_count < MAX_CMD_RETRIES) {
|
||||||
|
printk(KERN_WARNING "cciss%d: retrying %p\n",
|
||||||
|
h->ctlr, c);
|
||||||
|
c->retry_count++;
|
||||||
|
/* erase the old error information */
|
||||||
|
memset(c->err_info, 0, sizeof(c->err_info));
|
||||||
|
goto resend_cmd1;
|
||||||
|
}
|
||||||
|
printk(KERN_WARNING "cciss%d: retried %p too many "
|
||||||
|
"times\n", h->ctlr, c);
|
||||||
|
status = IO_ERROR;
|
||||||
|
goto cleanup1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
|
||||||
|
printk(KERN_WARNING "cciss%d: command could not be "
|
||||||
|
"aborted.\n", h->ctlr);
|
||||||
|
status = IO_ERROR;
|
||||||
|
goto cleanup1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr);
|
||||||
|
printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n",
|
||||||
|
c->Request.CDB[0], c->err_info->CommandStatus);
|
||||||
|
if (c->err_info->CommandStatus == CMD_TARGET_STATUS) {
|
||||||
|
printk(KERN_WARNING "Target status = 0x%02x\n",
|
||||||
|
c->err_info->ScsiStatus);
|
||||||
|
if (c->err_info->ScsiStatus == 2) /* chk cond */
|
||||||
|
printk(KERN_WARNING "Sense key = 0x%02x\n",
|
||||||
|
0xf & c->err_info->SenseInfo[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = IO_ERROR;
|
||||||
|
goto cleanup1;
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
cleanup1:
|
||||||
/* unlock the data buffer from DMA */
|
/* unlock the data buffer from DMA */
|
||||||
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
|
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
|
||||||
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
|
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
|
||||||
pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
|
pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
|
||||||
c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
|
c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
|
||||||
#ifdef CONFIG_CISS_SCSI_TAPE
|
#ifdef CONFIG_CISS_SCSI_TAPE
|
||||||
/* if we saved some commands for later, process them now. */
|
/* if we saved some commands for later, process them now. */
|
||||||
if (info_p->scsi_rejects.ncompletions > 0)
|
if (h->scsi_rejects.ncompletions > 0)
|
||||||
do_cciss_intr(0, info_p);
|
do_cciss_intr(0, h);
|
||||||
#endif
|
#endif
|
||||||
cmd_free(info_p, c, 1);
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a command to the controller, and wait for it to complete.
|
||||||
|
* Used at init time, and during SCSI error recovery.
|
||||||
|
*/
|
||||||
|
static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
|
||||||
|
unsigned int use_unit_num,/* 0: address the controller,
|
||||||
|
1: address logical volume log_unit,
|
||||||
|
2: periph device address is scsi3addr */
|
||||||
|
unsigned int log_unit,
|
||||||
|
__u8 page_code, unsigned char *scsi3addr, int cmd_type)
|
||||||
|
{
|
||||||
|
CommandList_struct *c;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
c = cmd_alloc(hba[ctlr], 1);
|
||||||
|
if (!c) {
|
||||||
|
printk(KERN_WARNING "cciss: unable to get memory");
|
||||||
|
return IO_ERROR;
|
||||||
|
}
|
||||||
|
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
|
||||||
|
log_unit, page_code, scsi3addr, cmd_type);
|
||||||
|
if (status == IO_OK)
|
||||||
|
status = sendcmd_core(hba[ctlr], c);
|
||||||
|
cmd_free(hba[ctlr], c, 1);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue