blob: 06f3769a539b08ab5ab5d2337a0a66b7f1d0a01e [file] [log] [blame]
/* $Id: acb4000.c,v 1.5 2006/09/30 12:34:21 fredette Exp $ */
/* scsi/acb4000.c - ACB4000 SCSI disk emulation: */
/*
* Copyright (c) 2003 Matt Fredette
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Matt Fredette.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <tme/common.h>
_TME_RCSID("$Id: acb4000.c,v 1.5 2006/09/30 12:34:21 fredette Exp $");
/* includes: */
#include <tme/scsi/scsi-disk.h>
#include <errno.h>
/* macros: */
/* types: */
/* this is the ACB4000 LUN addresser for LUN-aware devices: */
static int
_tme_acb4000_address_lun(struct tme_scsi_device *scsi_device)
{
struct tme_scsi_device_sense *sense;
int lun;
/* if an IDENTIFY message was sent, use that LUN: */
lun = scsi_device->tme_scsi_device_addressed_lun;
/* otherwise, get the LUN from bits 5-7 of the second
CDB byte: */
if (lun < 0) {
lun = (scsi_device->tme_scsi_device_cdb[1] >> 5);
scsi_device->tme_scsi_device_addressed_lun = lun;
}
/* if this LUN is not defined, and this isn't a REQUEST SENSE
command: */
if (!(scsi_device->tme_scsi_device_luns
& TME_BIT(lun))
&& (scsi_device->tme_scsi_device_cdb[0]
!= TME_SCSI_CDB_REQUEST_SENSE)) {
/* the ACB4000 returns a nonextended sense code of 0x25
for an undefined LUN: */
sense = &scsi_device->tme_scsi_device_sense[lun];
/* the error class and error code: */
sense->tme_scsi_device_sense_data[0]
= 0x25;
sense->tme_scsi_device_sense_data[1]
= 0;
sense->tme_scsi_device_sense_data[2]
= 0;
sense->tme_scsi_device_sense_data[3]
= 0;
sense->tme_scsi_device_sense_valid = 4;
/* return the CHECK CONDITION status: */
tme_scsi_device_target_do_smf(scsi_device,
TME_SCSI_STATUS_CHECK_CONDITION,
TME_SCSI_MSG_CMD_COMPLETE);
return (EINVAL);
}
return (TME_OK);
}
/* the ACB4000 doesn't support various commands: */
static _TME_SCSI_DEVICE_CDB_DECL(_tme_acb4000_cdb_bad)
{
int lun;
struct tme_scsi_device_sense *sense;
/* get the addressed LUN's sense: */
lun = scsi_device->tme_scsi_device_addressed_lun;
sense = &scsi_device->tme_scsi_device_sense[lun];
/* the ACB4000 returns a nonextended sense code of 0x20
for an invalid command: */
/* the error class and error code: */
sense->tme_scsi_device_sense_data[0]
= 0x20;
sense->tme_scsi_device_sense_data[1]
= 0;
sense->tme_scsi_device_sense_data[2]
= 0;
sense->tme_scsi_device_sense_data[3]
= 0;
sense->tme_scsi_device_sense_valid = 4;
/* return the CHECK CONDITION status: */
tme_scsi_device_target_do_smf(scsi_device,
TME_SCSI_STATUS_CHECK_CONDITION,
TME_SCSI_MSG_CMD_COMPLETE);
}
/* this initializes ACB4000 SCSI disk emulation: */
int
tme_scsi_disk_acb4000_init(struct tme_scsi_disk *scsi_disk)
{
struct tme_scsi_device *scsi_device;
scsi_device = &scsi_disk->tme_scsi_disk_device;
/* ACB4000 boards don't support the INQUIRY command: */
TME_SCSI_DEVICE_DO_CDB(scsi_device,
TME_SCSI_CDB_INQUIRY,
_tme_acb4000_cdb_bad);
/* ACB4000 boards don't support extended sense: */
scsi_device->tme_scsi_device_sense_no_extended
= TRUE;
/* ACB4000 boards have a particular LUN addressing behavior: */
scsi_device->tme_scsi_device_address_lun
= _tme_acb4000_address_lun;
return (TME_OK);
}