forked from Minki/linux
5c44cd2afa
We have some nasty issues with 2.6.12-rc6. Any request to scan on the lpfc or qla2xxx FC adapters will oops. What is happening is the system is defaulting to non-transport registered targets, which inherit the parent of the scan. On this second scan, performed by the attribute, the parent becomes the shost instead of the rport. The slave functions in the 2 FC adapters use starget_to_rport() routines, which incorrectly map the shost as an rport pointer. Additionally, this pointed out other weaknesses: - If the target structure is torn down outside of the transport, we have no method for it to be regenerated at the proper parent. - We have race conditions on the target being allocated by both the midlayer scan (parent=shost) and by the fc transport (parent=rport). Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
95 lines
3.1 KiB
C
95 lines
3.1 KiB
C
/*
|
|
* Transport specific attributes.
|
|
*
|
|
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#ifndef SCSI_TRANSPORT_H
|
|
#define SCSI_TRANSPORT_H
|
|
|
|
#include <linux/transport_class.h>
|
|
#include <scsi/scsi_host.h>
|
|
|
|
struct scsi_transport_template {
|
|
/* the attribute containers */
|
|
struct transport_container host_attrs;
|
|
struct transport_container target_attrs;
|
|
struct transport_container device_attrs;
|
|
|
|
/*
|
|
* If set, call target_parent prior to allocating a scsi_target,
|
|
* so we get the appropriate parent for the target. This function
|
|
* is required for transports like FC and iSCSI that do not put the
|
|
* scsi_target under scsi_host.
|
|
*/
|
|
struct device *(*target_parent)(struct Scsi_Host *, int, uint);
|
|
|
|
/* The size of the specific transport attribute structure (a
|
|
* space of this size will be left at the end of the
|
|
* scsi_* structure */
|
|
int device_size;
|
|
int device_private_offset;
|
|
int target_size;
|
|
int target_private_offset;
|
|
int host_size;
|
|
/* no private offset for the host; there's an alternative mechanism */
|
|
|
|
/*
|
|
* True if the transport wants to use a host-based work-queue
|
|
*/
|
|
unsigned int create_work_queue : 1;
|
|
};
|
|
|
|
#define transport_class_to_shost(tc) \
|
|
dev_to_shost((tc)->dev)
|
|
|
|
|
|
/* Private area maintenance. The driver requested allocations come
|
|
* directly after the transport class allocations (if any). The idea
|
|
* is that you *must* call these only once. The code assumes that the
|
|
* initial values are the ones the transport specific code requires */
|
|
static inline void
|
|
scsi_transport_reserve_target(struct scsi_transport_template * t, int space)
|
|
{
|
|
BUG_ON(t->target_private_offset != 0);
|
|
t->target_private_offset = ALIGN(t->target_size, sizeof(void *));
|
|
t->target_size = t->target_private_offset + space;
|
|
}
|
|
static inline void
|
|
scsi_transport_reserve_device(struct scsi_transport_template * t, int space)
|
|
{
|
|
BUG_ON(t->device_private_offset != 0);
|
|
t->device_private_offset = ALIGN(t->device_size, sizeof(void *));
|
|
t->device_size = t->device_private_offset + space;
|
|
}
|
|
static inline void *
|
|
scsi_transport_target_data(struct scsi_target *starget)
|
|
{
|
|
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
|
|
return (u8 *)starget->starget_data
|
|
+ shost->transportt->target_private_offset;
|
|
|
|
}
|
|
static inline void *
|
|
scsi_transport_device_data(struct scsi_device *sdev)
|
|
{
|
|
struct Scsi_Host *shost = sdev->host;
|
|
return (u8 *)sdev->sdev_data
|
|
+ shost->transportt->device_private_offset;
|
|
}
|
|
|
|
#endif /* SCSI_TRANSPORT_H */
|